chauth / confluence_http_authenticator

The new home of the Confluence HTTP Authenticator (formerly known as the Confluence Shibboleth Authenticator)
Other
64 stars 36 forks source link

Any tips on integrating with Confluence delegated LDAP #3

Closed shall05mit closed 10 years ago

shall05mit commented 11 years ago

Hey there! Great project thanks for all the work, and my apologies if this is not the place to be asking for tech support. I'm trying to integrate shibboleth SSO with a confluence 3.5.17 installation. I have a read only delegated LDAP directory configured in confluence and it works a treat when logging in as an ldap user. When I put shibboleth in front of it I can authenticate against the idp but my user's ldap information does not get populated into the Confluence directory (only the users email address gets put into the directory as the value for both the User and the Full Name). Is it that I am not passing in the correct shibboleth attributes? Once again my apologies if this is the wrong place to be asking such a basic question. Scott

garysweaver commented 11 years ago

Always good to hear from someone new who is using it! We recently had to move from free hosting at Atlassian to GitHub and have some documentation cleanup to do, so I apologize.

Ensure the following are set correctly in your configuration:

To ensure the right headers are coming through from shib, maybe shib a PHP script that dumps headers, or I have a war that does it if you'd like: https://github.com/garysweaver/id

You could also just turn on debug logging in the authenticator and look at the logs. See the relevant part of the documentation. Right now that's located here, but the docs might change later: https://github.com/chauth/confluence_http_authenticator#how-to-turn-on-debug-logging

If you have problems with shib config (like if the wrong headers are coming in) you can ask for help on the shibboleth mailing list: http://shibboleth.net/community/lists.html

Basically the support we provide for the authenticator is specific to the authenticator itself, so unless there is something in our code that is not handling things correctly, we won't be able to help much.

See also the readme here and the other documentation-looking files in the root of the project (at least for now- maybe eventually will move to wiki): https://github.com/chauth/confluence_http_authenticator#how-to-turn-on-debug-logging

Good luck!

garysweaver commented 11 years ago

In addition, pull requests to add to documentation or maybe moving docs to wiki and cleaning things up would be appreciated! It's always better to get documentation when someone is trying to learn something as they run into new things. Others might not have run into those things yet, and you likely have a unique perspective and can add valuable details. TIA!

shall05mit commented 11 years ago

Hey Gary,

I'll definitely contribute any solution I find to the wiki-docs!

Here's what's set in the remoteUserAuthentication.properties:

header.fullname = Shib-InetOrgPerson-displayName header.email = Shib-InetOrgPerson-mail

Funny behavior, I can do authenticate using the IdP and confluence adds me to the "Delegated read-only LDAP" directory I've configured but then confluence does not go out and query the external LDAP and get my groups or user info! As above it just populates User and Full Name with my email address.

Well after turning on debugging and authenticating I see these entries in the logs:

getFullName User full name header name in config was null/not specified. getFullName User full name was null or empty. Defaulting full name to user id.

...

garysweaver commented 11 years ago

@shall05mit just recorded that and edited. So it looks per the headers you sent me that header.fullname needs to be set to the header name that contains the full name (look at what you sent me to see which one). Similarly the header.email should be set to the header that is explicitly definining the email address (look through headers and pick best one). Then try that and keep tweaking until it doesn't say that getFullName was null and you're all set. Good luck!

garysweaver commented 11 years ago

Sorry didn't mean to close ticket.

shall05mit commented 11 years ago

S'ok, I just edited the remotUserAuthentication.properties file and set the correct values per the headers being sent.

This gets my user added into the default Delegated LDAP Directory but still seems to "short circuit" confluences default configured behavior for that directory. That is no search of my external configured LDAP and addition of groups happens.

Do I need to set: create_users=false to get confluences embedded crowd to behave as before?

garysweaver commented 11 years ago

@shall05mit (recorded and edited). Cool. Ok, if Confluence already has access to users and you don't want to create them (even if they are valid in shib but don't exist in your user repo which is backed by LDAP) then you'd do:

create.users=false

If you don't want it to try to update email or full name, then:

update.info=false

If you don't want it to update groups:

update.roles=false

I think that is it. You can review the full list of available options here and they each have info about what they do, but it might be a little cryptic in places (roles = groups being the main thing):

https://github.com/chauth/confluence_http_authenticator/blob/master/conf/remoteUserAuthenticator.properties

