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

This commit is contained in:
Ben Alex 2004-11-30 20:38:15 +00:00
parent 8888e072a2
commit ac3d3483b3
4 changed files with 147 additions and 14 deletions

View File

@ -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); ClassPathXmlApplicationContext ctx = null;
Map beans = ctx.getBeansOfType(AuthenticationManager.class, true, true);
if (beans.size() == 0) { if ((singletonId == null) || "".equals(singletonId)) {
throw new IllegalArgumentException( try {
"Bean context must contain at least one bean of type AuthenticationManager"); 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(); if ((beanName == null) || "".equals(beanName)) {
authenticationManager = (AuthenticationManager) beans.get(beanName); Map beans = null;
super.log.info("Successfully started JbossSpringLoginModule");
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 { 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(),

View File

@ -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>

View File

@ -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>

View File

@ -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>