Attached are some quick and dirty class/seq diagrams that outline a slightly different approach to determining which credentials to authenticate, choosing how to extract them, and then actually performing the authentication.
This approach would still require configuring your customized UT Processor in WSS4J in order to disable WSS4Js clumsy authentication system but moves the work of creating the SecurityContext and JAAS subject out of the WSS4J interceptors and into generic authentication framework. It looks like WSS4JInInterceptor simply looks for the first principal it finds in the WSS4J results and sends that on its way. When multiple tokens appear in a message, this approach may not always grab the one the application really requires. This approach works after the WSS4J security processing completes and examines the results from WSS4J, or another security framework if we ever use one, and determines which profile is in effect. A delegate interceptor is then called to extract the correct user credentials from the message and perform any additional validation that is needed for a given profile. The extracted credentials are then passed to an AuthenticationStrategy to perform the actual authentication. The AuthenticationService would return something like a JAAS Subject that is then used to create the CXF SecurityContext. As you can see, the "Credentials" concept is pretty vague as there are many different types of credentials out there. I feel that the most common two are X509 certificates and Username Tokens. This approach requires many more classes and could be more complex to configure. I have not thoroughly been over what the default SecurityProfile evaluator should be like nor do I know what concrete implementations of AbstractSecurityContextProvidingInterceptor should be provided. What I feel to be the three most common interceptor instances are listed in the class diagram. As for the default SecurityProfileChooser, I initially suggest that it simply allows the user to enable/disable no security, TLS, BST, and UT while allowing the end user to configure the desired precedence of each profile over the other. This approach can easily work with Spring Security as an AuthenticationService implementation. -----Original Message----- From: Sergey Beryozkin [mailto:sberyoz...@gmail.com] Sent: Wednesday, April 21, 2010 5:47 PM To: Daniel Kulp Cc: dev@cxf.apache.org Subject: Re: Using WS-Security UsernameToken to authenticate users and populate SecurityContexts I added a system test for a policy first case and refactored few bits along the way, as well as closed [1] as 'Wont fix', at least for now. I've just updated UsernameTokenInterceptor[1] so that a (WSS4J) principal can be created directly if a message property disabling the validation of passwords has been set. This property can be set as a jaxws contextual property in which case interceptors further in the chain will be able to get the (unauthenticated) Principal, validate it, and set a SecurityContext as needed. Another approach used in the system test is to write a custom interceptor[3] extending UsernameTokenInterceptor and disable the validation from there. This custom interceptor is currently being registered by setting a bus property, see [4]. Note that a jaxws endpoint adds SimpleAuthorizationInterceptor only and has no callbacks registered. See [5] for more details. It looks quite reasonable to me at the moment, perhaps there could be a simpler way to register custom interceptors. Dan, you've mentioned the fact you were planning to refactor some of the policy interceptors so that WSS4JInterceptor is not used for UsernameToken processing at all. I'd appreciate if you could look into this refactoring yourself, there could be some subtleties there I'm not aware of. Also, personally I'd prefer registering a noop processor with WSS4J rather adding a flag to WSS4J, perhaps this noop processor can be used for handling other types of tokens, using an approach similar to the one taken by UsernameTokenInterceptor, unless yourself, David V, others have something else in mind... cheers, Sergey [1] https://issues.apache.org/jira/browse/WSS-229 [2] http://svn.apache.org/repos/asf/cxf/trunk/rt/ws/security/src/main/java/org/a pache/cxf/ws/security/wss4j/UsernameTokenInterceptor.java [3] http://svn.apache.org/repos/asf/cxf/trunk/systests/ws-specs/src/test/java/or g/apache/cxf/systest/ws/wssec10/server/CustomUsernameTokenInterceptor.java [4] http://svn.apache.org/repos/asf/cxf/trunk/systests/ws-specs/src/test/java/or g/apache/cxf/systest/ws/wssec10/server/server_restricted_authorized.xml [5] http://svn.apache.org/viewvc?rev=936521&view=rev On Mon, Apr 19, 2010 at 1:46 PM, Sergey Beryozkin <sberyoz...@gmail.com>wrote: > Hi > > I've added an initial patch for addressing a policy-first case, see [1]. > It's a patch because it depends on another one I submitted to WSS4J [2]. > Both patches need more work (tests, etc) but I'd just like to initiate a > discussion/review. > > The idea behind [1] is quite similar to the one used in supporting a > java-first case, where a custom interceptor extends an > AbstractWSS4JSecurityContextPr > oviding interceptor. But is is much simpler in [1] where > UsernameTokenProcessor may be optionally extended and its createSubject > method be overridden. Provided [2] gets applied then a subclass will just > have a property set disabling the (WSS4J) validation of passwords and will > do its own validation in createSubject method. > > This is really all what will be needed in simple cases, where a > DefaultSecurityContext will do, but optionally, createSecurityContext can > be overridden too. > > A user would need to set a bus property > "org.apache.cxf.ws.security.usernametoken.interceptor" referincing a custom > interceptor which will indicate to the WSSecurityPolicyLoader that a custom > UsernameTokenProcessor subclass will need to be loaded. > > Similar approach can be employed for handling other types of tokens. > > cheers, Sergey > > [1] https://issues.apache.org/jira/browse/CXF-2754 > [2] https://issues.apache.org/jira/browse/WSS-229 > > > On Mon, Apr 19, 2010 at 1:43 PM, Sergey Beryozkin <sberyoz...@gmail.com>wrote: > >> Just realized I did not CC tp dev when replying to Dan the other day : >> >> Hi Dan >> >> >> On Fri, Apr 9, 2010 at 2:50 PM, Daniel Kulp <dk...@apache.org> wrote: >> >>> >>> My main "concern" with the implementation of this is that it's done as a >>> direct subclass of the WSS4JInInterceptor and thus not really usable by >>> the >>> policy based endpoints as those interceptors subclass WSS4JInInterceptor >>> as >>> well. >>> >>> I think the better approach may be to add a flag to wss4j (I can help >>> commit >>> changes there if needed) to have it not do any UserName token processing >>> at >>> all. (aside: this may be doable without changes to wss4j by >>> registering our >>> own "do nothing processor") Then, have another interceptor that runs >>> after >>> the WSS4JInInterceptor that would actually handle the UsernameToken and >>> verify >>> anything it needs and such. >>> >> >> This sounds like a very good idea, I agree the proposed approach won't do >> for the cases where policies drive the >> creation of interceptors. >> >> Having said that, I think the abstract utility interceptor extending >> WSS4JInInterceptor >> may still be used in cases where users start from manually configuring >> jaxws endpoints. In these cases they'd need to >> list up to 3 interceptors (the one which extends >> AbstractWSS4JSecuriyContextInterceptor, the authorizing interceptor if the >> authorization is needed plus may be a SAAJ one) but otherwise, when say a >> clear text password has been encrypted, they'd still need to specify >> WSS4JInInterceptor (with a flag disabling UsernameToken checks) plus >> UsernameTokenInterceptor, etc. >> >> At the moment AbstractWSS4JSecuriyContextInterceptor is a bit complicated >> due to the fact it blocks the WSS4J digest checks and thus also creates a >> security engine per every request, but it all will be gone in due time... >> >> >>> >>> To be honest, I WANT to do this for the Policy based stuff anyway. >>> There is >>> currently some duplicated code between the PolicyBasedWSS4JIinInterceptor >>> and >>> the new UsernameTokenInterceptor that could be eliminated by having the >>> PolicyBasedWSS4JIinInterceptor not do UsernameTokens at all and delegate >>> that >>> completely to the UsernameTokenInterceptor. >>> >> >> What I will do is I will experiment with the test you added (thanks :-)) >> and see how UsernameTokenInterceptor can be refactored >> so that a subclass can get an easy access to password, nonce, etc. I think >> I will need to come up with a contextual property so that a custom >> UsernameTokenInterceptor can be installed if needed. Or may be >> UsernameTokenInterceptor can store the details in a message to be later >> retrieved and processed for creating SecurityContext - but I'm not sure >> about it just yet. >> >> >>> >>> Basically, it would be good if the WSS4JIn* stuff just handled the >>> encryption/signature stuff and then let the authorization validations >>> stuff to >>> later interceptors. That would include things like key validation >>> checking >>> and stuff as well. Probably SAML token validation as well. >>> >>> >> sounds good >> >> cheers, Sergey >> >> On Fri, Apr 9, 2010 at 2:50 PM, Daniel Kulp <dk...@apache.org> wrote: >> >>> >>> My main "concern" with the implementation of this is that it's done as a >>> direct subclass of the WSS4JInInterceptor and thus not really usable by >>> the >>> policy based endpoints as those interceptors subclass WSS4JInInterceptor >>> as >>> well. >>> >>> I think the better approach may be to add a flag to wss4j (I can help >>> commit >>> changes there if needed) to have it not do any UserName token processing >>> at >>> all. (aside: this may be doable without changes to wss4j by >>> registering our >>> own "do nothing processor") Then, have another interceptor that runs >>> after >>> the WSS4JInInterceptor that would actually handle the UsernameToken and >>> verify >>> anything it needs and such. >>> >>> To be honest, I WANT to do this for the Policy based stuff anyway. >>> There is >>> currently some duplicated code between the PolicyBasedWSS4JIinInterceptor >>> and >>> the new UsernameTokenInterceptor that could be eliminated by having the >>> PolicyBasedWSS4JIinInterceptor not do UsernameTokens at all and delegate >>> that >>> completely to the UsernameTokenInterceptor. >>> >>> Basically, it would be good if the WSS4JIn* stuff just handled the >>> encryption/signature stuff and then let the authorization validations >>> stuff to >>> later interceptors. That would include things like key validation >>> checking >>> and stuff as well. Probably SAML token validation as well. >>> >>> Dan >>> >>> >>> On Thursday 08 April 2010 12:09:24 pm Sergey Beryozkin wrote: >>> > Hi David >>> > >>> > thanks for the comments... >>> > >>> > On Wed, Apr 7, 2010 at 9:41 PM, David Valeri <dval...@apache.org> >>> wrote: >>> > > Sergey, >>> > > >>> > > I think this type of functionality would be very useful to a number >>> of >>> > > folks. I have built two similar capabilities for clients very >>> recently >>> > > using CXF and Spring Security. Based on the code provided below, I >>> have >>> > > several points that I would like to see addressed in a solution. >>> > > >>> > > 1) Architecture to support more than just UsernameTokens. I have >>> worked >>> > > with systems that need to authenticate a user using UsernameTokens, >>> > > BinarySecurityTokens, SAML Assertions, and a combination of more than >>> one >>> > > of >>> > > these at a time. >>> > >>> > Supporting UsernameTokens is the initial requirement. At the moment I >>> do >>> > not even know how BinarySecurityTokens or SAML Assertions are >>> > processed/validated in CXF or WSS4J. >>> > >>> > > For the most part, WSS4J simply validates the structural >>> > > details of security. That is, signature validity, trust chaining of >>> > > digital >>> > > certificates, etc. As Glen pointed out with his reference to >>> > > https://issues.apache.org/jira/browse/WSS-183, WSS4J sometimes >>> performs >>> > > its >>> > > own password checking (authentication). Unfortunately, WSS4J doesn't >>> > > provide hooks for authenticating other forms of credentials that I >>> have >>> > > listed above (I don't consider trust to be equivalent to >>> authentication). >>> > > It would be best if the authentication interface supported multiple >>> > > credential types and allowed for authentication to be performed in a >>> > > single location in the same manner every time (not sometimes in the >>> > > WSS4J callback and sometimes in another interceptor for non-UT based >>> > > credentials). >>> > >>> > Makes sense. Assuming it is WSS4J which validates (the structure of) >>> > BinarySecurityTokens then >>> AbstractWSS4JSecurityContextProvidingInterceptor >>> > can also implement a processor for BinarySecurityTokens and delegate to >>> > subclass to authenticate and setup a subject. Some extra methods will >>> need >>> > to be added, to be optionally overridden. >>> > >>> > If it is not only WSS4J which is involved then perhaps another option >>> is to >>> > store (from WSS4J callback handler, etc) relevant details such username >>> > token details, etc to be acted upon by other interceptors. >>> > >>> > > That >>> > > last bit there means disabling WSS4J's password authentication since >>> it >>> > > gets >>> > > in the way of doing it later in our own interceptor. >>> > >>> > AbstractWSS4JSecurityContextProvidingInterceptor does it now by >>> > implementing a simplified UsernameTokenProcessor >>> > >>> > > 2) Allow for end-user flexibility in choosing the credentials they >>> want >>> > > to authenticate. For instance, each user is going to have their own >>> > > security profiles and authentication requirements. For instance, a >>> > > message contains a UT for a portal user and a digital signature from >>> the >>> > > portal (I know using >>> > > a SAML Assertion would be better here, but people still do it this >>> way). >>> > > Each organization will have different requirements as to which >>> > > credentials get authenticated and what needs to end up in the >>> security >>> > > context. >>> > >>> > I suppose AbstractWSS4JSecurityContextProvidingInterceptor subclasses >>> > should be able to do it, for username tokens and other tokens later on. >>> > >>> > > 3) Decouple the authentication interface from WSS4J. What is passed >>> in >>> > > needs to be abstracted enough that it can work with other WS-Security >>> > > libraries as well. >>> > >>> > the only WSS4J class which is leaked at the moment is >>> WSSecurityException. >>> > Perhaps we can come up later on with a different more generic approach >>> > which does not depend on WSS4J at all. As Dan indicated, in some cases >>> > WSS4JInInterceptor is not even used, so that case will need to be >>> > addressed. Experimenting wuth binary tokens might help with identifying >>> > another solution. >>> > >>> > > 4) It would be nice to be able to perform authorization using >>> something >>> > > like >>> > > Spring Security at the service operation level. With a POJO or >>> JAX-WS >>> > > based >>> > > service, one can just use Spring Security's method interceptor to >>> provide >>> > > such security; however, in situations where one only has a WSDL based >>> > > service or a provider style service, a method interceptor can't be >>> used. >>> > > >>> > > It >>> > > >>> > > would be nice to provide a hook into Spring Security to allow >>> end-users >>> > > to specify role based authorization policy based on a combination of >>> > > interface, >>> > > instance, and operation names. It seems like your >>> > > AbstractAuthorizingInterceptor and SimpleAuthorizingInterceptor are >>> > > looking in this direction, but I think it would be best if we can >>> stand >>> > > on the shoulders of the Spring Security giant as much as possible so >>> > > that we can take advantage of their rich authorization manager, >>> voter, >>> > > XML >>> > > configuration >>> > > capabilities. >>> > >>> > Not sure what to say here yet. But I think non-Spring users should be >>> taken >>> > care of too. Or when simpler cases are dealt with then perhaps there's >>> no >>> > need to bring in Spring security. Perhaps the utility authorization >>> > interceptors should just not be used when Spring Security is preferred >>> ? >>> > >>> > > 5) Try not to leave the ServiceMix CXF-BC out in the cold. The >>> CXF-BC >>> > > currently has a limited capability to select the credentials to >>> > > authenticate >>> > > and would benefit from 1 and 2 above. The CXF-BC ultimately >>> delegates >>> > > authentication to the JBI container through a ServiceMix components >>> > > authentication service abstraction of JAAS. Whatever solution we >>> have >>> > > for 1 >>> > > and 2 would help out the component if the ServiceMix authentication >>> > > service abstraction could be wired up in lieu of whatever we provide >>> out >>> > > of the box. >>> > >>> > I'm not planning to contribute to ServiceMix. I agree though that an >>> ideal >>> > solution will meet multiple requirements >>> > >>> > thanks, Sergey >>> > >>> > > -----Original Message----- >>> > > From: Sergey Beryozkin [mailto:sberyoz...@gmail.com] >>> > > Sent: Wednesday, April 07, 2010 10:11 AM >>> > > To: dev@cxf.apache.org >>> > > Subject: Using WS-Security UsernameToken to authenticate users and >>> > > populate SecurityContexts >>> > > >>> > > Hi >>> > > >>> > > I've been looking recently at extending the CXF WS-Security component >>> > > such that a current UsernameToken could be used by custom >>> interceptors >>> > > to authenticate a user with the external security systems and, if >>> > > possible, provide enough information for CXF to populate a >>> > > SecurityContext [1] to be used later on for >>> > > authorization decisions. >>> > > >>> > > Here is the approach I've taken so far. >>> > > A custom interceptor extends >>> > > AbstractWSS4JSecurityContextProvidingInterceptor [2] and the only >>> method >>> > > it overrides is >>> > > >>> > > abstract Subject createSubject(String name, String password, boolean >>> > > isDigest, >>> > > >>> > > String nonce, >>> > > String created) throws >>> > > >>> > > WSSecurityException; >>> > > >>> > > >>> > > For example, see [3]. >>> > > >>> > > The idea here is that a custom interceptor interfaces whichever way >>> it >>> > > needs >>> > > to with the external system and populates a Subject following this >>> simple >>> > > rule : first Subject principal is the current user (identified by a >>> > > 'name' argument), followed by one or more Groups this user is a >>> member >>> > > of. AbstractWSS4JSecurityContextProvidingInterceptor will use this >>> > > Subject to provide a functional SecurityContext instance. >>> > > >>> > > This is the first part, next is how to utilize a SecurityContext and >>> get >>> > > the >>> > > expected roles associated one way or the other with a current method >>> to >>> > > be invoked. There's a number of usual options available here, perhaps >>> > > even SpringSecurity can be used now that SecurityContext is >>> available, >>> > > or application code or other custom CXF interceptor can check the >>> known >>> > > roles against SecurityContext. >>> > > >>> > > I've also added AbstractAuthorizingInInterceptor interceptor which >>> custom >>> > > interceptors can override and return a list of expected roles given a >>> > > (service) Method to be invoked upon, AbstractAuthorizingInInterceptor >>> > > will then ask available SecurityContext to match the roles; one >>> concrete >>> > > implementation is SimpleAuthorizingInterceptor[5], it can be injected >>> > > with a >>> > > method specific or class (applying to all methods) roles. Another >>> > > implementation which I will likely add later on will be injected with >>> a >>> > > name >>> > > of annotation such as RolesAlloved and it will introspect a method >>> and >>> > > its class. >>> > > >>> > > Note that I haven't looked into the case when a policy runtimes adds >>> the >>> > > interceptors yet (as opposed to interceptors being configured form >>> > > Spring/programmatically). I think an optional contextual property >>> will >>> > > need to be setup in such cases for users be able to indicate that say >>> an >>> > > interceptor such as [3] has to be used as opposed to >>> WSS4JInInterceptor, >>> > > etc. >>> > > >>> > > I'm going to validate this approach with JBoss CXF. If you have any >>> > > comments >>> > > then please let me know. >>> > > >>> > > I think we may have a simpler alternative eventually to the way >>> > > authorization decisions are made. [1]-[3] is specific to ws-security, >>> but >>> > > [4]-[5] is not >>> > > >>> > > cheers, Sergey >>> > > >>> > > [1] https://issues.apache.org/jira/browse/CXF-2754 >>> > > [2] >>> > > >>> > > >>> http://svn.apache.org/repos/asf/cxf/trunk/rt/ws/security/src/main/java/or >>> > > g/a >>> > > >>> > > >>> pache/cxf/ws/security/wss4j/AbstractWSS4JSecurityContextProvidingIntercep >>> > > tor< >>> http://svn.apache.org/repos/asf/cxf/trunk/rt/ws/security/src/main/jav >>> > > >>> a/org/a%0Apache/cxf/ws/security/wss4j/AbstractWSS4JSecurityContextProvidi >>> > > ngInterceptor> .java >>> > > [3] >>> > > >>> > > >>> http://svn.apache.org/repos/asf/cxf/trunk/rt/ws/security/src/test/java/or >>> > > g/a >>> > > >>> pache/cxf/ws/security/wss4j/SimpleSubjectCreatingInterceptor.java<http:/ >>> > > / >>> svn.apache.org/repos/asf/cxf/trunk/rt/ws/security/src/test/java/org/a%0A >>> > > pache/cxf/ws/security/wss4j/SimpleSubjectCreatingInterceptor.java> >>> [4] >>> > > >>> > > >>> http://svn.apache.org/repos/asf/cxf/trunk/rt/core/src/main/java/org/apach >>> > > e/c >>> > > xf/interceptor/security/AbstractAuthorizingInInterceptor.java< >>> http://svn >>> > > . >>> apache.org/repos/asf/cxf/trunk/rt/core/src/main/java/org/apache/c%0Axf/i >>> > > nterceptor/security/AbstractAuthorizingInInterceptor.java> [5] >>> > > >>> > > >>> http://svn.apache.org/repos/asf/cxf/trunk/rt/core/src/main/java/org/apach >>> > > e/c >>> > > xf/interceptor/security/SimpleAuthorizingInterceptor.java< >>> http://svn.apa >>> > > >>> che.org/repos/asf/cxf/trunk/rt/core/src/main/java/org/apache/c%0Axf/inter >>> > > ceptor/security/SimpleAuthorizingInterceptor.java> >>> >>> -- >>> Daniel Kulp >>> dk...@apache.org >>> http://dankulp.com/blog >>> >> >> >