4 Replies Latest reply on Mar 1, 2007 6:05 AM by kristof.devos

    Help ... flushAuthenticationCache don't work

    venika

      Hallo,

      I have a problem with JAAS-Security in my application. I need to change the user roles on the fly in my application. So I try to call the "flushAuthenticationCache" ? method in my application, but this call has no effect. In other JBoss topics I have found that after this call the JASS-Security should call my custom LoginModule again and the subject should be initialized once more. I have tried to control this with my debugger, but my custom LoginModule is called once, only at the login.

      The call of the "flushAuthenticationCache"-method don't remove the principal from the TimedCache.

      Can anybody say me what is wrong in my application?

      I use the JBoss Application Server 4.0.5 GA (at home) and 4.0.2 (at work). I have written a small prototype of my application. The prototype consists of two servlets. One servlet is an admin Servlet and second is a user servlet. In user Servlet I want to change the user role to admin. I am using CustomPrincipal and CustomLoginModule to authenticate the user.

      Hier is my source:

      a) web.xml

      b) jboss-web.xml

      c) CustomLoginModule.java

      d) CustomPrincipal.java

      e) SecureServlet.java

      f) AdminSecureServlet.java

      g) login-config.xml


      web.xml

      <?xml version="1.0" encoding="UTF-8"?>
      <web-app id="WebApp_ID" version="2.4"
      xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
      http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
      
      <display-name>Refresh</display-name>
       <servlet>
       <description>Servlet ohne Zugriffsbeschraenkung</description>
       <display-name>UnsecureServlet</display-name>
       <servlet-name>UnsecureServlet</servlet-name>
       <servlet-class>de.venia.servlets.UnsecureServlet</servlet-class>
       </servlet>
       <servlet>
       <description>Zugriffsgeschuetzter Servlet</description>
       <display-name>SecureServlet</display-name>
       <servlet-name>SecureServlet</servlet-name>
       <servlet-class>de.venia.servlets.SecureServlet</servlet-class>
       </servlet>
       <servlet>
       <description>Admin Servlet</description>
       <display-name>AdminSecureServlet</display-name>
       <servlet-name>AdminSecureServlet</servlet-name>
       <servlet-class>de.venia.servlets.AdminSecureServlet</servlet-class>
       </servlet>
       <servlet-mapping>
       <servlet-name>UnsecureServlet</servlet-name>
       <url-pattern>/UnsecureServlet/*</url-pattern>
       </servlet-mapping>
       <servlet-mapping>
       <servlet-name>SecureServlet</servlet-name>
       <url-pattern>/SecureServlet/*</url-pattern>
       </servlet-mapping>
       <servlet-mapping>
       <servlet-name>AdminSecureServlet</servlet-name>
       <url-pattern>/AdminServlet/*</url-pattern>
       </servlet-mapping>
       <security-constraint>
       <web-resource-collection>
       <web-resource-name>First</web-resource-name>
       <url-pattern>/SecureServlet/*</url-pattern>
       <http-method>POST</http-method>
       <http-method>GET</http-method>
       </web-resource-collection>
       <auth-constraint>
       <role-name>user</role-name>
       <role-name>admin</role-name>
       </auth-constraint>
       </security-constraint>
       <security-constraint>
       <web-resource-collection>
       <web-resource-name>Admin</web-resource-name>
       <url-pattern>/AdminServlet/*</url-pattern>
       <http-method>POST</http-method>
       <http-method>GET</http-method>
       </web-resource-collection>
       <auth-constraint>
       <role-name>admin</role-name>
       </auth-constraint>
       </security-constraint>
       <login-config>
       <auth-method>FORM</auth-method>
       <realm-name>ReportingServcieJAAS</realm-name>
       <form-login-config>
       <form-login-page>/jsp/login.jsp</form-login-page>
       <form-error-page>/jsp/error.jsp</form-error-page>
       </form-login-config>
       </login-config>
       <security-role>
       <role-name>user</role-name>
       </security-role>
       <security-role>
       <role-name>admin</role-name>
       </security-role>
       <welcome-file-list>
       <welcome-file>index.html</welcome-file>
       </welcome-file-list>
      </web-app>


      Jboss-web.xml

      <?xml version="1.0" encoding="UTF-8" ?>
      <jboss-web>
       <security-domain>java:/jaas/ReportingServcieJAAS</security-domain>
      </jboss-web>


      CustomLoginModule

      package de.venia.login;
      
      import java.security.Principal;
      import java.security.acl.Group;
      import java.util.Map;
      import javax.security.auth.Subject;
      import javax.security.auth.callback.CallbackHandler;
      import javax.security.auth.login.LoginException;
      import javax.security.jacc.PolicyContext;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpSession;
      import org.jboss.security.SimpleGroup;
      import org.jboss.security.SimplePrincipal;
      import org.jboss.security.auth.spi.AbstractServerLoginModule;
      
      public class CustomLoginModule extends AbstractServerLoginModule {
      
       public void initialize( Subject arg0, CallbackHandler arg1, Map arg2, Map arg3) {
       this.subject = arg0;
       this.callbackHandler = arg1;
       this.sharedState = arg2;
       this.options = arg3;
       }
      
       public boolean login() throws LoginException {
       this.loginOk = true;
       return true;
       }
      
       public boolean abort() throws LoginException {
       return true;
       }
      
       public boolean commit() throws LoginException {
       String userRole = null;
       try {
       HttpServletRequest request =
      
       (HttpServletRequest)
      
       PolicyContext.getContext("javax.servlet.http.HttpServletRequest");
       if( request != null) {
       HttpSession session = request.getSession();
       Object obj = session.getAttribute("newRole");
       if( obj != null) userRole = (String) obj;
       }
       }catch( Exception e) {
       }
      
       if( userRole == null) userRole = "user";
      
       SimpleGroup gr = new SimpleGroup("CallerPrincipal");
       SimpleGroup gr2 = new SimpleGroup("Roles");
       gr.addMember( new CustomPrincipal("Benjamin"));
       gr2.addMember( new SimplePrincipal( userRole));
       this.subject.getPrincipals().add(gr);
       this.subject.getPrincipals().add(gr2);
      
       return true;
       }
      
       public boolean logout() throws LoginException {
       this.subject.getPrincipals().clear();
       this.subject.getPublicCredentials().clear();
       this.subject.getPrivateCredentials().clear();
      
       return true;
       }
      
       protected Principal getIdentity() {
       return null;
       }
      
       protected Group[] getRoleSets() throws LoginException {
       return null;
       }
      }


      CustomPrincipal

      package de.venia.login;
      
      import java.security.Principal;
      import java.sql.Timestamp;
      
      public class CustomPrincipal implements Principal {
      
       private String name = null;
       private Timestamp time = null;
      
       public CustomPrincipal( String nameM) {
       this.name = nameM;
       time = new Timestamp( System.currentTimeMillis());
       }
      
       public String getName() {
       return this.getTimedName();
       }
      
       private String getTimedName() {
       return this.name + "_" + this.time.toString();
       }
      
       public int hashCode() {
       int hash = this.getTimedName().hashCode();
       return hash;
       }
      
       public boolean equals( Object objM) {
       if( objM == null || !(objM instanceof CustomPrincipal)) {
       return false;
       }
       CustomPrincipal compar = (CustomPrincipal) objM;
       return ( this.getTimedName()).equals( compar.getTimedName());
       }
      }


      SecureServlet

      package de.venia.servlets;
      
      import java.io.IOException;
      import java.io.PrintWriter;
      import java.security.Principal;
      import javax.management.MBeanServer;
      import javax.management.MBeanServerFactory;
      import javax.management.ObjectName;
      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import de.venia.login.CustomPrincipal;
      
      public class SecureServlet extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {
      
       private static final long serialVersionUID = 1L;
      
       public SecureServlet() {
       super();
       }
      
       protected void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
       doPost( request, response);
       }
      
       protected void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
      
       PrintWriter outputter = response.getWriter();
       outputter.println("I'm protected servlet, role - user");
       outputter.println("<br />");
       outputter.println("SessionID:" + request.getSession().getId());
       outputter.println("<br />");
      
       Object obj = request.getUserPrincipal();
       if( obj != null) outputter.println("User:" + ((CustomPrincipal)obj).getName());
      
       //Flush principal
       Object flushObj = request.getParameter("flush");
       Object roleObj = request.getParameter("role");
       if( flushObj != null && ((String) flushObj).equalsIgnoreCase("true"))
       if( roleObj != null) {
       request.getSession().setAttribute("newRole", (String) roleObj);
       try {
       String domain = "ReportingServcieJAAS";
       //Principal principal = new SimplePrincipal(((CustomPrincipal)obj).getName());
       Principal principal = (Principal) request.getUserPrincipal();
       ObjectName jaasMgr = new ObjectName( "jboss.security:service=JaasSecurityManager");
       Object[] params = { domain, principal };
       String[] signature = { "java.lang.String", Principal.class.getName() };
       MBeanServer server = (MBeanServer) MBeanServerFactory.findMBeanServer(null).get(0);
       server.invoke( jaasMgr, "flushAuthenticationCache", params, signature);
       } catch (Exception e) {
       e.printStackTrace(outputter);
       }
       }
      
       //Flush all
       Object flushAllObj = request.getParameter("flushAll");
       if( flushAllObj != null && ((String) flushAllObj).equalsIgnoreCase("true")) {
       try {
       String domain = "ReportingServcieJAAS";
       ObjectName jaasMgr = new ObjectName( "jboss.security:service=JaasSecurityManager");
       Object[] params = { domain };
       String[] signature = { "java.lang.String"};
       MBeanServer server = (MBeanServer) MBeanServerFactory.findMBeanServer(null).get(0);
       server.invoke( jaasMgr, "flushAuthenticationCache", params, signature);
       } catch (Exception e) {
       e.printStackTrace(outputter);
       }
       }
       }
      }


      AdminSecureServlet

      package de.venia.servlets;
      
      import java.io.IOException;
      import java.io.PrintWriter;
      import javax.servlet.ServletException;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      
      public class AdminSecureServlet extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {
      
       private static final long serialVersionUID = 1L;
      
       public AdminSecureServlet() {
       super();
       }
      
       protected void doGet(HttpServletRequest request, HttpServletResponse response)
       throws ServletException, IOException {
       doPost( request, response);
       }
      
       protected void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
       PrintWriter outputter = response.getWriter();
       outputter.println("I'm protected servlet, role - admin");
       outputter.println("<br />");
       }
      }


      Login-config.xml

      <application-policy name="ReportingServcieJAAS">
       <authentication>
       <login-module code="de.venia.login.CustomLoginModule" flag="required">
       </login-module>
       </authentication>
       </application-policy>




      Thanks a lot for your help ;-)))





        • 1. Re: Help ... flushAuthenticationCache don't work
          kristof.devos

          sorry, this won't help you but I'm having the same problem. I can put the new credential in the securityassociation but new time the loginmodule is called still the old password in returned from the getCredential method.

          I even do a login logout and still the previous password is used

          In this case I have the problem with a change password call

          • 2. Re: Help ... flushAuthenticationCache don't work

            try this

            in your

            <jboss_home>/server/conf/jboss-service.xml
            try to modify cache params

            <mbean code="org.jboss.security.plugins.JaasSecurityManagerService"
             name="jboss.security:service=JaasSecurityManager">
             <!-- A flag which indicates whether the SecurityAssociation server mode
             is set on service creation. This is true by default since the
             SecurityAssociation should be thread local for multi-threaded server
             operation.
             -->
             <attribute name="ServerMode">true</attribute>
             <attribute name="SecurityManagerClassName">org.jboss.security.plugins.JaasSecurityManager</attribute>
             <attribute name="DefaultUnauthenticatedPrincipal">anonymous</attribute>
             <!-- DefaultCacheTimeout: Specifies the default timed cache policy timeout
             in seconds.
             If you want to disable caching of security credentials, set this to 0 to
             force authentication to occur every time. This has no affect if the
             AuthenticationCacheJndiName has been changed from the default value.
             -->
             <attribute name="DefaultCacheTimeout">0</attribute>
             <!-- DefaultCacheResolution: Specifies the default timed cache policy
             resolution in seconds. This controls the interval at which the cache
             current timestamp is updated and should be less than the DefaultCacheTimeout
             in order for the timeout to be meaningful. This has no affect if the
             AuthenticationCacheJndiName has been changed from the default value.
             -->
             <!-- <attribute name="DefaultCacheResolution">60</attribute> -->
             </mbean>



            Also in your jboss-web.xml define flushOnSessionInvalidation="true"
            <jboss-web>
             <security-domain flushOnSessionInvalidation="true" >java:jaas/eluminate</security-domain>
            </jboss-web>
            


            Let me know if it works

            Thanks
            Nipun

            • 3. Re: Help ... flushAuthenticationCache don't work
              ecoray

              Hi

              use your security-domain name as argument for the flushAuthenticationCache() operation. Tested with jboss-3.2.5
              Your security-domain name is : ReportingServcieJAAS
              in this case invoke : flushAuthenticationCache("ReportingServcieJAAS")

              1. start jmx-console and select
              jboss.security->service=JaasSecurityManager
              2. select OperationName : flushAuthenticationCache and
              insert "ReportingServcieJAAS" as argument.
              3. Invoke the operation

              Now your AuthenticationCache should be flushed.


              • 4. Re: Help ... flushAuthenticationCache don't work
                kristof.devos

                THX for the reply

                The problem is more complex, we do a password change and want the current session to use the new password for any EJB access call

                --> nipunbatra

                indeed this is a solution but we want to avoid an authorization call (remote in our case) for each EJB access, that's why we enable the caching

                --> ecoray

                We do this flush but the problem is when the flush is done and you do a logout the EJB destroy methods are called and because the cache is flushed the applic wants to reauthenticate for EJB access but he uses the password before the change and causes several attempts to login with the user which causes the user to block (if you login 3 times with different password our login module blocks the user)

                I tried the SecurityAssociaton.setCredential but at next login the old password is still ini the securityassociation object, so it seems more than one securityassociation object is stored in the cache