From ac3d3483b3593c8e42c3d8f3edff62f15816c01d Mon Sep 17 00:00:00 2001 From: Ben Alex Date: Tue, 30 Nov 2004 20:38:15 +0000 Subject: [PATCH] =?UTF-8?q?Improve=20performance=20of=20JBoss=20container?= =?UTF-8?q?=20adapter=20(thanks=20to=20Sergio=20Bern=EF=BF=BD).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../adapters/jboss/JbossAcegiLoginModule.java | 102 ++++++++++++++++-- doc/docbook/index.xml | 55 +++++++++- doc/xdocs/changes.xml | 1 + project.xml | 3 + 4 files changed, 147 insertions(+), 14 deletions(-) diff --git a/adapters/jboss/src/main/java/org/acegisecurity/adapters/jboss/JbossAcegiLoginModule.java b/adapters/jboss/src/main/java/org/acegisecurity/adapters/jboss/JbossAcegiLoginModule.java index 12704b7aaf..13133db768 100644 --- a/adapters/jboss/src/main/java/org/acegisecurity/adapters/jboss/JbossAcegiLoginModule.java +++ b/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.auth.spi.AbstractServerLoginModule; +import org.springframework.beans.factory.access.*; +import org.springframework.beans.factory.access.SingletonBeanFactoryLocator; + import org.springframework.context.support.ClassPathXmlApplicationContext; import java.security.Principal; @@ -53,6 +56,7 @@ import javax.security.auth.login.LoginException; *

* * @author Ben Alex + * @author Sergio Berná * @version $Id$ */ public class JbossAcegiLoginModule extends AbstractServerLoginModule { @@ -69,35 +73,99 @@ public class JbossAcegiLoginModule extends AbstractServerLoginModule { Map sharedState, Map options) { super.initialize(subject, callbackHandler, sharedState, options); + if (super.log.isInfoEnabled()) { + super.log.info("initializing jboss login module"); + } + this.key = (String) options.get("key"); if ((key == null) || "".equals(key)) { throw new IllegalArgumentException("key must be defined"); } + String singletonId = (String) options.get("singletonId"); + String appContextLocation = (String) options.get("appContextLocation"); - if ((appContextLocation == null) || "".equals(appContextLocation)) { + if ((((singletonId == null) || "".equals(singletonId)) + && (appContextLocation == null)) || "".equals(appContextLocation)) { throw new IllegalArgumentException( "appContextLocation must be defined"); } + String beanName = (String) options.get("authenticationManager"); + if (Thread.currentThread().getContextClassLoader().getResource(appContextLocation) == null) { + if (super.log.isInfoEnabled()) { + super.log.info("cannot locate " + appContextLocation); + } + throw new IllegalArgumentException("Cannot locate " + 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"); + } } - String beanName = (String) beans.keySet().iterator().next(); - authenticationManager = (AuthenticationManager) beans.get(beanName); - super.log.info("Successfully started JbossSpringLoginModule"); + 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(); + } + + authenticationManager = (AuthenticationManager) ctx.getBean(beanName); + + if (super.log.isInfoEnabled()) { + super.log.info("Successfully started JbossSpringLoginModule"); + } } public boolean login() throws LoginException { @@ -121,13 +189,27 @@ public class JbossAcegiLoginModule extends AbstractServerLoginModule { password = ""; } + if (super.log.isDebugEnabled()) { + super.log.debug("checking identity"); + } + if (identity == null) { + super.log.debug("creating usernamepassword token"); + Authentication request = new UsernamePasswordAuthenticationToken(username, password); Authentication response = null; try { + if (super.log.isDebugEnabled()) { + super.log.debug("attempting authentication"); + } + response = authenticationManager.authenticate(request); + + if (super.log.isDebugEnabled()) { + super.log.debug("authentication succeded"); + } } catch (AuthenticationException failed) { if (super.log.isDebugEnabled()) { super.log.debug("Bad password for username=" + username); @@ -137,6 +219,8 @@ public class JbossAcegiLoginModule extends AbstractServerLoginModule { "Password Incorrect/Password Required"); } + super.log.debug("user is logged. redirecting to jaas classes"); + identity = new PrincipalAcegiUserToken(this.key, response.getPrincipal().toString(), response.getCredentials().toString(), diff --git a/doc/docbook/index.xml b/doc/docbook/index.xml index 93c0f0e167..1573f2bac6 100644 --- a/doc/docbook/index.xml +++ b/doc/docbook/index.xml @@ -1,7 +1,6 @@ - - Acegi Security System for Spring @@ -2479,14 +2477,17 @@ $CATALINA_HOME/bin/startup.sh JBoss Installation - The following was tested with JBoss 3.2.3. We automatically test + The following was tested with JBoss 3.2.6. We automatically test the following directions using our container integration test system and this version of JBoss. $JBOSS_HOME refers to the root of your JBoss installation. - Edit your + There are two different ways of making spring context available + to the Jboss integration classes. + + The first approach is by editing your $JBOSS_HOME/server/your_config/conf/login-config.xml file so that it contains a new entry under the <Policy> section: @@ -2504,7 +2505,51 @@ $CATALINA_HOME/bin/startup.sh Copy acegisecurity.xml into $JBOSS_HOME/server/your_config/conf. - Copy the following files into + In this configuration acegisecurity.xml + contains the spring context definition including all the + authentication manager beans. You have to bear in mind though, that + SecurityContext 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 + org.springframework.beans.factory.access.SingletonBeanFactoryLocator. + The required configuration for this approach is: + + <application-policy name = "SpringPoweredRealm"> + <authentication> + <login-module code = "net.sf.acegisecurity.adapters.jboss.JbossSpringLoginModule" + flag = "required"> + <module-option name = "singletonId">springRealm</module-option> + <module-option name = "key">my_password</module-option> + <module-option name = "authenticationManager">authenticationManager</module-option> + </login-module> + </authentication> + </application-policy> + + In the above code fragment, + authenticationManager is a helper property that + defines the expected name of the + AuthenticationManager in case you have several + defined in the IoC container. The singletonId + property references a bean defined in a + beanRefFactory.xml file. This file needs to be + available from anywhere on the JBoss classpath, including + $JBOSS_HOME/server/your_config/conf. The + beanRefFactory.xml contains the following + declaration: + + <beans> + <bean id="springRealm" singleton="true" lazy-init="true" class="org.springframework.context.support.ClassPathXmlApplicationContext"> + <constructor-arg> + <list> + <value>acegisecurity.xml</value> + </list> + </constructor-arg> + </bean> +</beans> + + Finally, irrespective of the configuration approach you need to + copy the following files into $JBOSS_HOME/server/your_config/lib: aopalliance.jar diff --git a/doc/xdocs/changes.xml b/doc/xdocs/changes.xml index 541b4bb14f..b87a9f6a1b 100644 --- a/doc/xdocs/changes.xml +++ b/doc/xdocs/changes.xml @@ -46,6 +46,7 @@ Improved BasicAclProvider to only respond to specified ACL object requests Refactored MethodDefinitionSource to work with Method, not MethodInvocation Refactored AbstractSecurityInterceptor to better support other AOP libraries + Improved performance of JBoss container adapter (see reference docs) Fixed AbstractProcessingFilter to use removeAttribute (JRun compatibility) Fixed GrantedAuthorityEffectiveAclResolver support of UserDetails principals Moved MethodSecurityInterceptor to ...intercept.method.aopalliance package diff --git a/project.xml b/project.xml index eb8eabe142..c21d8638a4 100644 --- a/project.xml +++ b/project.xml @@ -120,6 +120,9 @@ Andrew Petro + + Sergio Berná +