فهرست منبع

Improve performance of JBoss container adapter (thanks to Sergio Bern�).

Ben Alex 21 سال پیش
والد
کامیت
ac3d3483b3
4فایلهای تغییر یافته به همراه147 افزوده شده و 14 حذف شده
  1. 93 9
      adapters/jboss/src/main/java/org/acegisecurity/adapters/jboss/JbossAcegiLoginModule.java
  2. 50 5
      doc/docbook/index.xml
  3. 1 0
      doc/xdocs/changes.xml
  4. 3 0
      project.xml

+ 93 - 9
adapters/jboss/src/main/java/org/acegisecurity/adapters/jboss/JbossAcegiLoginModule.java

@@ -25,6 +25,9 @@ import org.jboss.security.SimpleGroup;
 import org.jboss.security.SimplePrincipal;
 import org.jboss.security.SimplePrincipal;
 import org.jboss.security.auth.spi.AbstractServerLoginModule;
 import org.jboss.security.auth.spi.AbstractServerLoginModule;
 
 
+import org.springframework.beans.factory.access.*;
+import org.springframework.beans.factory.access.SingletonBeanFactoryLocator;
+
 import org.springframework.context.support.ClassPathXmlApplicationContext;
 import org.springframework.context.support.ClassPathXmlApplicationContext;
 
 
 import java.security.Principal;
 import java.security.Principal;
@@ -53,6 +56,7 @@ import javax.security.auth.login.LoginException;
  * </p>
  * </p>
  *
  *
  * @author Ben Alex
  * @author Ben Alex
