0 Replies Latest reply on Mar 26, 2014 12:25 PM by code-monkey

    Initialization error of custom login module

    code-monkey

      I have implemented a custom Login-Module for JBoss 6 which extends AbstractServerLoginModule. Unfortunately it fails to initialize after the first request on a protected page.

      This is the correpsonding section of my server.log:

       

       

      2014-03-25 15:14:08,159 DEBUG [org.apache.catalina.session.ManagerBase#processExpires] (ContainerBackgroundProcessor[StandardEngine[jboss.web]]) processExpires End expire sessions StandardManager processingTime 0 expired sessions: 0
      2014-03-25 15:14:12,260 TRACE [org.jboss.security.SecurityRolesAssociation#setSecurityRoles] (http-127.0.0.1-21000-1) setSecurityRoles Setting threadlocal:{}
      2014-03-25 15:14:12,262 DEBUG [org.apache.catalina.authenticator.AuthenticatorBase#invoke] (http-127.0.0.1-21000-1) invoke Security checking request GET /powerpanel/pages/login.xhtml
      2014-03-25 15:14:12,263 DEBUG [org.apache.catalina.realm.RealmBase#findSecurityConstraints] (http-127.0.0.1-21000-1) findSecurityConstraints   Checking constraint 'SecurityConstraint[powerpanel]' against GET /pages/login.xhtml --> true
      2014-03-25 15:14:12,263 DEBUG [org.apache.catalina.realm.RealmBase#findSecurityConstraints] (http-127.0.0.1-21000-1) findSecurityConstraints   Checking constraint 'SecurityConstraint[powerpanel]' against GET /pages/login.xhtml --> true
      2014-03-25 15:14:12,263 DEBUG [org.apache.catalina.authenticator.AuthenticatorBase#invoke] (http-127.0.0.1-21000-1) invoke  Calling hasUserDataPermission()
      2014-03-25 15:14:12,264 DEBUG [org.apache.catalina.realm.RealmBase#hasUserDataPermission] (http-127.0.0.1-21000-1) hasUserDataPermission   User data constraint has no restrictions
      2014-03-25 15:14:12,277 DEBUG [org.jboss.security.integration.JNDIBasedSecurityManagement#createSecurityDomainContext] (http-127.0.0.1-21000-1) createSecurityDomainContext Creating SDC for domain=i24-panel-ws-auth
      2014-03-25 15:14:12,278 TRACE [org.jboss.security.integration.JNDIBasedSecurityManagement#lookUpJNDI] (http-127.0.0.1-21000-1) lookUpJNDI Look up of JNDI for i24-panel-ws-auth/authorizationMgr failed with org.jboss.security.plugins.JaasSecurityManager cannot be cast to org.jboss.security.AuthenticationManager
      2014-03-25 15:14:12,279 TRACE [org.jboss.security.integration.JNDIBasedSecurityManagement#getAuthorizationManager] (http-127.0.0.1-21000-1) getAuthorizationManager Exception in getting authorization mgr: java.lang.NullPointerException
        at java.util.concurrent.ConcurrentHashMap.put(ConcurrentHashMap.java:881) [:1.6.0_35]
        at org.jboss.security.integration.JNDIBasedSecurityManagement.getAuthorizationManager(JNDIBasedSecurityManagement.java:172) [:6.0.0.Final]
        at org.jboss.security.plugins.JBossSecurityContext.getAuthorizationManager(JBossSecurityContext.java:268) [:6.0.0.Final]
        at org.jboss.security.plugins.javaee.WebAuthorizationHelper.hasUserDataPermission(WebAuthorizationHelper.java:183) [:3.0.0.CR2]
        at org.jboss.web.tomcat.security.JBossWebRealm.hasUserDataPermission(JBossWebRealm.java:668) [:6.0.0.Final]
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:529) [:6.0.0.Final]
        at org.jboss.modcluster.catalina.CatalinaContext$RequestListenerValve.event(CatalinaContext.java:285) [:1.1.0.Final]
        at org.jboss.modcluster.catalina.CatalinaContext$RequestListenerValve.invoke(CatalinaContext.java:261) [:1.1.0.Final]
        at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:88) [:6.0.0.Final]
        at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:100) [:6.0.0.Final]
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) [:6.0.0.Final]
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [:6.0.0.Final]
        at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158) [:6.0.0.Final]
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [:6.0.0.Final]
        at org.jboss.web.tomcat.service.request.ActiveRequestResponseCacheValve.invoke(ActiveRequestResponseCacheValve.java:53) [:6.0.0.Final]
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:362) [:6.0.0.Final]
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [:6.0.0.Final]
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:654) [:6.0.0.Final]
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:951) [:6.0.0.Final]
        at java.lang.Thread.run(Thread.java:662) [:1.6.0_35]
      
      
      2014-03-25 15:14:12,285 TRACE [org.jboss.security.SecurityRolesAssociation#setSecurityRoles] (http-127.0.0.1-21000-1) setSecurityRoles Setting threadlocal:null
      2014-03-25 15:14:12,286 ERROR [org.apache.catalina.connector.CoyoteAdapter#service] (http-127.0.0.1-21000-1) service An exception or error occurred in the container during the request processing: java.lang.IllegalStateException: Authorization Manager is null
        at org.jboss.security.plugins.javaee.WebAuthorizationHelper.hasUserDataPermission(WebAuthorizationHelper.java:185) [:3.0.0.CR2]
        at org.jboss.web.tomcat.security.JBossWebRealm.hasUserDataPermission(JBossWebRealm.java:668) [:6.0.0.Final]
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:529) [:6.0.0.Final]
        at org.jboss.modcluster.catalina.CatalinaContext$RequestListenerValve.event(CatalinaContext.java:285) [:1.1.0.Final]
        at org.jboss.modcluster.catalina.CatalinaContext$RequestListenerValve.invoke(CatalinaContext.java:261) [:1.1.0.Final]
        at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:88) [:6.0.0.Final]
        at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:100) [:6.0.0.Final]
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) [:6.0.0.Final]
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [:6.0.0.Final]
        at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158) [:6.0.0.Final]
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [:6.0.0.Final]
        at org.jboss.web.tomcat.service.request.ActiveRequestResponseCacheValve.invoke(ActiveRequestResponseCacheValve.java:53) [:6.0.0.Final]
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:362) [:6.0.0.Final]
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [:6.0.0.Final]
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:654) [:6.0.0.Final]
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:951) [:6.0.0.Final]
        at java.lang.Thread.run(Thread.java:662) [:1.6.0_35]
      

       

      Obviously the AuthorizationManager cannot be created from the JaasSecurityManager but I'm not getting the reason for this. I thought this would be handled transparently by the SX framework as long as I provide a proper extension/implementation of one of the existing JBoss Login-Modules.

      Has anybody tried to extend AbstractServerLoginModule with success or had a similar problem? Also, any clarification of the issue would be highly appreciated!

      Here is how I set up the Login-Module:

      The implementing class is part of the web-application which I'm trying to secure

      package de.ig.ui.kundenpanel.authorization;
      
      
      import java.io.IOException;
      import java.security.Principal;
      import java.security.acl.Group;
      import java.util.Enumeration;
      import java.util.HashSet;
      import java.util.List;
      import java.util.Map;
      import java.util.Set;
      
      
      import javax.security.auth.Subject;
      import javax.security.auth.callback.Callback;
      import javax.security.auth.callback.CallbackHandler;
      import javax.security.auth.callback.NameCallback;
      import javax.security.auth.callback.PasswordCallback;
      import javax.security.auth.callback.UnsupportedCallbackException;
      import javax.security.auth.login.LoginException;
      
      
      import org.jboss.security.SimpleGroup;
      import org.jboss.security.SimplePrincipal;
      import org.jboss.security.auth.spi.AbstractServerLoginModule;
      
      
      import de.ig.common.bo.i24.authentication.AuthLoginRequest;
      import de.ig.common.bo.i24.authentication.AuthLoginResponse;
      import de.ig.common.bo.userlogin.UserLogin;
      import de.ig.common.exception.SoapClientException;
      import de.ig.common.exception.TechnicalException;
      import de.ig.common.tool.communication.IgServiceLocator;
      import de.ig.common.tool.communication.SessionKeyAuthParams;
      import de.ig.common.tool.communication.rmi.delegator.I24AuthenticationClientRMILocal;
      import de.ig.common.tool.log.TransactionItem;
      import de.ig.ui.kundenpanel.utility.TransactionItemFactory;
      
      
      /**
       * Custom login module that authenticates against I24 Panel Authentication
       * Web-Service.
       * 
       * @author mthielsch
       * 
       */
      public class I24PanelLoginModule extends AbstractServerLoginModule {
      
      
        private static final String I24_AUTHENTICATION_CLIENT = "i24_authentication_client";
      
      
        /**
        * The login identity
        */
        private UserContext identity;
      
      
        /**
        * The user roles
        */
        private Set<Principal> principalRoles = new HashSet<Principal>();
      
      
        // user credentials
        private String userName;
        private String password;
        private String callerIpAddress;
      
      
        private I24AuthenticationClientRMILocal rmiAuthenticationClientDelegator = (I24AuthenticationClientRMILocal) IgServiceLocator
        .getInstance().getService(IgServiceLocator.I24_AUTHENTICATION_SERVICE_LOCAL);
      
      
        public I24PanelLoginModule() {
        super();
        }
      
      
        @SuppressWarnings("rawtypes")
        @Override
        public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {
        super.initialize(subject, callbackHandler, sharedState, options);
        }
      
      
        @Override
        public boolean login() throws LoginException {
        log.trace("login");
        loginOk = false;
        try {
        // If useFirstPass is true, look for the shared password
        if (useFirstPass == true) {
        initCredentialsFromSharedState();
        } else {
        // Use credentials from callback handler
        initCredentialsFromCallbackHandler();
        }
      
      
        if (userName != null && password != null) {
        AuthLoginRequest authLoginRequest = new AuthLoginRequest();
        authLoginRequest.setUsername(userName);
        authLoginRequest.setPassword(password);
        authLoginRequest.setIp(callerIpAddress);
        TransactionItem track = TransactionItemFactory.getTransactionItem();
        SessionKeyAuthParams authParams = new SessionKeyAuthParams(null);
        authParams.setTransactionItem(track);
        AuthLoginResponse authLoginResponse = rmiAuthenticationClientDelegator.login(track, authParams,
        authLoginRequest);
      
      
        this.identity = createIdentity(userName, password, authLoginResponse.getPermissions(),
        authLoginResponse.getAuthKey(), authLoginResponse.getCustomer(), callerIpAddress);
        for (String role : authLoginResponse.getPermissions()) {
        principalRoles.add(new SimplePrincipal(role));
        }
        loginOk = true;
        return true;
        }
        // Else, fall through and perform the login
        } catch (UnsupportedCallbackException uce) {
        log.error("CallbackHandler failed to provide login credentials", uce);
        throw new LoginException("CallbackHandler failed to provide login credentials");
        } catch (SoapClientException sce) {
        log.error("Calling I24 Authentication Web-Service failed", sce);
        throw new LoginException("Calling I24 Authentication Web-Service failed");
        } catch (TechnicalException te) {
        log.error("Calling I24 Authentication Web-Service failed", te);
        throw new LoginException("Calling I24 Authentication Web-Service failed");
        } catch (IOException ioe) {
        log.error("Got IOException during login process", ioe);
        throw new LoginException("Login failed while reading provided credentials");
        }
        return false;
        }
      
      
        private void initCredentialsFromCallbackHandler() throws IOException, UnsupportedCallbackException {
        Callback[] callbacks = new Callback[3];
        callbacks[0] = new NameCallback("username");
        callbacks[1] = new PasswordCallback("password", false);
        callbacks[2] = new IPAddressCallback();
        callbackHandler.handle(callbacks);
        userName = ((NameCallback) callbacks[0]).getName();
        password = new String(((PasswordCallback) callbacks[1]).getPassword());
        callerIpAddress = ((IPAddressCallback) callbacks[2]).getIpAddress();
        }
      
      
        private void initCredentialsFromSharedState() {
        Object userNameObject = sharedState.get("javax.security.auth.login.name");
        Object passwordObject = sharedState.get("javax.security.auth.login.password");
        userName = extractUserName(userNameObject);
        password = extractPassword(passwordObject);
        }
      
      
        private String extractUserName(Object userNameObject) {
        if (userNameObject instanceof Principal) {
        return ((Principal) userNameObject).getName();
        } else if (userNameObject != null) {
        return userNameObject.toString();
        }
        return null;
        }
      
      
        private String extractPassword(Object passwordObject) {
        if (passwordObject instanceof char[])
        return new String((char[]) passwordObject);
        else if (passwordObject != null) {
        return passwordObject.toString();
        }
        return null;
        }
      
      
        private UserContext createIdentity(String userName, String password, List<String> roles, String sessionToken,
        String customerId, String ipAddress) throws LoginException {
        try {
        UserContext identity = new UserContext();
        identity.setPrincipalName(userName);
        identity.setSessionToken(sessionToken);
        identity.setRemoteAddr(ipAddress);
        UserLogin userLogin = new UserLogin();
        userLogin.setUserName(userName);
        userLogin.setPassword(password);
        userLogin.setRoles(roles);
        userLogin.setCustomerId(customerId);
        identity.setUserLogin(userLogin);
      
      
        return identity;
        } catch (Exception e) {
        log.debug("Failed to create identity", e);
        throw new LoginException("Failed to create principal: " + e.getMessage());
        }
        }
      
      
        @Override
        public boolean commit() throws LoginException {
        if (loginOk == false)
        return false;
        // Add subject principals
        Set<Principal> principals = subject.getPrincipals();
        if (!principals.contains(identity)) {
        principals.add(identity);
        }
        Group[] roleSets = getRoleSets();
        for (int g = 0; g < roleSets.length; g++) {
        Group group = roleSets[g];
        String name = group.getName();
        Group subjectGroup = createGroup(name, principals);
        // Copy the group members to the Subject group
        Enumeration<? extends Principal> members = group.members();
        while (members.hasMoreElements()) {
        Principal role = (Principal) members.nextElement();
        subjectGroup.addMember(role);
        }
        }
      
      
        return true;
        }
      
      
        @Override
        protected Principal getIdentity() {
        return identity;
        }
      
      
        @Override
        public boolean logout() throws LoginException {
        subject.getPrincipals().remove(this.identity);
        this.identity = null;
        this.userName = null;
        this.password = null;
        this.callerIpAddress = null;
        this.principalRoles = null;
        return true;
        }
      
      
        @Override
        protected Group[] getRoleSets() throws LoginException {
        Group roles = new SimpleGroup("Roles");
        for (Principal role : principalRoles) {
        roles.addMember(role);
        }
        return new Group[] { roles };
        }
      
      
      }
      

       

      Definition of the module within /server/default/conf/login-config.xml is as follows

      <application-policy name="i24-panel-ws-auth">

           <authentication>

                <login-module code="de.ig.ui.kundenpanel.authorization.I24PanelLoginModule" flag="required"> </login-module> 

           </authentication>

      </application-policy>

      Which is then referenced in the jboss-web.xml within the WAR

      <jboss-web>

           <security-domain>i24-panel-ws-auth</security-domain>

           <context-root>myContextRoot</context-root>

      </jboss-web>

      And finally the security configuration within the web.xml:

      <welcome-file-list>
         <welcome-file>/pages/login.xhtml</welcome-file>
      </welcome-file-list>
      
      <login-config>
         <auth-method>FORM</auth-method>
         <realm-name>i24-panel-ws-auth</realm-name>
         <form-login-config>
         <form-login-page>/pages/login.xhtml</form-login-page>
         <form-error-page>/pages/login.xhtml</form-error-page>
         </form-login-config>
      </login-config>
      <security-role>
         <role-name>AuthAll</role-name>
      </security-role>
      <security-constraint>
         <web-resource-collection>
         <web-resource-name>myContextRoot</web-resource-name>
         <url-pattern>/pages/*</url-pattern>
        <http-method>GET</http-method>
        <http-method>POST</http-method>
        </web-resource-collection>
        <auth-constraint>
        <role-name>AuthAll</role-name>
        </auth-constraint>
      </security-constraint>