Plone: list all ldap users - plone

I'm trying to get the list of all users - local accounts and ldap ones.
If I know an userid (ldap or local account) this is simple, I can get it and check it's properties:
site = self.context.portal_url.getPortalObject() from
Products.CMFCore.utils import getToolByName
membership_tool = getToolByName(site, 'portal_membership')
membership_tool.getMemberById('some_user_id')
^ This is working for both: ldap and local.
membership_tool.listMemberIds() # local accounts ids are listed
The same with:
users_tool = getToolByName(self, 'acl_users')
users_tool.getUserIds() # local accounts ids are listed
Any idea how to get the list of users that are using ldap account?

Solved by iterating the keys of _members in portal_memberdata tool. We have some fields for each user.
md = getToolByName(self, 'portal_memberdata')
all_members = [x for x in md._members.keys()] # ids of ldap and local accounts are listed

Related

Configure authentication and synchronization with two LDAP in Alfresco 5.1

We perform migration from enterprise version Alfresco 4.2 to the 5.1.
There are two Active Directory domains (primary and child) in company, for this reason we configure two LDAP(AD) subsystems in Alfresco 5.1.
Structure of properties:
/opt/tomcat7/shared/classes/alfresco/extension/subsystems/Authentication/ldap-ad/ldap2
/opt/tomcat7/shared/classes/alfresco/extension/subsystems/Authentication/ldap-ad/ldap1
Problem is that authentication and synchronistaion work only for one ldap-ad subsystem (ldap1 or ldap2), which have first place in the list of authentication chain (ldap1 and ldap2 don't work together).
Authentication chain screenshot
For a example, if ldap1 have first place in the list, that user's login from ldap2 fails (and conversely!).
In this case I look error in alfresco.log:
Caused by: net.sf.acegisecurity.AuthenticationCredentialsNotFoundException: A valid SecureContext was not provided in the RequestContext
My properties:
/opt/tomcat7/shared/classes/alfresco/extension/subsystems/Authentication/ldap-ad/ldap1/ldap-ad-authentication.properties
ldap.authentication.active=true
ldap.authentication.allowGuestLogin=false
ldap.authentication.userNameFormat=%s#fake.local
ldap.authentication.java.naming.provider.url=ldap://fake.local:***
ldap.authentication.defaultAdministratorUserNames=fake_user
ldap.authentication.java.naming.referral=follow
ldap.synchronization.java.naming.security.principal=fake_user#fake.local
ldap.synchronization.java.naming.security.credentials=somepassword
ldap.synchronization.groupSearchBase=ou=Archiv,ou=FileServerGroups,ou=Groups,dc=fake,dc=local
ldap.synchronization.userSearchBase=dc=fake,dc=local
ldap.synchronization.groupDisplayNameAttributeName=description
ldap.synchronization.userOrganizationalIdAttributeNameCustom=distinguishedName
ldap.synchronization.com.sun.jndi.ldap.connect.pool=true
/opt/tomcat7/shared/classes/alfresco/extension/subsystems/Authentication/ldap-ad/ldap2/ldap-ad-authentication.properties
ldap.authentication.active=true
ldap.authentication.allowGuestLogin=false
ldap.authentication.userNameFormat=%s#gss.fake.local
ldap.authentication.java.naming.provider.url=ldap://gss.fake.local:***
ldap.authentication.defaultAdministratorUserNames=fake_user
ldap.authentication.java.naming.referral=follow
ldap.synchronization.java.naming.security.principal=fake_user#fake.local
ldap.synchronization.java.naming.security.credentials=somepassword%
ldap.synchronization.groupSearchBase=ou=Archiv,ou=FileServerGroups,ou=Groups,dc=gss,dc=fake,dc=local
ldap.synchronization.userSearchBase=dc=gss,dc=fake,dc=local
ldap.synchronization.groupDisplayNameAttributeName=description
ldap.synchronization.userOrganizationalIdAttributeNameCustom=distinguishedName
ldap.synchronization.com.sun.jndi.ldap.connect.pool=true
alfresco-global.properties
### Authentication ###
#authentication.chain=ldap1:ldap-ad,ldap2:ldap-ad,alfrescoNtlm1:alfrescoNtlm
authentication.chain=alfinst:alfrescoNtlm,ldap1:ldap-ad,ldap2:ldap-ad
Thanks in advance!
Finally, I resolved issue related to authentication users.
I put empty string of parametr:
ldap.authentication.userNameFormat=
for each LDAP subsystems in files ldap-ad-authentication.properties.
After, users from two ldaps could login successfully.
ldap.authentication.userNameFormat
Specifies how to map the user identifier entered by the user to that
passed through to LDAP. If set to an empty string (the default for the
ldap subsystem), an LDAP query involving
ldap.synchronization.personQuery and
ldap.synchronization.userIdAttributeName will be performed to resolve
the DN from the user ID dynamically. This allows directories to be
structured and does not require the user ID to appear in the DN.
If set to a non-empty value, the substring %s in this value will be
replaced with the entered user ID to produce the ID passed to LDAP.
This restricts LDAP user names to a fixed format. The recommended
format of this value depends on your LDAP server.

Hosting WIF Identity Provider and generating self signed certificates for it

For my final year project I've developed an ASP.NET website and I've implemented a Single Sign On Login System using Windows Identity Foundation (in a similar manner to the tutorial shown here: http://www.primaryobjects.com/2013/08/08/using-single-sign-on-with-windows-identity-foundation-in-mvc-net )
This means that I currently have a 2 Websites, my Identity Provider Site and the site that uses the IP and contains most of the functionality.The IP uses X509 certificate to generate the token and for this I've been able so far to use a self signed certificate. This is the code that I've been using to retrieve the certificate from the local machine:
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
X509Certificate2Collection certificates = null;
store.Open(OpenFlags.ReadOnly);
try
{
certificates = store.Certificates;
var certs = certificates.OfType<X509Certificate2>().Where(x => x.SubjectName.Name.Equals(subjectName, StringComparison.OrdinalIgnoreCase)).ToList();
if (certs.Count == 0)
throw new ApplicationException(string.Format("No certificate was found for subject Name {0}", subjectName));
else if (certs.Count > 1)
throw new ApplicationException(string.Format("There are multiple certificates for subject Name {0}", subjectName));
return new X509Certificate2(certs[0]);
}
In order to be able to present my project I will be asked to host it on the web, but this will mean that I'll need a substitute for my self signed certificate.
I could use something like azure websites to host my websites but I wasn't able to find a solution so far that would allow me to generate a self signed certificate on a service like azure and retrieve it programatically.
Could you please suggest me a solution for this problem?
Ideally, you wouldn't have to create your own IDP. You could use something like ADFS.
Azure AD is an IDP and has its own certificates so you don't need to create any.
All you need is the metadata and you can find the URL under AppServices / Endpoints.
There's an example here but note that this uses WS-Fed OWIN not WIF. (WIF is somewhat old school).
To make your life easier, you can update your web.config programmatically by adding code to global.asax.
Or just move your whole solution to a VM in Azure.

ASP Identity : Binding Sessions To Request Url (Sub Domains)

I don't think the title of the question is particularly accurate but that's how best i could title it.
Without summarizing, I have an MVC app hosted on Microsoft Azure. The app was built for multiple institutions (each connecting to a separate database) but the Login Module (Asp Identity) is in a central database (users are identified by their institution code). So during deployment, a sub domain is created (still pointing to the app on azure).
My problem is, the app has no regard for the Request Url, the sessions are maintained across domains. This is a serious problem because i cache User data (by session). So if a user Logs in on "domain1.myapp.com" , then opens another tab , logs into "domain2.myapp.com" , all data cached for the user logged in for "domain1" will be used for the user logged in at "domain2". The app doesn't bother to get data for the user in "domain2" since the key for that data value is already present in the session cache.
Okay, I hope the problem is understood. How do i get past this.
Ideas ? implementation ?
EDIT 1
I insert data into the cache by,
HttpRuntime.Cache.Insert("KEY", "VALUE", null, DateTime.Now.AddMinutes(30),Cache.NoSlidingExpiration);
Your caching strategy needs to change when you cache per user and per domain. The simplest approach is just to add the domain and user name to the cache key, which will keep each cache in a separate per user and per domain bucket. Make sure you put a delimiter between the values to ensure uniqueness of the key.
var domain = HttpContext.Request.Url.DnsSafeHost;
var user = HttpContext.User.Identity.Name;
var key = "__" + domain + "_" + user + "_" + "KEY";
HttpRuntime.Cache.Insert(key, "VALUE", null, DateTime.Now.AddMinutes(30),Cache.NoSlidingExpiration);
Note that if you use HttpContext.Session, it will automatically put different domain information into separate buckets because it is based on a cookie (which by default is domain specific). However, HttpContext.Session comes with its own set of problems.

Openstack: login as admin and retrieve server data from different tenants via python

I'm writing some cron job in python for Openstack that should read server ids from a database and then get the servers from the API by using the python-novaclient.
In pseudo code things should work like this:
session = login_to_keystone(user="admin", password="something") #or use a token
nova_client = get_nova_client(session)
#the servers array holds dictionaries with server, user and tenant ids as strings
# e.g. {"server_id": "1-2-3", "tentant_id": "456", user_id: "11111-2222"}
for server in servers:
server_obj = nova_client.servers.get(server.server_id)
...do stuff with server_obj (read data from it, delete,...)...
What I've come up with is the following, but it's not right as I get a EndpointNotFound exception. I'm using Devstack with Juno.
from keystoneclient.v2_0 import client as keystone_client
from keystoneclient import session
from novaclient import client as nova_client
#the url is the admin endpoint
keystone = keystone_client.Client(token="my-admin-token",
auth_url="http://192.168.1.1:35357/v2.0",
endpoint="http://192.168.1.1:35357/v2.0")
key_session = session.Session(auth=keystone)
nova = nova_client.Client(2, session=key_session)
#let's assume the servers array is already populated
for server in servers:
server_obj = nova.servers.get(server.server_id) #Exception happens here
I need to run this as admin as servers can belong to any tenant and they might even be deleted by the cron job.
Thanks for any help!
UPDATE:
The information I need was that I can use the admin tenant for retrieving all servers (regardless of their owner). This allows me also to use the publicURL.
My current solution looks like this:
from keystoneclient.auth.identity import v2
from keystoneclient import session
from novaclient import client as nova_client
auth = v2.Password(auth_url="http://192.168.1.1:5000/v2.0",
username="admin",
password="my_secrete",
tenant_name="admin") # the admin's tenant
auth_session = session.Session(auth=auth)
nova = nova_client.Client(2, session=auth_session)
for server in servers:
... do stuff like nova.servers.get("some id")
In order to get a list of servers from all tenants, you need to perform two tasks:
Log in as a user with admin privileges, and
Tell the Nova API that you want a list of servers for all tenants.
Logging in as an admin user
It looks like you're trying to use the admin_token defined in keystone.conf for authentication. This may work, but this mechanism is meant primarily as a means of bootstrapping Keystone. When interacting with the other services, you are meant to log in using a username/password pair that has been defined in Keystone with admin credentials. I think that what #anoop.babu has given you will work just fine:
>>> nova = nova_client.Client('2', USERNAME, PASSWORD,
PROJECT_ID, AUTH_URL)
Where:
USERNAME = admin
PASSWORD = password_for_admin_user
PROJECT_ID = admin
AUTH_URL = http://your_api_server:5000/v2.0
We can test this client out using something like:
>>> nova.hypervisors.list()
[<Hypervisor: 2>]
That tells us we've authenticated successfully.
Listing all servers
If we simply called nova.servers.list(), we are asking for a list of Nova servers owned by the admin tenant, which should generally be empty:
>>> nova.servers.list()
[]
In order to see servers from other tenants, you need to pass the all_tenants search option:
>>> nova.servers.list(search_opts={'all_tenants':1})
[<Server: cirros0>]
And that should get you where you want to be.
Here you have given auth_url as your endpoint. endpoint is actually the publicURL of the service.
You can find the publicURL using the below CLI Command
nova endpoints
and check for keystone details.
You can also get an authenticated keystone object using below api version without using endpoint,
import keystoneclient.v2_0.client as keystone_client
keystone = keystone_client.Client(auth_url = my_auth_url , username = my_user_name , password = my_password , tenant_name = my_tenant_name )
And create a session object as below,
from keystoneclient import session
key_session = session.Session(auth=keystone)
An alternate and simplified approach to get nova client authorized without keystone is,
from novaclient import client as nova_client
nova = nova_client.Client('2', USERNAME, PASSWORD, PROJECT_ID, AUTH_URL)
server_obj = nova.servers.find( name=my_server_name )

Check other user's role membership (IsInRole, WindowsIdentity/Principal)

I'm writing ASP.NET code to run on an internal network where Windows Authentication will be used. Certain operations will require me to run a group membership check on other users (not the current user)
NOTE: I am NOT trying to impersonate this account, or access any information in the context of this other user. Just trying to find out what kind of user they are for internal business logic.
My first thought was to use
new WindowsPrincipal(new WindowsIdentity("MACHINENAME\\username"))
.IsInRole("MACHINENAME\\Group1")
However, the WindowsIdentity constructor fails with a SecurityException "The name provided is not a properly formed account name".
If I strip MACHINENAME\ from the parameter, I get a different error: There are currently no logon servers available to service the logon request
The WindowsTokenRoleProvider role provider explicitly only works with the current user, and will not check other user accounts.
Are there security restrictions to checking roles of other users? Would it make a difference if the web server was on a domain and I were checking domain accounts?
In the end, I'll need to have this work on an AD domain, but would prefer a solution that will work on either local or AD accounts.
Thank you
UPDATE: I've been able to test this on a domain now -- the code does work in an AD context so long as I don't use the domain name (test "username" against "Group1", not "DOMAIN\username" against "DOMAIN\Group1")
So how would I get this to work in the context of local users and groups?
Based on Rob A's comment, PrincipalContext and UserPrincipal are the classes I apparently need to use:
using (PrincipalContext ctx = new PrincipalContext(ContextType.Machine))
{
var u = UserPrincipal.FindByIdentity(ctx, IdentityType.Name, "username");
var b = u.IsMemberOf(ctx, IdentityType.Name, "Group1");
var groups = u.GetAuthorizationGroups();
}
And by altering the ContextType, can switch between local accounts and AD accounts. I wish this was built into a RoleProvider, but I guess that's something I'd have to do for myself.

Resources