7 Replies Latest reply on Jul 23, 2004 7:58 PM by eweber

    With Scott Stark's example, still can't use request.isUserIn

    eweber

      Hello, I am building Struts apps on 3.2.4.

      I have configured login-config.xml to query my own database schema for usera and roles during authentication, and that part is working.

      But propagation of Subjects to the web container seems to be the problem I cannot solve.

      To put it simply, I am noticing a difference between using these two methods of web-app authentication:

      If I use a form with the action parameter set to "j_security_check", the username parameter named "j_username" and the password parameter named "j_password", everything works fine. The user is authenticated against my database, and I can then invoke the "isUserInRole" method on the HttpServletRequest associated with each request, and it works.

      However, if I use my own form (tied to Struts action mapping rather than to "j_security_check"), and then process the login myself by instantiating a login context (same as that named in login-config.xml) with my own "passive" callback handler and then invoking login, the authentication works, but the propagation part doesn't seem to work -- the "isUserInRole" method no longer works.

      Setting the form action to "j_security_check" is not practical unless I am missing something. What if I want to validate the form input? I need to use my own form. How can I propagate the authenticated principal to the container environment so that I can use the methods such as "isUserInRole"?

      Thanks,
      Erik

        • 1. Re: With Scott Stark's example, still can't use request.isUs
          dev2gosoft

          j_security_check not only authenticates the user against a speciified realm in login-config.xml but also writes the necessary information (authenticated identity/principal) into the thread local storage (TLS) so that security context is propagated.

          If you do your custom login authentication, it is your responsibility to make sure that the above thing happens for each request (thread).

          There is a workaround ...but it is still a bit painful...but not very intricate.

          Java Application (thick clients do this in Jboss) by using the jboss supplied ClientLoginModule (that sets the SecurityAssociation (jboss specific) in TLS ).
          You can do this by logging in and out using the ClientLoginModule in a filter that is set to fire in for every secure request and authenticates...this will make sure every thread / request has the authenticated identity set in the TLS.

          Hope this helps...

          • 2. Re: With Scott Stark's example, still can't use request.isUs
            auckyboy

            Read this.

            http://www.jboss.org/index.html?module=bb&op=viewtopic&t=46370

            Great stuff by Scott. The guy is awesome.

            • 3. Re: With Scott Stark's example, still can't use request.isUs
              anil.saldhana

              Scott is the CTO and has implemented majority of the security in JBoss. You should meet him in person to know how technically sound he is. :-)

              • 4. Re: With Scott Stark's example, still can't use request.isUs
                stueccles

                Scott's howto is an excellent explanation in the use of JAAS and configuring JBoss Login Modules, far better than most other application servers.

                But it doesnt cover web-application security in much depth and certainly not what you are after. The need to do additional processing on a logon action or supply varied error cases arnt covered by the standard authenticators (FORM,BASIC,DIGEST,NONE) in jetty/tomcat.

                So you can either
                1) write your own FORM authenticator using org.apache.catalina.authenticator.FormAuthenticator as a base.
                note how the authenticator calls context.getRealm().authenticate(username, password);
                this uses org.jboss.web.tomcat.security.JBossSecurityMgrRealm
                which handles the JAAS logon based on the domain specified in jboss-web.xml
                where
                <jboss-web>
                <security-domain>java:/jaas/[domainname]</security-domain>
                </jboss-web>

                OR

                2) have your struts action make its authentication calls first as a "pre-auth" before redirecting a user to j_security_check?j_username=user&j_password=password. the security check will then log them in properly and redirect back to the originally requested page.

                BUT

                It is not possible to use the web-constraint type web authorsation and isUserInRole without going through an authenticator mainly because when you hit a constraint page (and getUserPrincipal and isUserInRole will only work on constraint pages) the authenticator tries to re-auth to the security realm using cached credentials where Jboss then looks up the subject (principal and roles) from its cache. The thing is, in tomcat at least, these credentials are cached using Session.setNote by the authenticator so could never be set by a Servlet like your struts action.

                Its a real pain , id be very glad to hear anyone elses ideas on this

                Stuart Eccles

                • 5. Re: With Scott Stark's example, still can't use request.isUs
                  stueccles

                  thinking about it i guess you could also write a filter that took your credentials out of the HttpSession (assuming your Action had put them there earlier)
                  and do something like {from JBossSecurityMgrRealm}

                  Context securityCtx = null;
                  try
                  {
                  InitialContext iniCtx = new InitialContext();
                  securityCtx = (Context) iniCtx.lookup("java:comp/env/security");


                  // Get the JBoss security manager from the ENC context
                  SubjectSecurityManager securityMgr = (SubjectSecurityManager) securityCtx.lookup("securityMgr");
                  principal = new SimplePrincipal(username);
                  char[] passwordChars = null;
                  if (credentials != null)
                  passwordChars = credentials.toCharArray();
                  if (securityMgr.isValid(principal, passwordChars))
                  {
                  SecurityAssociationActions.setPrincipalInfo(principal, passwordChars);
                  }

                  }

                  that might work. but im not sure if the filter is called before or after the security Authenticator valve on the web-application
                  ...................

                  • 6. Re: With Scott Stark's example, still can't use request.isUs
                    auckyboy

                    Stuart this is not a good solution.

                    As already mentioned in the howto..

                    Simply perform a login in the loginContext. This will provide the Subject with the right roles and can be loaded into the session.

                    To access third party system, you can use the ClientLoginModule.

                    • 7. Re: With Scott Stark's example, still can't use request.isUs
                      eweber

                      Guys, I really appreciate your ideas. Some if these suggestions, combined with some I got from Struts users, could lead me to something good. I will come back and post when I've had a chance to try some things.

                      Thanks,
                      Erik