shall05mit commented 11 years ago

Ok, well with

create.users=false

I get no luck

2013-03-04 13:24:37,833 DEBUG [TP-Processor7] [confluence.authentication.shibboleth.RemoteUserAuthenticator] createUser Configuration does NOT allow creation of new user accounts, authentication will fail for ...

Perhaps a combination of:

create.users=true

and

update.info=false
update_roles=false

... we'll see

Thanks!

garysweaver commented 11 years ago

(Note: Looks like there is a wierd issue in GitHub that is keeping me from being able to format bits of code correctly when editing someone else's comment that came in from email. Sorry for the spam you probably got as I learned that. Just trying to make it pretty.)

shall05mit commented 11 years ago

Oh well, no joy here. I can authenticate either via shibboleth and get default roles/groups as configured. Or I can authenticate via the internal delegated LDAP configuration and get my groups from LDAP migrated but no combination of configurations in: remotUserAuthentication.properties seems to allow for shibboleth authentication to the directory and lets confluence copy my users info over from LDAP. Using shibboleth I end up with a User with only the default roles/groups. Like I wrote above the ldap search/add that confluence does using just the local directory doesn't happen when using shibboleth. Hmmm I'll keep trying to figure this out...

garysweaver commented 11 years ago

Ahh, ok. I see. Yes, that is something we used to do in the CSUM plugin I worked on (you could put in the username and it would use the LDAP repo configured in Confluence to get the user info and create the user in Confluence); it wasn't trivial (from what I could see) to do that starting in Confluence 3.4/3.5. Anyway- in the authenticator, you can do what you want by exposing all the group info via the IdP and SP. Look at the dynamic roles functionality. That is how others are doing it. It definitely is not as trivial as just pointing the authenticator at a configured LDAP repo, but it should actually be faster than an additional call to LDAP during authentication. I'm assuming that you are passing LDAP info in via the shib headers, otherwise what I just said probably makes no sense.

garysweaver commented 11 years ago

Also note- what you had above- you had put underscore in the config where that should have been a period:

update.roles=true

I'm assuming that wasn't the problem though?

So, anyway, if you get your IdP admin to expose all LDAP attribs containing group membership, then you'd want:

create.users=true
update.info=true
update.roles=true
dynamicroles.auto_create_role=true

and then look at the rest of the config to determine what to uncomment and set correctly so that it takes the header(s) passed in and converts them/parses them (via regex even) into valid group names: https://github.com/chauth/confluence_http_authenticator/blob/master/conf/remoteUserAuthenticator.properties

That is messy, for sure, as basically the wiki is going to have even more of a partial copy of LDAP that is updated only when the user logs in. But, it is an option. If you wanted to contribute something that would look at Crowd directories and then do LDAP lookup of the user, that's cool too; or even connect to LDAP, and have its own connection info, as long as it's optional. I'd rather do as much as we can to reduce code and the number of requests being sent during authentication to get info, but if it makes things better for you, I'm all for it being part of the code, because someone else might use it also.

shall05mit commented 11 years ago

Ahh okay Gary, thanks for the info, and yes the underscore was a typo here not in the actual config. I'll explore my options with our shibboleth Admin folks. And yes I was passing in LDAP info via the shib headers, but the user info just gets added into the directory (along with the default roles/groups) and no search of ldap and synchronizing of groups would happen (as the Directory is configured to do).

shall05mit commented 11 years ago

Hmmm, how about a regular (non delegated) LDAP directory, once it was synchronized and set as the primary User Directory I could probably use shibboleth SSO and be good... messy though we have a lot of users and groups - I'll need filters at least. - sigh

garysweaver commented 11 years ago

Ok, if Confluence is doing the automatic syncing, I wonder if we could use the Confluence API to do that. I'll ask Atlassian and do some searching. If it exposes that, that would be a heck of a lot easier than configuring the way I was talking about.

shall05mit commented 11 years ago

Thanks Gary!

garysweaver commented 11 years ago

Ok, Joe Clark of Atlassian probably did a lot of what we're talking about here: https://bitbucket.org/jaysee00/example-confluence-sso-authenticator/src/381eb95ebc08/src/main/java/com/atlassian/confluence/seraph/example/ExampleSSOAuthenticator.java

Might integrate some of that, or maybe you could use that authenticator instead if it works for you?

Which version of the Confluence HTTP Authenticator are you using, btw, since I just saw that you're using Confluence 3.5.17?

I have a sinking feeling I'm going to have to start maintaining three branches of Confluence HTTP Authenticator since I'm going to release 2.2.0 with support for Confluence 5.x shortly and I thought that Confluence HTTP Authenticator 2.1.x had some Confluence 4.1.x+ specific code in it.

garysweaver commented 11 years ago

Yes, reading back up the documentation, it looks like I had written that v2.0.1 is what you need to be using for Confluence 3.5.x, however if v2.1.16 was working for you, let me know. Also, please let me know if it looks like Joe's authenticator might work for you. (And if it doesn't try an older version of it.)

