Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.Sign up
WIP - Expose attributes to script attribute repositories via thread local #4696
This stores an "in progress" principal in a thread local so it (the attributes in it) can be accessed from script attribute repositories. It includes attributes gathered during authentication and accumulates attributes from the attribute repositories as they are queried in order.
Accessing the attributes from a script would look like this:
I have a use-case where x509 and LDAP auth are both supported, with some x509 users in LDAP and some not. During X509 auth LDAP is queried via user principal from cert SAN and additional attributes are retrieved (if user is in LDAP). Another attribute repository (groovy script) needs access to the subject DN (another X509 attribute) in order to make an external request for more attributes.
I updated the two principal resolvers that add attributes from the credentials (x509 and WSFED) and I saw during testing that some attributes gathered from LDAP during authentication (for use by PM module) were available in a script attribute repository.
This is WIP pending feedback and then I can add tests and documentation.
mmoayyed left a comment
I think we need to review and discuss the use case in more detail to find an alternative. The patch here, while likely adequate to address the need feels a bit too brittle.
Let me clarify and confirm a few things:
You have an X509 resolver that fetches a principal from a cert attribute, and uses this attribute to query LDAP to collect more attributes to build the final principal. So once this step is complete, you have a resolved Principal that contains some stuff from X509, and may or may not contain additional attributes from LDAP. Is that correct?
Then, you have a Groovy attribute repository(?) that needs access to this already-resolved principal to make a separate call to some other resource to fetch attributes and more, right? If so, why do you need to do this in a Groovy script outside the already-available and processed principal resolution engine, and do this strange cross-walk?
Why not, simply:
Do this all inside your own resolver and inject it into CAS as custom code. The solution that you have here seems strangely complicated for something that might be customized and injected into CAS in form of a simple resolver with code re-use from existing components.
Thanks for the review and the comments. I agree this needs work but I got it working and wanted feedback before investing more time in it.
I am using the SUBJECT_ALT_NAME x509 authentication b/c that is the link to the user in LDAP but I also need to query attributes (using groovy attribute repository) from an external service that requires the subjectDn and the issuerDn which are both attributes extracted from the certificate. I have a java client that the groovy script calls since the service requires x509 client auth and the results need to be processed into CAS attributes. Theoretically (if http request is on thread local) I could re-parse the certificate and re-extract the attributes but I would rather not have to do that if the attributes could be made available to groovy since they were already parsed out by CAS.
To date I have been able to do everything I need to do (for three different CAS deployments: dev and two different production environments) without custom Java code other than the client code for external services but that Java code is not aware of CAS, it is just bundled with CAS so it can be called from groovy. Each deployment has different service definitions and spring profiles allow for different properties and allow for different selections of attribute repositories but they all run using the same CAS image and no custom CAS code (because CAS has so many configuration options it hasn't been necessary). I was getting away with using x509 SUBJECT_ALT_NAME in dev and x509 SUBJECT_DN in production environments which meant that I was able to use SUBJECT_DN in the groovy script to call the external service. Now I need to support some internal tools outside of dev where LDAP will have to be queried (by either SAN or EMAIL depending on environment) and I also need to support a new external service that needs subject DN and issuer DN as arguments for attribute retrieval.
If you don't think this can be cleaned up and made less brittle/more maintainable then I can go the custom resolver route, I just thought that what is useful for one person might be useful for others. I realize x509 is only used in a few niche areas (mostly govt) but I would imagine being able to manufacture or retrieve attributes using the attributes gathered from previous attribute repositories would be generally useful but people have survived without it until now so maybe I am wrong.
Thanks for the notes. Most helpful.
Definitely; I fully agree. Exposing what's ready resolved to downstream components such as attribute repositories is quite legitimate and an attractive use case and something we ought to support, and I personally would very much like for CAS to handle it without having you write custom code for sure. That said, the way we are going about it should be simplified and I have a proposal/suggestion that might get us the best of both worlds:
This is the sort of use case that would require API re-work and much of it likely needs to happen inside PersonDirectory. At this point, we are using a ThreadLocal instance as a bandaid and a bridge to store what's resolved and expose it later to attribute repositories, etc. I propose that it would be much better, semantically, if the attribute repository and family could directly receive and operate on what's resolved via known APIs and parameter passing, etc vs holding thread-local contexts for later access.
In other words, instead of:
1- Resolve the principal from authn
I submit that we are much better off to:
1- Resolve the principal from authn
Steps 1 and 3 already are pretty much covered. We should just focus on step 2.
This allows for:
Certainly it's more work, but I'd argue that it's likely easier to maintain and reason about and now that PersonDirectory is gearing up for a v2 release, it's perfect timing to maybe rethink APIs and allow for this sort of flexibility there.
I hope you find this agreeable, and if so, we should probably start by a blueprint proposal of an API for Person Directory to see what we need to change at a minimum to allow for this use case there. Since you are the use-case owner, you're in a perfect position to start the work and back it up by a real deployment environment. You're most welcome to start with a general outline, or if you prefer, I can try to put something together for person directory to make it easier for you to test it from the CAS perspective.
I agree that adding it to the person-directory API is probably the right way to go. In the short term so I can get a release out I may follow your suggestion of temporarily making a custom principal resolver bean, since for my specific use-case I really just need to override the x509 principal resolver bean and I should be able to create and cleanup a thread local just by overriding the retrievePersonAttributes method.
I can help out with the person-directory changes but I would prefer if you proposed the API change and I could work on implementing it. When I looked at it before it almost seemed like the API might be there since they let you call getPeople with a
There are also some deprecated methods in IPersonAttributeDao and maybe we should remove those as part of 2.0 (they were deprecated in 2008).