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]>
----------------------------------------------------------------

Reply via email to