shall05mit commented 11 years ago

Ok, Joe Clark of Atlassian probably did a lot of what we're talking about here: https://bitbucket.org/jaysee00/example-confluence-sso-authenticator/src/381eb95ebc08/src/main/java/com/atlassian/confluence/seraph/example/ExampleSSOAuthenticator.java

Might integrate some of that.

I'll have a look at that code, but I'm no developer (lowly sysadmin) still I can deduce some of whats needed no doubt.

Which version of the Confluence HTTP Authenticator are you using, btw, since I just saw that you're using Confluence 3.5.17?

I'm using remoteUserAuth-2.1.3.jar - should I up-downgrade before moving on?

Thanks again!

shall05mit commented 11 years ago

Yes, reading back up the documentation, it looks like I had written that v2.0.1 is what you need to be using for Confluence 3.5.x, however if v2.1.16 was working for you, let me know. Also, please let me know if it looks like Joe's authenticator might work for you. (And if it doesn't try an older version of it.)

Well 2.1.3 was working for me like I said earlier...

How do I implement Joe's authenticator class?

Grab the source javac source.java

and then configuration??

I'll take another look at the source.

If I do get this working I do promise to document it (since I have to anyway for our procedures)

garysweaver commented 11 years ago

If you use Joe's authenticator, don't document that here, because it is a separate project. His project is built with Maven and the pom.xml, etc. is here: https://bitbucket.org/jaysee00/example-confluence-sso-authenticator/src - you'd want to get a Java developer to assist you, or ask Joe. Note that he says here that it is not suitable for production and is just an example: https://bitbucket.org/jaysee00/example-confluence-sso-authenticator/src/e1bd90c64370cb352525c8bcd3833a8952ea8dcf/README.txt?at=master

Basically, at this point I can't help much more until I have time to see whether we could use Joe's code as an example of similar functionality to later add to the authenticator. I noticed that you were trying to get help on the answers site before- you might just want to contact Atlassian support and see what they recommend.

Good luck, and I'll let you know if we end up adding similar functionality in the future. If you want this to stay open as a feature request, we can leave it open, but if you find another solution, let me know so I can close it. Thanks!

shall05mit commented 11 years ago

Hey Gary,

Yes I was coming to those conclusions as well. I read Joe's README and got the warning about it not being ready for prime time. Thanks for all the help!

garysweaver commented 11 years ago

Cool. Also, if 2.1.3 works in your version of Confluence, that's great. I'd hope that our version compatibility info was accurate, but unfortunately I don't have the resources to confirm at the moment, and rely on others like yourself to test. If you run into issues, though, try 2.0.x.

shall05mit commented 11 years ago

Hey Gary, I'm struggling trying to understand how to map group info using the dynamic roles functionality.

On 3/4/13 2:44 PM, Gary S. Weaver wrote:

Anyway- in the authenticator, you can do what you want by exposing all the group info via the IdP and SP. Look at the dynamic roles functionality.

So I would first map the attributes of the group info as defined in the attribute mapping for the SP?

header.dynamicroles.attributenames=Attribute1, Attribute2

What if I don't want to map the roles at all but just use the content of the headers? After all I'm just mapping a users groups exposed via the IdP/SP to groups of the same name in Confluence? How can the mapping happen if the groups are not necessarily known (for inclusion in the configuration file).

That is how others are doing it. It definitely is not as trivial as just pointing the authenticator at a configured LDAP repo,

but it should actually be faster than an additional call to LDAP during authentication.

I'm assuming that you are passing LDAP info in via the shib headers, otherwise what I just said probably makes no sense.

We are passing some LDAP info in the shib headers but not groups (yet). Thanks again and sorry to be so thick.

garysweaver commented 11 years ago