+ * @author Sergio Berná
  * @version $Id$
  * @version $Id$
  */
  */
 public class JbossAcegiLoginModule extends AbstractServerLoginModule {
 public class JbossAcegiLoginModule extends AbstractServerLoginModule {
@@ -69,35 +73,99 @@ public class JbossAcegiLoginModule extends AbstractServerLoginModule {
         Map sharedState, Map options) {
         Map sharedState, Map options) {
         super.initialize(subject, callbackHandler, sharedState, options);
         super.initialize(subject, callbackHandler, sharedState, options);
 
 
+        if (super.log.isInfoEnabled()) {
+            super.log.info("initializing jboss login module");
+        }
+
         this.key = (String) options.get("key");
         this.key = (String) options.get("key");
 
 
         if ((key == null) || "".equals(key)) {
         if ((key == null) || "".equals(key)) {
             throw new IllegalArgumentException("key must be defined");
             throw new IllegalArgumentException("key must be defined");
         }
         }
 
 
+        String singletonId = (String) options.get("singletonId");
+
         String appContextLocation = (String) options.get("appContextLocation");
         String appContextLocation = (String) options.get("appContextLocation");
 
 
-        if ((appContextLocation == null) || "".equals(appContextLocation)) {
+        if ((((singletonId == null) || "".equals(singletonId))
+            && (appContextLocation == null)) || "".equals(appContextLocation)) {
             throw new IllegalArgumentException(
             throw new IllegalArgumentException(
                 "appContextLocation must be defined");
                 "appContextLocation must be defined");
         }
         }
 
 
+        String beanName = (String) options.get("authenticationManager");
+
         if (Thread.currentThread().getContextClassLoader().getResource(appContextLocation) == null) {
         if (Thread.currentThread().getContextClassLoader().getResource(appContextLocation) == null) {
+            if (super.log.isInfoEnabled()) {
+                super.log.info("cannot locate " + appContextLocation);
+            }
+
             throw new IllegalArgumentException("Cannot locate "
             throw new IllegalArgumentException("Cannot locate "
                 + appContextLocation);
                 + appContextLocation);
         }
         }
 
 
-        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(appContextLocation);
-        Map beans = ctx.getBeansOfType(AuthenticationManager.class, true, true);
+        ClassPathXmlApplicationContext ctx = null;
 
 
-        if (beans.size() == 0) {
-            throw new IllegalArgumentException(
-                "Bean context must contain at least one bean of type AuthenticationManager");
+        if ((singletonId == null) || "".equals(singletonId)) {
+            try {
+                ctx = new ClassPathXmlApplicationContext(appContextLocation);
+            } catch (Exception e) {
+                if (super.log.isInfoEnabled()) {
+                    super.log.info("error loading spring context "
+                        + appContextLocation + " " + e);
+                }
+
+                throw new IllegalArgumentException(
+                    "error loading spring context " + appContextLocation + " "
+                    + e);
+            }
+        } else {
+            if (super.log.isInfoEnabled()) {
+                super.log.debug("retrieving singleton instance " + singletonId);
+            }
+
+            BeanFactoryLocator bfl = SingletonBeanFactoryLocator.getInstance();
+            BeanFactoryReference bf = bfl.useBeanFactory(singletonId);
+            ctx = (ClassPathXmlApplicationContext) bf.getFactory();
+
+            if (ctx == null) {
+                if (super.log.isInfoEnabled()) {
+                    super.log.info("singleton " + beanName + " does not exists");
+                }
+
+                throw new IllegalArgumentException("singleton " + singletonId
+                    + " does not exists");
+            }
+        }
+
+        if ((beanName == null) || "".equals(beanName)) {
+            Map beans = null;
+
+            try {
+                beans = ctx.getBeansOfType(AuthenticationManager.class, true,
+                        true);
+            } catch (Exception e) {
+                if (super.log.isInfoEnabled()) {
+                    super.log.info("exception in getBeansOfType " + e);
+                }
+
+                throw new IllegalStateException(
+                    "spring error in get beans by class");
+            }
+
+            if (beans.size() == 0) {
+                throw new IllegalArgumentException(
+                    "Bean context must contain at least one bean of type AuthenticationManager");
+            }
+
+            beanName = (String) beans.keySet().iterator().next();
         }
         }
 
 
-        String beanName = (String) beans.keySet().iterator().next();
-        authenticationManager = (AuthenticationManager) beans.get(beanName);
-        super.log.info("Successfully started JbossSpringLoginModule");
+        authenticationManager = (AuthenticationManager) ctx.getBean(beanName);
+
+        if (super.log.isInfoEnabled()) {
+            super.log.info("Successfully started JbossSpringLoginModule");
+        }
     }
     }
 
 
     public boolean login() throws LoginException {
     public boolean login() throws LoginException {
@@ -121,13 +189,27 @@ public class JbossAcegiLoginModule extends AbstractServerLoginModule {
             password = "";
             password = "";
         }
         }
 
 
+        if (super.log.isDebugEnabled()) {
+            super.log.debug("checking identity");
+        }
+
         if (identity == null) {
         if (identity == null) {
+            super.log.debug("creating usernamepassword token");
+
             Authentication request = new UsernamePasswordAuthenticationToken(username,
             Authentication request = new UsernamePasswordAuthenticationToken(username,
                     password);
                     password);
             Authentication response = null;
             Authentication response = null;
 
 
             try {
             try {
+                if (super.log.isDebugEnabled()) {
+                    super.log.debug("attempting authentication");
+                }
+
                 response = authenticationManager.authenticate(request);
                 response = authenticationManager.authenticate(request);
+
+                if (super.log.isDebugEnabled()) {
+                    super.log.debug("authentication succeded");
+                }
             } catch (AuthenticationException failed) {
             } catch (AuthenticationException failed) {
                 if (super.log.isDebugEnabled()) {
                 if (super.log.isDebugEnabled()) {
                     super.log.debug("Bad password for username=" + username);
                     super.log.debug("Bad password for username=" + username);
@@ -137,6 +219,8 @@ public class JbossAcegiLoginModule extends AbstractServerLoginModule {
                     "Password Incorrect/Password Required");
                     "Password Incorrect/Password Required");
             }
             }
 
 
+            super.log.debug("user is logged. redirecting to jaas classes");
+
             identity = new PrincipalAcegiUserToken(this.key,
             identity = new PrincipalAcegiUserToken(this.key,
                     response.getPrincipal().toString(),
                     response.getPrincipal().toString(),
                     response.getCredentials().toString(),
                     response.getCredentials().toString(),

+ 50 - 5
doc/docbook/index.xml

@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
 <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
 "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
 <!--
 <!--
  * ========================================================================
  * ========================================================================
  * 
  * 
@@ -21,7 +20,6 @@
  * 
  * 
  * ========================================================================
  * ========================================================================
 -->
 -->
-
 <book>
 <book>
   <bookinfo>
   <bookinfo>
     <title>Acegi Security System for Spring</title>
     <title>Acegi Security System for Spring</title>
@@ -2479,14 +2477,17 @@ $CATALINA_HOME/bin/startup.sh</programlisting></para>
       <sect2 id="security-container-adapters-joss">
       <sect2 id="security-container-adapters-joss">
         <title>JBoss Installation</title>
         <title>JBoss Installation</title>
 
 
-        <para>The following was tested with JBoss 3.2.3. We automatically test
+        <para>The following was tested with JBoss 3.2.6. We automatically test
         the following directions using our container integration test system
         the following directions using our container integration test system
         and this version of JBoss.</para>
         and this version of JBoss.</para>
 
 
         <para><literal>$JBOSS_HOME</literal> refers to the root of your JBoss
         <para><literal>$JBOSS_HOME</literal> refers to the root of your JBoss
         installation.</para>
         installation.</para>
 
 
-        <para>Edit your
+        <para>There are two different ways of making spring context available
+        to the Jboss integration classes. </para>
+
+        <para>The first approach is by editing your
         <literal>$JBOSS_HOME/server/your_config/conf/login-config.xml</literal>
         <literal>$JBOSS_HOME/server/your_config/conf/login-config.xml</literal>
         file so that it contains a new entry under the
         file so that it contains a new entry under the
         <literal>&lt;Policy&gt;</literal> section:</para>
         <literal>&lt;Policy&gt;</literal> section:</para>
@@ -2504,7 +2505,51 @@ $CATALINA_HOME/bin/startup.sh</programlisting></para>
         <para>Copy <literal>acegisecurity.xml</literal> into
         <para>Copy <literal>acegisecurity.xml</literal> into
         <literal>$JBOSS_HOME/server/your_config/conf</literal>.</para>
         <literal>$JBOSS_HOME/server/your_config/conf</literal>.</para>
 
 
-        <para>Copy the following files into
+        <para>In this configuration <literal>acegisecurity.xml</literal>
+        contains the spring context definition including all the
+        authentication manager beans. You have to bear in mind though, that
+        <literal>SecurityContext</literal> is created and destroyed on each
+        login request, so the login operation might become costly.
+        Alternatively, the second approach is to use Spring singleton
+        capabilities through
+        <literal>org.springframework.beans.factory.access.SingletonBeanFactoryLocator</literal>.
+        The required configuration for this approach is:</para>
+
+        <para><programlisting>    &lt;application-policy name = "SpringPoweredRealm"&gt;
+       &lt;authentication&gt;
+          &lt;login-module code = "net.sf.acegisecurity.adapters.jboss.JbossSpringLoginModule"
+            flag = "required"&gt;
+            &lt;module-option name = "singletonId"&gt;springRealm&lt;/module-option&gt;
+            &lt;module-option name = "key"&gt;my_password&lt;/module-option&gt;
+            &lt;module-option name = "authenticationManager"&gt;authenticationManager&lt;/module-option&gt;
+         &lt;/login-module&gt;
+       &lt;/authentication&gt;
+    &lt;/application-policy&gt;</programlisting></para>
+
+        <para>In the above code fragment,
+        <literal>authenticationManager</literal> is a helper property that
+        defines the expected name of the
+        <literal>AuthenticationManager</literal> in case you have several
+        defined in the IoC container. The <literal>singletonId</literal>
+        property references a bean defined in a
+        <literal>beanRefFactory.xml</literal> file. This file needs to be
+        available from anywhere on the JBoss classpath, including
+        <literal>$JBOSS_HOME/server/your_config/conf</literal>. The
+        <literal>beanRefFactory.xml</literal> contains the following
+        declaration:</para>
+
+        <para><programlisting>&lt;beans&gt;
+  &lt;bean id="springRealm" singleton="true" lazy-init="true" class="org.springframework.context.support.ClassPathXmlApplicationContext"&gt;
+    &lt;constructor-arg&gt;
+      &lt;list&gt;
+        &lt;value&gt;acegisecurity.xml&lt;/value&gt;
+      &lt;/list&gt;
+    &lt;/constructor-arg&gt;
+  &lt;/bean&gt;
+&lt;/beans&gt;</programlisting></para>
+
+        <para>Finally, irrespective of the configuration approach you need to
+        copy the following files into
         <literal>$JBOSS_HOME/server/your_config/lib</literal>:<itemizedlist>
         <literal>$JBOSS_HOME/server/your_config/lib</literal>:<itemizedlist>
             <listitem>
             <listitem>
               <para><literal>aopalliance.jar</literal></para>
               <para><literal>aopalliance.jar</literal></para>

+ 1 - 0
doc/xdocs/changes.xml

@@ -46,6 +46,7 @@
       <action dev="benalex" type="update">Improved BasicAclProvider to only respond to specified ACL object requests</action>
       <action dev="benalex" type="update">Improved BasicAclProvider to only respond to specified ACL object requests</action>
       <action dev="benalex" type="update">Refactored MethodDefinitionSource to work with Method, not MethodInvocation</action>
       <action dev="benalex" type="update">Refactored MethodDefinitionSource to work with Method, not MethodInvocation</action>
       <action dev="benalex" type="update">Refactored AbstractSecurityInterceptor to better support other AOP libraries</action>
       <action dev="benalex" type="update">Refactored AbstractSecurityInterceptor to better support other AOP libraries</action>
+      <action dev="benalex" type="update">Improved performance of JBoss container adapter (see reference docs)</action>
       <action dev="benalex" type="fix">Fixed AbstractProcessingFilter to use removeAttribute (JRun compatibility)</action>
       <action dev="benalex" type="fix">Fixed AbstractProcessingFilter to use removeAttribute (JRun compatibility)</action>
       <action dev="benalex" type="fix">Fixed GrantedAuthorityEffectiveAclResolver support of UserDetails principals</action>
       <action dev="benalex" type="fix">Fixed GrantedAuthorityEffectiveAclResolver support of UserDetails principals</action>
       <action dev="benalex" type="update">Moved MethodSecurityInterceptor to ...intercept.method.aopalliance package</action>
       <action dev="benalex" type="update">Moved MethodSecurityInterceptor to ...intercept.method.aopalliance package</action>

+ 3 - 0
project.xml

@@ -120,6 +120,9 @@
     <contributor>
     <contributor>
       <name>Andrew Petro</name>
       <name>Andrew Petro</name>
     </contributor>
     </contributor>
+    <contributor>
+      <name>Sergio Berná</name>
+    </contributor>
   </contributors>
   </contributors>
   <dependencies>
   <dependencies>
     <dependency>
     <dependency>