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á
+