Yeah, the info here needs some serious cleanup, I think: https://github.com/chauth/confluence_http_authenticator/blob/7c57ec674fb1da07fddc69637a057c092557950b/README.md#dynamic-roles

It was described a bit differently in the source, which might make it more obvious: https://github.com/chauth/confluence_http_authenticator/blob/87079b9d1241d57e9ea84cf4fc6db0a3928e1626/src/main/java/shibauth/confluence/authentication/shibboleth/RemoteUserAuthenticator.java

Copied and pasted from the class javadoc and cleaned up, it says:


I don't know that this is fully up-to-date, though. May want to look in this file to see (partial) names of config properties: https://github.com/chauth/confluence_http_authenticator/blob/87079b9d1241d57e9ea84cf4fc6db0a3928e1626/src/main/java/shibauth/confluence/authentication/shibboleth/ShibAuthConstants.java


So, as a simple example, if you are in a test environment or don't want to precreate the groups (which is safer), in config you might use:

  dynamicroles.auto_create_role=true

And if you have headers called FOO and BAR, then first in the config file, we define FOO and its mapping:

  dynamicroles.header.FOO=MY_MAPPING
  dynamicroles.mapper.MY_MAPPING.match=(.*)
  dynamicroles.mapper.MY_MAPPING.transform=santa-$1

Where match is a Java regexp, kind of a subset as Perl 5 regexps, as described somewhat here: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/regex/Pattern.html

In this sample, we have captured the whole header as the group name, via (.*) and then prefixed the string "santa-" so if the header FOO has value "claus" then the group is "santa-claus".

  dynamicroles.header.BAR=MY_OTHER_MAPPING
  dynamicroles.mapper.MY_OTHER_MAPPING.match=(.*)
  dynamicroles.mapper.MY_OTHER_MAPPING.transform=reindeer-$1

So if the header BAR has value "pause" then the group is "reindeer-pause".

If you get confused, grab a Java dev that might be able to look at the code and assist.

Hope that helps.

shall05mit commented 11 years ago

Hey Gary,

Thanks for the clarification, pretty much what I had thought from reading the available docs.

So to be really clear, this:

#############################################

Seems to say that if I don't specify a transform method for the mapping the value of the header will be passed as is? thusly:

dynamicroles.header.FOO=MY_MAPPING dynamicroles.mapper.MY_MAPPING.match=(.*) (match all to get the full value of the group passed in the header FOO)

Or would it be more proper to pass $0 to the transform method?

dynamicroles.header.FOO=MY_MAPPING dynamicroles.mapper.MY_MAPPING.match=(.*) (match all to get the full value of the group passed in the header FOO) dynamicroles.mapper.MY_MAPPING.transform=$0 (just pass the input value through)

Which is what I interpret this to mean from the source:

##############################################

//in case someone uses $0 t = t.replaceAll("\$0", m.group(0));

##############################################

Thanks again!

garysweaver commented 11 years ago

This is the javadoc that helps explain what it is doing: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/regex/Matcher.html#group%28int%29

If the header value is "foobar jones", then $1 in the example:

  dynamicroles.mapper.MY_MAPPING.match=foo(.*)
  dynamicroles.mapper.MY_MAPPING.transform=$1

passes in the first group (.*), which is "bar jones".

But, in this:

  dynamicroles.mapper.MY_MAPPING.match=foo(.*)
  dynamicroles.mapper.MY_MAPPING.transform=$0

$0 returns the input subsequence, which would be "foobar jones".

In the case you described above:

  dynamicroles.header.FOO=MY_MAPPING
  dynamicroles.mapper.MY_MAPPING.match=(.*)

both:

  dynamicroles.mapper.MY_MAPPING.transform=$0

and:

  dynamicroles.mapper.MY_MAPPING.transform=$1

should return the same result.

If you don't care about groups, then:

    dynamicroles.header.FOO=MY_MAPPING
    dynamicroles.mapper.MY_MAPPING.match=.*
    dynamicroles.mapper.MY_MAPPING.transform=$0

But, that is up to you. Either is fine.

As for whether or not to specify the transform- because of this:

    String t = transform;
    if (t == null) {
        t = value;
    }

it doesn't really matter that much. If you don't pass in a transform, the transform becomes the header value itself. It just means that when the t.replaceAll's get called, nothing will happen.

So, yes:

dynamicroles.header.FOO=MY_MAPPING
dynamicroles.mapper.MY_MAPPING.match=.*

