Hussain Akbar
Hussain Akbar

Reputation: 686

Setting up LDAP authorization using OpenLDAP

This is the same as asked here: LDAP authorization

I am attempting to set up LDAP to use with PHP applications. I've got the authentication and group membership set up. What next?

The aim is that, firstly, there should be roles (groups in LDAP?) e.g. customerViewer, customerInfoUpdater, etc.

Then, there should be a group of users. e.g. Tom, Dick & Harry would be in financeUsers group.

So far so good. I can do both by setting up memberOf.

Now, how do I put / assign customerViewer group/right/permission to the financeUsers group? That is to say, Tom et al are added to financeUsers group and financeUsers is assigned to customerViewer group (or am I totally wrong here?)

How would I check that the currently logged in user is in customerViewer group so that he get the authorization to view customer records?

I am using CentOS 7 on the server and have Apache LDAP Studio installed on my Windows client.

Upvotes: 1

Views: 1946

Answers (2)

EricLavault
EricLavault

Reputation: 16035

You can create or use 2 organizational units, one to list groups and the other to hold roles. Use the objectclass organizationalunit (required) :

# Groups 
dn: ou=groups,dc=example,dc=com
objectclass:organizationalunit
ou: groups
description: generic groups branch

# Roles
dn: ou=roles,dc=example,dc=com
objectclass:organizationalunit
ou: roles
description: generic roles branch

Each organizational unit can contain a (possibly nested) list of entries, with each entry holding user memberships via the member attribute. The ability to represent membership is made possible by the groupOfNames objectclass :

# Create financeUsers group under groups
dn: cn=financeUsers,ou=groups,dc=example,dc=com
objectclass: groupofnames
cn: financeUsers
description: Finance team.
member: uid=someone,ou=people,dc=example,dc=com 
member: uid=someone_else,ou=people,dc=example,dc=com  

# Create customerViewer role under roles
dn: cn=customerViewer,ou=roles,dc=example,dc=com
objectclass: groupofnames
cn: customerViewer 
description: Customer viewer role (every members have 'view' access to Customer entity)
member: uid=someone,ou=people,dc=example,dc=com 
member: uid=somebody,ou=people,dc=example,dc=com  

The thing to remember is that everything depends on your access policy :

  • If being member of a group must assign that member to a group role (that is in this case a set of group specific permissions), then you can consider using the same ldap entry to hold both group and role memberships, because the permissions are given by the group membership.
  • If being member of a group is just a condition but does not suffice to grant permissions, or if it is independent from your access policy, then you need to use roles memberships to proceed to a proper authorization.

The check in itself merely depends on the client/application used to authorize users, please update your question so I can go further or ask a new one if you think it may belong to another post.

Upvotes: 1

LisaJ
LisaJ

Reputation: 1706

You might look into the autogroup overlay for OpenLDAP which would populate your cutomerInfoEditor group membership based on a filter rather than using nested group memberships.

You can use nested group memberships in your directory and handle it in code. If your customerInfoEditor only contains one level of nested groups (i.e. its members are groups, but none of those groups have groups as members), you could build a filter based on the membership list of customerInfoEditor.

If the members of customerInfoEditor are the groups "financeUsers", "salesUsers", and "whateverOtherUsers", your filter to determine if a particular user, USERINPUT, should be assigned this role is

(&(uid=USERINPUT)(|(memberOf=financeUsers)(memberOf=salesUsers)(memberOf=whateverOtherUsers))

The | is an or operator. The filter says find a user where ( (uid is the value with which the user authenticated) AND (they are a member of financeUsers OR a member of salesUsers OR a member of whateverOtherUsers) )

Using code to build the or component of the filter allows you to redefine what entitles someone to the customerInfoEditor role without code changes -- add yetAnotherGroupOfUsers as a member of customerInfoEditor and your filter will dynamically change to include that group too.

You might be able to speed the query up a bit by getting the user's fully qualified DN (FQDN) and changing the search base to the user's FQDN. Then the filter would simply be

(|(memberOf=financeUsers)(memberOf=salesUsers)(memberOf=whateverOtherUsers))

In either case, getting 1 record back means they should be assigned the access. 0 means they should not be. And >1 is strange -- I generally throw an error instructing the user to ring up our help desk in this case.

If your role groups, like customerInfoEditor, may have multiple levels of nesting (financeUsers are a member, but financeUsers members are groups like accountsRecievableUsers, accountsPayableUsers, cfoUsers, and some of those groups could even have groups as members) then ... well, personally since I do all of my provisioning automatically ... I'd just add another "add to group" event in my provisioning workflow for all of those groups and not use deeply nested groups. When I add someone to cfoUsers, I'd also add the to customerInfoEditor and the role group would contain only user accounts as members.

But if there's no other alternative, the only thing I know to do is handle the group expansion within your code. As far as I/O goes, it's expensive because you'd have to look at all of the groups of which an individual is a member, check to see what those groups are a member of, check to see what those groups a member of. If you're only dealing with a single role, you could break out of the expansion as soon as the role is found, but if you need to look for multiple role groups ... you'd have to run until you hit the top of the tree and had an expanded list of all groups of which the individual is a direct or indirect member. And track groups you've already expanded to handle loops otherwise A is member of B, B is member of C, C is member of D, D is member of A becomes an infinite expansion loop.

Upvotes: 1

Related Questions