4 Replies Latest reply on Mar 20, 2007 5:21 AM by shane.bryzak

    Seam security with JAAS config

    pdpantages

      Hello Forum,

      seam 1.1.6.GA
      jboss-4.0.5.GA
      ajax4jsf-1.0.6
      Facelets

      I am trying out the new seam security.

      I want to use the JAAS security as described in sec. 12.2.5.1 of the ref manual.

      I would like to know if there is a working example anywhere I could look at.

      What I have tried is:

      We have our own policy & I have set the jaas-config-name accordingly.
      Note that I saw the bug report about the documentation and am using
      "jaas-config-name" instead of "jaasConfigName".

      In my components.xml I have the following:

       <security:identity jaas-config-name="centina"/>
      


      My login action authenticates like so:
      ....
      identity.setUsername(j_username);
      identity.setPassword(j_password);
      log.debug( "LoginAction: Identity Login result " + identity.login() ) ;
      ....
      


      I removed the login-config an security-constraint tags from my web.xml
      My web.xml now contains no JAAS security stuff in it.

      When I give it a try, I find that the initial authentication works, calling our
      authenticator as expected, & the identity.login() returns "success".

      But the next call I make fails (see exception, below). This seems to
      be due to the authentication prinicplal not being saved anywhere? The stack trace
      shows a re-authentication attempt.

      I looked at the source for JBossSecurityMgrRealm etc., to see how
      "they did it" and noticed the following is executed if the
      authentication passes: ( line 494 )
       ...
       SecurityAssociationActions.setPrincipalInfo(principal, certs,subject);
       . ..
      


      The Seam Identity object does not do this (explicity anyway) as far as
      I can tell.

      I tried to call SecurityAssociationActions.setPrincipalInfo() myself
      after my authentication, in my login action, but can't do so as the
      class is not public. I suppose that this really means I shouldn't try to
      do it this way :)

      I get the following failure. This exception is thrown because the
      username passed in is null. The username is normally set by
      UsernamePasswordLoginModule.getUsernameAndPassword() via callback
      functions.

      Anyway, my exception is:
      javax.security.auth.login.LoginException: No username specified
       at centina.sa.server.security.SecurityManagerLoginModule.createIdentity(SecurityManagerLoginModule.java:59)
       at org.jboss.security.auth.spi.UsernamePasswordLoginModule.login(UsernamePasswordLoginModule.java:194)
       at centina.sa.server.security.SecurityManagerLoginModule.login(SecurityManagerLoginModule.java:126)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at javax.security.auth.login.LoginContext.invoke(LoginContext.java:769)
       at javax.security.auth.login.LoginContext.access$000(LoginContext.java:186)
       at javax.security.auth.login.LoginContext$4.run(LoginContext.java:683)
       at java.security.AccessController.doPrivileged(Native Method)
       at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680)
       at javax.security.auth.login.LoginContext.login(LoginContext.java:579)
       at org.jboss.security.plugins.JaasSecurityManager.defaultLogin(JaasSecurityManager.java:601)
       at org.jboss.security.plugins.JaasSecurityManager.authenticate(JaasSecurityManager.java:535)
       at org.jboss.security.plugins.JaasSecurityManager.isValid(JaasSecurityManager.java:344)
       at org.jboss.aspects.security.AuthenticationInterceptor.authenticate(AuthenticationInterceptor.java:123)
       at org.jboss.aspects.security.AuthenticationInterceptor.invoke(AuthenticationInterceptor.java:66)
       at org.jboss.ejb3.security.Ejb3AuthenticationInterceptor.invoke(Ejb3AuthenticationInterceptor.java:102)
       at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       at org.jboss.ejb3.ENCPropagationInterceptor.invoke(ENCPropagationInterceptor.java:47)
       at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       at org.jboss.ejb3.asynchronous.AsynchronousInterceptor.invoke(AsynchronousInterceptor.java:106)
       at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       at org.jboss.ejb3.stateless.StatelessContainer.localInvoke(StatelessContainer.java:211)
       at org.jboss.ejb3.stateless.StatelessLocalProxy.invoke(StatelessLocalProxy.java:79)
       at $Proxy1105.getUser(Unknown Source)
       .....
      


      Here is the Thread.dumpStack() of the successful authentication by the Identity.login() method:
      java.lang.Exception: Stack trace
       at java.lang.Thread.dumpStack(Thread.java:1158)
       at centina.sa.server.security.SecurityManager.completeLogin(SecurityManager.java:507)
       at centina.sa.server.security.SecurityManagerLoginModule.commit(SecurityManagerLoginModule.java:180)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at javax.security.auth.login.LoginContext.invoke(LoginContext.java:769)
       at javax.security.auth.login.LoginContext.access$000(LoginContext.java:186)
       at javax.security.auth.login.LoginContext$4.run(LoginContext.java:683)
       at java.security.AccessController.doPrivileged(Native Method)
       at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680)
       at javax.security.auth.login.LoginContext.login(LoginContext.java:580)
       at org.jboss.seam.security.Identity.authenticate(Identity.java:206)
       at org.jboss.seam.security.Identity.authenticate(Identity.java:199)
       at org.jboss.seam.security.Identity.login(Identity.java:184)
       at centina.sa.client.session.LoginAction.login(LoginAction.java:158)
       .....
      



      Any ideas (esp. an example) would be much appreciated.

      Thanks, PdP

        • 1. Re: Seam security with JAAS config
          shane.bryzak

          Seam Security only uses JAAS for authentication, not for authorization. I'm guessing that your action is protected with some container security mechanism, rather than the authorization features provided by Seam?

          • 2. Re: Seam security with JAAS config
            pdpantages

            Yes, you are correct; there is a mechanism protecting the calls. Up until now, I
            had been using the FORM method to authenticate with a login
            servlet. Once authenticated, this authorization mechanism works properly.

            I wanted to add and use the Seam Identity to do role-based page-level
            authorzation, and for conditional rendering in my facelets, while
            keeping the old authorization mechanism for methods.

            I though that the JAAS authentication would behave the same way, if I specified
            a jass-config-name in components.xml.

            I.e., like the call I see in FormAuthenticator:

             ...
             principal = context.getRealm().authenticate(username,password);
            


            It doesn't appear that the Identity authenticates the way
            FormAuthenticator did. I guess this is design intent.

            Since it doesn't, I though I could make this call myself, in an
            "authenticate-method", something like:
             public class Authenticator {
             public boolean authenticate() {
             ....
             Realm realm = ???
             p = realm.authenticate(identity.getUsername(),identity.getPassword());
             ...
             return true;
            }
            


            Then, if it was OK, I would populate the identity with the user's roles return true.

            ....But I can't figure out how the get ahold of the/a "Realm" instance. I see that the
            FormAuthenticator gets it from the context, which comes from the request.

            Is this workable, or am I missing something obvious....? I am a bit of
            a novice with JAAS & have to admit it is a bit confusing at times.


            A dumpstack for My old FORM method authentication. ( I looked at these sources
            to see how a successful authentication is/was done. )

            at java.lang.Thread.dumpStack(Thread.java:1158)
            at centina.sa.server.security.SecurityManager.completeLogin(SecurityManager.java:507)
            at centina.sa.server.security.SecurityManagerLoginModule.commit(SecurityManagerLoginModule.java:181)
            at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
            at java.lang.reflect.Method.invoke(Method.java:585)
            at javax.security.auth.login.LoginContext.invoke(LoginContext.java:769)
            at javax.security.auth.login.LoginContext.access$000(LoginContext.java:186)
            at javax.security.auth.login.LoginContext$4.run(LoginContext.java:683)
            at java.security.AccessController.doPrivileged(Native Method)
            at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680)
            at javax.security.auth.login.LoginContext.login(LoginContext.java:580) Above called at (579)
            at org.jboss.security.plugins.JaasSecurityManager.defaultLogin(JaasSecurityManager.java:601)
            at org.jboss.security.plugins.JaasSecurityManager.authenticate(JaasSecurityManager.java:535)
            at org.jboss.security.plugins.JaasSecurityManager.isValid(JaasSecurityManager.java:344)
            at org.jboss.web.tomcat.security.JBossSecurityMgrRealm.authenticate(JBossSecurityMgrRealm.java:491)
            at org.apache.catalina.authenticator.FormAuthenticator.authenticate(FormAuthenticator.java:257)
            at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:416)
            at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:74)
            at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
            at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
            at org.jboss.web.tomcat.tc5.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:156)
            at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
            at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
            at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
            at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:664)
            at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
            at org.apache.tomcat.util.net.MasterSlaveWorkerThread.run(MasterSlaveWorkerThread.java:112)
            at java.lang.Thread.run(Thread.java:595)
            



            • 3. Re: Seam security with JAAS config

              I am having exactly the same problems in that I am porting a Seam application that was working with JAAS FORM authentication to use the new Seam security code:

              Seam Security only uses JAAS for authentication, not for authorization. I'm guessing that your action is protected with some container security mechanism, rather than the authorization features provided by Seam?

              Is it possible to get Seam Security to work with existing JAAS components for authorization as well? (Is this even planned?)

              Let me explain...

              For security reasons I have explicitly secured ALL my EJBs with container security annotations. This is because they may be invoked from sources other than just the seam web interface (e.g. web services, remote mbean connections, etc).

              To do this, I mark all my business logic with annotations like:
              @Stateless
              @SecurityDomain("myapp")
              @RolesAllowed({"AppUser","AppSystem","AppAdmin"})


              Previously, I was using the standard Tomcat JAAS FORM authentication support (using <security-constraint> and <login-config> in web.xml), which I believe was responsible for injecting the currently authenticated user into the session, so when my authenticated Seam session made calls on EJBs, everything "just worked". In fact, I was even able to get the current logged-in JAAS user from my EJB code by calling SessionContext.getCallerPrincipal().

              Since I am now longer using Tomcat to do this, is it possible to get Seam to inject the JAAS principal into the session context so authenticated calls to EJB methods still work?

              I do not know enough about the internal workings of this stuff, but would it not be the responsibility of the SeamListener to inject the JAAS context accordingly?

              Thanks, Scott

              • 4. Re: Seam security with JAAS config
                shane.bryzak

                We've got a number of outstanding JIRA issues to address this, see the following container task for details:

                http://jira.jboss.com/jira/browse/SECURITY-38