is more terse than:

dynamicroles.header.FOO=MY_MAPPING
dynamicroles.mapper.MY_MAPPING.match=.*
dynamicroles.mapper.MY_MAPPING.transform=$0

so, use the former rather than the latter, to reduce the size of your config file. :)

shall05mit commented 11 years ago

Yeah that's what I thought from my brief look at the source.

Another question by way of clarification.

Having one attribute like this one for my all of my groups:

Isn't going to work right? If my user is a member of 30 odd groups I'll need to provide a one-to-one group-to-attribute scheme.

Or will the mapper iterate through the values in the header if provided with an appropriate regex?

e.g.

dynamicroles.mapper.My_MAPPING.match=[^:]+

for a header containing group names separated by a ":"

Once I have this worked out I can write up an example of what we did to make it work and send it along if you think that's a useful contribution.

Thanks again!

garysweaver commented 11 years ago

I think that would not be possible right now because it is only able to do a replacement with a defined number of groups. It iterates the matches and then does a replace all of $(1-based group number) in the provided "transform" string value, so if you matched 10 groups with your regexp, you'd only be able to do:

So, thinking about how to fix:

If you want to fix it and do a pull req, go for it. Otherwise I can look at it this evening or soon. Should be trivial to add. Biggest pain is that this is for Confluence v3.5 so need to add to v2.0.x, v2.1.x, and v2.2.x (fun with backporting).

garysweaver commented 11 years ago

