Hi everyone, hi Mike, I really like Mike's suggestion of splitting up the JAAS code - that could help a lot to make SSO (or other custom login) solutions more understandable in terms of the code, and also easier/faster to implement...
I also agree with his suggestion that the LoginFilter should be able to return a code indicating the request is successfully and finally authenticated (STATUS_SUCCEEDED_FINAL) - thereby terminating the processing of further LoginHandlers. This is an optimization that makes a lot of sense in any scenario, since normally, if a login succeeds with one LoginHandler, it will be NOT_HANDLED by all the other login-handlers. There is not really any scenario where both BASIC auth and FORM (just for example) could both succeed. In addition, it would be nice to have an equivalent status-code for authoritatively terminating logins with a failure. At the moment, if your LoginHandler returns NO_LOGIN, then the LoginFilter still simply tries the next login-handler. But what if the login-attempt contained SSO information, but it simply isn't valid? Is it really wise to let the other login-handlers try to handle this request? Instead the LoginHandler should be able to return a status indicating that further processing should be stopped (NO_LOGIN_FINAL). Finally, I think there needs to be explicit consideration for the session. At the moment, even if the user has been successfully authenticated previously, the system still attempts to login the user via all existing LoginHandlers, on each request. This behavior is bad, for a number of reasons: 1) For FORM and BASIC auth that is only a minimal performance hit, but for other login systems it might cause unnecessary calls to backends like LDAP or AD Servers, so it's bad for performance. 2) SSO Systems, depending on the implementation, will re-authenticate the user on each request, killing the user's existing session. 3) Other SSO Systems will only authenticate on the first request, meaning subsequent attempts to re-authenticate will fail, possibly with nasty error messages. Why is Magnolia re-authenticating already authenticated sessions?? IMHO there should be a "SessionLoginHandler", configured first in the LoginHandler sequence, which returns "STATUS_SUCCEEDED_FINAL" (without killing the existing session) if the user has an existing and valid session. In this way the other LoginHandlers would not be consulted for requests already associated with an existing session. At the moment this is happening "unofficially": if none of the LoginHandlers returns STATUS_SUCCEEDED or STATUS_IN_PROCESS then the LoginFilter continues processing without doing anything to the (possibly) existing session. So only after all LoginHandlers have said "I don't know" does the existing session get a chance... Regards from Vienna, Richard -----Ursprüngliche Nachricht----- Von: [email protected] [mailto:[email protected]] Im Auftrag von Mike Wilson (via Magnolia Forums) Gesendet: Montag, 01. Oktober 2012 15:33 An: Magnolia User List Betreff: [magnolia-user] Re: suggestions for implementation of AD login when authentication is done externally [b]Implementation[/b] As promised, here's my solution. I subclassed ADAuthenticationModule like so: [code]public class ADSingleSignOnAuthenticationModule extends ADAuthenticationModule { @Override protected void validateUser(final String jndiConfigFilePath, final String connectionName) throws AuthenticationException, NamingException, LoginException, AccountException { // Force ssoSlave (to avoid attempt to log in to LDAP as user) and call superclass this.getProperties().setProperty(AttributeMap.SSO_SLAVE, "true"); super.validateUser(jndiConfigFilePath, connectionName); // Lookup user information SearchControls ctrl = new SearchControls(); ctrl.setSearchScope(SearchControls.SUBTREE_SCOPE); final String filter = getUserFilter(this.name); NamingEnumeration<SearchResult> answer = this.getContext().search(this.getProperties().getProperty(AttributeMap.INITIAL_SEARCH_STRING), filter, ctrl); this.parseSearchResult(answer); } }[/code] and created a separate chain in jaas.config: [code]magnoliasso { ADSingleSignOnAuthenticationModule requisite realm=external; info.magnolia.jaas.sp.jcr.JCRAuthorizationModule required; }; magnolia { info.magnolia.jaas.sp.jcr.JCRAuthenticationModule requisite; info.magnolia.jaas.sp.jcr.JCRAuthorizationModule required; }; [/code] The new JAAS chain is then referenced by a custom LoginHandler. This way I can reuse the existing CallbackHandlers etc. [b]Suggestions[/b] I discovered a few things along the way that could be improved in Magnolia code (looking at 4.4.5 codebase): 1) Provide ssoSlave alternative where only authentication is external The current ADAuthenticationModule provides the following two modes: [code] ssoSlave=false: - connect to AD with admin credentials - load user information from AD (group memberships etc) - authenticate user by logging in to AD with user/password ssoSlave=true: - connect to AD with admin credentials [/code] This doesn't benefit the case where you just want to authenticate separately and then continue the standard flow for AD users. A more flexible approach would be to refactor the LoginModules into a chain with four tasks: [code] Task Current JCR code Current AD code ---- ---------------- --------------- a) authenticate user JCRAuthenticationModule ADAuthenticationModule(ssoSlave=false) b) load user info JCRAuthenticationModule ADAuthenticationModule(ssoSlave=false) c) associate user with groups and roles JCRAuthenticationModule ADAuthenticationModule d) setup permissions based on groups/roles JCRAuthorizationModule [/code] If each task was to be handled by a separate LoginModule class it would be easier to override the desired parts with only configuration or minimal programming needed. 2) Allow LoginHandler to say "handled" Currently the LoginFilter's LoginHandler chain will normally run through all LoginHandlers on every request even if there is already a user logged in. For SingleSignOn use cases you may want to force the SSO user and only allow form login if there is no SSO user available. This would be possible by putting the SSO LoginHandler first in the chain and then being able to return a "handled" status to stop executing the rest of the chain, thereby disabling form login and other login methods. 3) Improve portability (JBoss) As described in Magnolia docs, JAAS configuration needs to be maintained in two different files in different formats to cater for both JBoss and other appservers. It would be good to see a single file solution (maybe possible with JBoss dynamic security domains)? -- Context is everything: http://forum.magnolia-cms.com/forum/thread.html?threadId=878e325c-2ac2-4b8f-8575-640c0c0740f3 ---------------------------------------------------------------- For list details, see http://www.magnolia-cms.com/community/mailing-lists.html Alternatively, use our forums: http://forum.magnolia-cms.com/ To unsubscribe, E-mail to: <[email protected]> ---------------------------------------------------------------- ---------------------------------------------------------------- For list details, see http://www.magnolia-cms.com/community/mailing-lists.html Alternatively, use our forums: http://forum.magnolia-cms.com/ To unsubscribe, E-mail to: <[email protected]> ----------------------------------------------------------------