I have a feeling though that you shouldn't be sending in as single header value comma-delimited. Shib should be able to send in as array (attributes) with same header, I think? Shouldn't that work? It should work in the role mapping stuff at least, because of:

  private void getRolesFromHeader(HttpServletRequest request,
                                Set accumulatedRoles) {
        ...
        //process the headers by looking up only those list of registered headers
        for (Iterator headerIt = attribHeaders.iterator(); headerIt.hasNext(); ) {
            String headerName = headerIt.next().toString();
            for (Enumeration en = request.getHeaders(headerName); en.hasMoreElements(); ) {
                String headerValue = en.nextElement().toString();
garysweaver commented 11 years ago

I still like the idea of being able to transform all matches into their own groups even for a variable number of matches, so I could add it.

shall05mit commented 11 years ago

My ignorance of shibboleth is showing, I was basing my previous comment on an assumption that the header sent the values as colon separated name-value pairs - is that treated as an array? if groups are passed in via an attribute like:

isMemberOf

By shibboleth and that's an array

0 => group 1 => group1 2 => group2

Then I guess my previous naive configuration will work...

dynamicroles.header.isMemberOf=MAP_GROUPS dynamicroles.mapper.MAP_GROUPS.match=.*

Nothing to loose by trying I guess!

garysweaver commented 11 years ago

Ask on the shibboleth-users list (http://shibboleth.net/community/lists.html) if there is a way to configure the IdP and SP to do any or all of the following:

I'm not a Shib expert. It will be good to get them involved.

shall05mit commented 11 years ago

Gary - I just posted to the list, I'll also ask our local shibboleth admin.

garysweaver commented 11 years ago

Great, and I'll plan on taking a look tonight or soon at being able to provide a way or two to split up a single header into 0-many groups on some provided delimiter per what I said earlier. Thanks and hope that helped.

garysweaver commented 11 years ago

Try this out: https://github.com/chauth/confluence_http_authenticator/blob/master/releases/remoteUserAuth-2.0.2.1-alpha-1.jar

That should work in Confluence 3.5.x (I think?), .e.g. will allow colon-delimited groups in single isMemberOf header value:

  dynamicroles.header.isMemberOf=MY_MAPPING
  dynamicroles.mapper.MY_MAPPING.match=[^:]+
  dynamicroles.mapper.MY_MAPPING.transform_each=$_

$_ represents a single capture group within all capture groups. You could also do:

  dynamicroles.header.isMemberOf=MY_MAPPING
  dynamicroles.mapper.MY_MAPPING.match=[^:]+
  dynamicroles.mapper.MY_MAPPING.transform_each=foo-$_,bar-$_

which would create both a foo-(something) and bar-(something) group for each match.

If that works for you, let me know. Adding new features in old branches is going to royally screw up my versioning method of madness, but it is already a method of madness, so I guess that's ok.

Code's also in: https://github.com/chauth/confluence_http_authenticator/tree/2.0.2.1-alpha-1

shall05mit commented 11 years ago

Hi Gary,

As soon as I can get with my shibboleth admin and get them to expose groups in an attribute I'll be testing this...

May not happen til next week though.

On 3/8/13 12:49 AM, Gary S. Weaver wrote:

Try this out: https://github.com/chauth/confluence_http_authenticator/blob/master/releases/remoteUserAuth-2.0.2.1-alpha-1.jar

That should work in Confluence 3.5.x (I think?), .e.g. will allow colon-delimited groups in single isMemberOf header value:

   dynamicroles.header.isMemberOf=MY_MAPPING
   dynamicroles.mapper.MY_MAPPING.match=[^:]+
   dynamicroles.mapper.MY_MAPPING.transform_each=$_

$_ represents a single capture group within all capture groups. You could also do:

   dynamicroles.header.isMemberOf=MY_MAPPING
   dynamicroles.mapper.MY_MAPPING.match=[^:]+
   dynamicroles.mapper.MY_MAPPING.transform_each=foo-$_,bar-$_

which would create both a foo-(something) and bar-(something) group for each match.

If that works for you, let me know. Adding new features in old branches is going to royally screw up my versioning method of madness, but it is already a method of madness, so I guess that's ok.

Code's also in: https://github.com/chauth/confluence_http_authenticator/tree/2.0.2.1-alpha-1


Reply to this email directly or view it on GitHub: https://github.com/chauth/confluence_http_authenticator/issues/3#issuecomment-14603798

shall05mit commented 11 years ago

Hi Gary,

It turns out shibboleth administrators are not keen on the idea of exposing group membership info for a variety of reasons, (expensive queries amongst other things)..

As a result this option is back-burnered for now and I'm looking at either a full LDAP synchronization in Confluence with shibboleth (rather than a delegated directory with the copy users on first log in option) or enlisting our devs to write a custom authentication module (extending the seraph class).

I'll let you know if things change here and I get a chance to use test the alpha code.

On 3/8/13 12:49 AM, Gary S. Weaver wrote:

Try this out: https://github.com/chauth/confluence_http_authenticator/blob/master/releases/remoteUserAuth-2.0.2.1-alpha-1.jar

That should work in Confluence 3.5.x (I think?), .e.g. will allow colon-delimited groups in single isMemberOf header value:

   dynamicroles.header.isMemberOf=MY_MAPPING
   dynamicroles.mapper.MY_MAPPING.match=[^:]+
   dynamicroles.mapper.MY_MAPPING.transform_each=$_

$_ represents a single capture group within all capture groups. You could also do:

   dynamicroles.header.isMemberOf=MY_MAPPING
   dynamicroles.mapper.MY_MAPPING.match=[^:]+
   dynamicroles.mapper.MY_MAPPING.transform_each=foo-$_,bar-$_

which would create both a foo-(something) and bar-(something) group for each match.

If that works for you, let me know. Adding new features in old branches is going to royally screw up my versioning method of madness, but it is already a method of madness, so I guess that's ok.

Code's also in: https://github.com/chauth/confluence_http_authenticator/tree/2.0.2.1-alpha-1


Reply to this email directly or view it on GitHub: https://github.com/chauth/confluence_http_authenticator/issues/3#issuecomment-14603798

Scott Hall Enterprise Systems Administration W91-219b Massachusetts Institute of Technology 77 Mass Ave Cambridge, MA 02139 617-324-4814

bananastalktome commented 11 years ago

@shall05mit For what it's worth, we do full LDAP synchronization of around 40,000 users (though we use local groups) and use Shibboleth for logins just fine.

shall05mit commented 10 years ago

Hi Gary, Well it's six months down the road and I wanted to let you know that I got a config working using: 2.0.2.1-alpha-1 our idp released a group attribute "memberOf" Looks like this in the header - memberOf CN=group1,OU=groups,OU=Admin,DC=group,DC=mit,DC=edu; CN=group2,OU=groups,OU=Admin,DC=group,DC=mit,DC=edu; CN=group3.... And I'm using a configuration based on what you sent in March:

header.dynamicroles.attributenames=memberOf dynamicroles.header.memberOf=rolestomap dynamicroles.mapper.rolestomap.match=CN=(.*?) dynamicroles.mapper.rolestomap.transformeach=$

So far so good - I wonder after all this time if this behavior was merged into the master branch? Thanks again for all the help