[jboss-cvs] Picketbox SVN: r180 - in trunk: picketbox-infinispan and 16 other directories.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Thu Mar 31 10:09:00 EDT 2011
Author: mmoyses
Date: 2011-03-31 10:09:00 -0400 (Thu, 31 Mar 2011)
New Revision: 180
Added:
trunk/picketbox-infinispan/
trunk/picketbox-infinispan/.classpath
trunk/picketbox-infinispan/.project
trunk/picketbox-infinispan/.settings/
trunk/picketbox-infinispan/.settings/org.eclipse.jdt.core.prefs
trunk/picketbox-infinispan/.settings/org.maven.ide.eclipse.prefs
trunk/picketbox-infinispan/pom.xml
trunk/picketbox-infinispan/src/
trunk/picketbox-infinispan/src/main/
trunk/picketbox-infinispan/src/main/java/
trunk/picketbox-infinispan/src/main/java/org/
trunk/picketbox-infinispan/src/main/java/org/jboss/
trunk/picketbox-infinispan/src/main/java/org/jboss/security/
trunk/picketbox-infinispan/src/main/java/org/jboss/security/authentication/
trunk/picketbox-infinispan/src/main/java/org/jboss/security/authentication/JBossCachedAuthenticationManager.java
trunk/picketbox-infinispan/src/main/java/org/jboss/security/authentication/SubjectActions.java
trunk/picketbox-infinispan/src/test/
trunk/picketbox-infinispan/src/test/java/
trunk/picketbox-infinispan/src/test/java/org/
trunk/picketbox-infinispan/src/test/java/org/jboss/
trunk/picketbox-infinispan/src/test/java/org/jboss/security/
trunk/picketbox-infinispan/src/test/java/org/jboss/security/test/
trunk/picketbox-infinispan/src/test/java/org/jboss/security/test/authentication/
trunk/picketbox-infinispan/src/test/java/org/jboss/security/test/authentication/JBossCachedAuthenticationManagerUnitTestCase.java
trunk/picketbox-infinispan/src/test/java/org/jboss/security/test/authentication/SecurityActions.java
trunk/picketbox-infinispan/src/test/resources/
trunk/picketbox-infinispan/src/test/resources/roles.properties
trunk/picketbox-infinispan/src/test/resources/users.properties
Modified:
trunk/pom.xml
Log:
SECURITY-577: new AuthenticationManager implementation using Infinispan as cache solution
Property changes on: trunk/picketbox-infinispan
___________________________________________________________________
Added: svn:ignore
+ .settings
Added: trunk/picketbox-infinispan/.classpath
===================================================================
--- trunk/picketbox-infinispan/.classpath (rev 0)
+++ trunk/picketbox-infinispan/.classpath 2011-03-31 14:09:00 UTC (rev 180)
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" output="target/classes" path="src/main/java"/>
+ <classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
+ <classpathentry kind="src" path="src/test/resources"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+ <classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
+ <classpathentry kind="output" path="target/classes"/>
+</classpath>
Added: trunk/picketbox-infinispan/.project
===================================================================
--- trunk/picketbox-infinispan/.project (rev 0)
+++ trunk/picketbox-infinispan/.project 2011-03-31 14:09:00 UTC (rev 180)
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>picketbox-infinispan</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.maven.ide.eclipse.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.maven.ide.eclipse.maven2Nature</nature>
+ </natures>
+</projectDescription>
Added: trunk/picketbox-infinispan/.settings/org.eclipse.jdt.core.prefs
===================================================================
--- trunk/picketbox-infinispan/.settings/org.eclipse.jdt.core.prefs (rev 0)
+++ trunk/picketbox-infinispan/.settings/org.eclipse.jdt.core.prefs 2011-03-31 14:09:00 UTC (rev 180)
@@ -0,0 +1,9 @@
+#Thu Mar 24 17:50:09 BRT 2011
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.6
Added: trunk/picketbox-infinispan/.settings/org.maven.ide.eclipse.prefs
===================================================================
--- trunk/picketbox-infinispan/.settings/org.maven.ide.eclipse.prefs (rev 0)
+++ trunk/picketbox-infinispan/.settings/org.maven.ide.eclipse.prefs 2011-03-31 14:09:00 UTC (rev 180)
@@ -0,0 +1,8 @@
+#Thu Mar 24 17:49:52 BRT 2011
+activeProfiles=
+eclipse.preferences.version=1
+fullBuildGoals=process-test-resources
+resolveWorkspaceProjects=true
+resourceFilterGoals=process-resources resources\:testResources
+skipCompilerPlugin=true
+version=1
Added: trunk/picketbox-infinispan/pom.xml
===================================================================
--- trunk/picketbox-infinispan/pom.xml (rev 0)
+++ trunk/picketbox-infinispan/pom.xml 2011-03-31 14:09:00 UTC (rev 180)
@@ -0,0 +1,53 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.jboss</groupId>
+ <artifactId>jboss-parent</artifactId>
+ <version>5</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.picketbox</groupId>
+ <artifactId>picketbox-infinispan</artifactId>
+ <version>4.0.0-SNAPSHOT</version>
+ <packaging>jar</packaging>
+ <name>Picketbox Infinispan</name>
+ <url>http://jboss.org/picketbox</url>
+ <description>PicketBox Infinispan adds cluster and cache capabilities to PicktBox.</description>
+
+ <properties>
+ <version.org.infinispan>4.2.1.FINAL</version.org.infinispan>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.picketbox</groupId>
+ <artifactId>picketbox-spi-bare</artifactId>
+ <version>${project.version}</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.picketbox</groupId>
+ <artifactId>jbosssx-bare</artifactId>
+ <version>${project.version}</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.logging</groupId>
+ <artifactId>jboss-logging-spi</artifactId>
+ <version>2.1.1.GA</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.infinispan</groupId>
+ <artifactId>infinispan-core</artifactId>
+ <version>${version.org.infinispan}</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.8.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
Added: trunk/picketbox-infinispan/src/main/java/org/jboss/security/authentication/JBossCachedAuthenticationManager.java
===================================================================
--- trunk/picketbox-infinispan/src/main/java/org/jboss/security/authentication/JBossCachedAuthenticationManager.java (rev 0)
+++ trunk/picketbox-infinispan/src/main/java/org/jboss/security/authentication/JBossCachedAuthenticationManager.java 2011-03-31 14:09:00 UTC (rev 180)
@@ -0,0 +1,493 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2011, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.security.authentication;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.lang.reflect.UndeclaredThrowableException;
+import java.security.Principal;
+import java.security.acl.Group;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+import org.infinispan.Cache;
+import org.jboss.logging.Logger;
+import org.jboss.security.AuthenticationManager;
+import org.jboss.security.CacheableManager;
+import org.jboss.security.SecurityConstants;
+import org.jboss.security.SecurityContext;
+import org.jboss.security.SecurityContextAssociation;
+import org.jboss.security.auth.callback.JBossCallbackHandler;
+import org.jboss.security.authentication.JBossCachedAuthenticationManager.DomainInfo;
+
+/**
+ * {@link AuthenticationManager} implementation that uses {@link Cache} as the cache provider.
+ *
+ * @author <a href="mmoyses at redhat.com">Marcus Moyses</a>
+ * @author <a href="on at ibis.odessa.ua">Oleg Nitz</a>
+ * @author Scott.Stark at jboss.org
+ * @author Anil.Saldhana at jboss.org
+ */
+public class JBossCachedAuthenticationManager
+ implements
+ AuthenticationManager,
+ CacheableManager<Cache<Principal, DomainInfo>, Principal>
+{
+
+ private String securityDomain;
+
+ private CallbackHandler callbackHandler;
+
+ protected Logger log = Logger.getLogger(this.getClass());
+
+ protected boolean trace;
+
+ private transient Method setSecurityInfo;
+
+ protected Cache<Principal, DomainInfo> domainCache;
+
+ private boolean deepCopySubjectOption = false;
+
+ /**
+ * Create a new JBossCachedAuthenticationManager using the
+ * default security domain and {@link CallbackHandler} implementation.
+ */
+ public JBossCachedAuthenticationManager()
+ {
+ this(SecurityConstants.DEFAULT_APPLICATION_POLICY, new JBossCallbackHandler());
+ }
+
+ /**
+ * Create a new JBossCachedAuthenticationManager.
+ *
+ * @param securityDomain name of the security domain
+ * @param callbackHandler {@link CallbackHandler} implementation
+ */
+ public JBossCachedAuthenticationManager(String securityDomain, CallbackHandler callbackHandler)
+ {
+ this.securityDomain = securityDomain;
+ this.callbackHandler = callbackHandler;
+ this.trace = log.isTraceEnabled();
+
+ // Get the setSecurityInfo(Principal principal, Object credential) method
+ Class<?>[] sig =
+ {Principal.class, Object.class};
+ try
+ {
+ setSecurityInfo = callbackHandler.getClass().getMethod("setSecurityInfo", sig);
+ }
+ catch (Exception e)
+ {
+ String msg = "Failed to find setSecurityInfo(Principal, Object) method in CallbackHandler";
+ throw new UndeclaredThrowableException(e, msg);
+ }
+ if (trace)
+ log.trace("CallbackHandler: " + callbackHandler);
+ }
+
+ @Override
+ public Subject getActiveSubject()
+ {
+ Subject subj = null;
+ SecurityContext sc = SecurityContextAssociation.getSecurityContext();
+ if (sc != null)
+ {
+ subj = sc.getUtil().getSubject();
+ }
+ return subj;
+ }
+
+ @Override
+ public Principal getTargetPrincipal(Principal anotherDomainPrincipal, Map<String, Object> contextMap)
+ {
+ throw new RuntimeException("Not implemented yet");
+ }
+
+ @Override
+ public boolean isValid(Principal principal, Object credential)
+ {
+ return isValid(principal, credential, null);
+ }
+
+ @Override
+ public boolean isValid(Principal principal, Object credential, Subject activeSubject)
+ {
+ // first check cache
+ DomainInfo cachedEntry = getCacheInfo(principal);
+ if (trace)
+ log.trace("Begin isValid, principal:" + principal + ", cache entry: " + cachedEntry);
+
+ boolean isValid = false;
+ if (cachedEntry != null)
+ {
+ isValid = validateCache(cachedEntry, credential, activeSubject);
+ }
+
+ if (!isValid)
+ isValid = authenticate(principal, credential, activeSubject);
+
+ if (trace)
+ log.trace("End isValid, " + isValid);
+
+ return isValid;
+ }
+
+ @Override
+ public String getSecurityDomain()
+ {
+ return securityDomain;
+ }
+
+ @Override
+ public void flushCache()
+ {
+ if (trace)
+ log.trace("Flushing all entried from the cache");
+ domainCache.clear();
+ }
+
+ @Override
+ public void flushCache(Principal key)
+ {
+ if (trace)
+ log.trace("Flushing " + key.getName() + " from cache");
+ domainCache.evict(key);
+ }
+
+ @Override
+ public void setCache(Cache<Principal, DomainInfo> cache)
+ {
+ this.domainCache = cache;
+ }
+
+ @Override
+ public boolean containsKey(Principal key)
+ {
+ return domainCache.containsKey(key);
+ }
+
+ /**
+ * Flag to specify if deep copy of subject sets needs to be
+ * enabled
+ *
+ * @param flag
+ */
+ public void setDeepCopySubjectOption(Boolean flag)
+ {
+ if (trace)
+ log.trace("setDeepCopySubjectOption=" + flag);
+ deepCopySubjectOption = flag.booleanValue();
+ }
+
+ /**
+ * Retrieve on entry from the cache.
+ *
+ * @param principal entry's key
+ * @return entry's value or null if not found
+ */
+ private DomainInfo getCacheInfo(Principal principal)
+ {
+ if (domainCache == null)
+ return null;
+ return domainCache.get(principal);
+ }
+
+ /**
+ * Validate the cache credential value against the provided credential
+ */
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ private boolean validateCache(DomainInfo info, Object credential, Subject theSubject)
+ {
+ if (trace)
+ {
+ StringBuffer tmp = new StringBuffer("Begin validateCache, info=");
+ tmp.append(info.toString());
+ tmp.append(";credential.class=");
+ if (credential != null)
+ {
+ Class c = credential.getClass();
+ tmp.append(c.getName());
+ tmp.append('@');
+ tmp.append(System.identityHashCode(c));
+ }
+ else
+ {
+ tmp.append("null");
+ }
+ log.trace(tmp.toString());
+ }
+
+ Object subjectCredential = info.credential;
+ boolean isValid = false;
+ // Check for a null credential as can be the case for an anonymous user
+ if (credential == null || subjectCredential == null)
+ {
+ // Both credentials must be null
+ isValid = (credential == null) && (subjectCredential == null);
+ }
+ // See if the credential is assignable to the cache value
+ else if (subjectCredential.getClass().isAssignableFrom(credential.getClass()))
+ {
+ // Validate the credential by trying Comparable, char[], byte[], Object[], and finally Object.equals()
+ if (subjectCredential instanceof Comparable)
+ {
+ Comparable c = (Comparable) subjectCredential;
+ isValid = c.compareTo(credential) == 0;
+ }
+ else if (subjectCredential instanceof char[])
+ {
+ char[] a1 = (char[]) subjectCredential;
+ char[] a2 = (char[]) credential;
+ isValid = Arrays.equals(a1, a2);
+ }
+ else if (subjectCredential instanceof byte[])
+ {
+ byte[] a1 = (byte[]) subjectCredential;
+ byte[] a2 = (byte[]) credential;
+ isValid = Arrays.equals(a1, a2);
+ }
+ else if (subjectCredential.getClass().isArray())
+ {
+ Object[] a1 = (Object[]) subjectCredential;
+ Object[] a2 = (Object[]) credential;
+ isValid = Arrays.equals(a1, a2);
+ }
+ else
+ {
+ isValid = subjectCredential.equals(credential);
+ }
+ }
+ else if (subjectCredential instanceof char[] && credential instanceof String)
+ {
+ char[] a1 = (char[]) subjectCredential;
+ char[] a2 = ((String) credential).toCharArray();
+ isValid = Arrays.equals(a1, a2);
+ }
+ else if (subjectCredential instanceof String && credential instanceof char[])
+ {
+ char[] a1 = ((String) subjectCredential).toCharArray();
+ char[] a2 = (char[]) credential;
+ isValid = Arrays.equals(a1, a2);
+ }
+
+ // If the credentials match, set the thread's active Subject
+ if (isValid)
+ {
+ // Copy the current subject into theSubject
+ if (theSubject != null)
+ {
+ SubjectActions.copySubject(info.subject, theSubject, false, this.deepCopySubjectOption);
+ }
+ }
+ if (trace)
+ log.trace("End validateCache, isValid=" + isValid);
+
+ return isValid;
+ }
+
+ /**
+ * Currently this simply calls defaultLogin() to do a JAAS login using the
+ * security domain name as the login module configuration name.
+ *
+ * @param principal - the user id to authenticate
+ * @param credential - an opaque credential.
+ * @return false on failure, true on success.
+ */
+ private boolean authenticate(Principal principal, Object credential, Subject theSubject)
+ {
+ Subject subject = null;
+ boolean authenticated = false;
+ LoginException authException = null;
+
+ try
+ {
+ // Validate the principal using the login configuration for this domain
+ LoginContext lc = defaultLogin(principal, credential);
+ subject = lc.getSubject();
+
+ // Set the current subject if login was successful
+ if (subject != null)
+ {
+ // Copy the current subject into theSubject
+ if (theSubject != null)
+ {
+ SubjectActions.copySubject(subject, theSubject, false, this.deepCopySubjectOption);
+ }
+ else
+ {
+ theSubject = subject;
+ }
+
+ authenticated = true;
+ // Build the Subject based DomainInfo cache value
+ updateCache(lc, subject, principal, credential);
+ }
+ }
+ catch (LoginException e)
+ {
+ // Don't log anonymous user failures unless trace level logging is on
+ if (principal != null && principal.getName() != null || trace)
+ log.trace("Login failure", e);
+ authException = e;
+ }
+ // Set the security association thread context info exception
+ SubjectActions.setContextInfo("org.jboss.security.exception", authException);
+
+ return authenticated;
+ }
+
+ /**
+ * Pass the security info to the login modules configured for
+ * this security domain using our SecurityAssociationHandler.
+ *
+ * @return The authenticated Subject if successful.
+ * @exception LoginException throw if login fails for any reason.
+ */
+ private LoginContext defaultLogin(Principal principal, Object credential) throws LoginException
+ {
+ // We use our internal CallbackHandler to provide the security info. A
+ // copy must be made to ensure there is a unique handler per active
+ // login since there can be multiple active logins.
+ Object[] securityInfo = {principal, credential};
+ CallbackHandler theHandler = null;
+ try
+ {
+ theHandler = (CallbackHandler) callbackHandler.getClass().newInstance();
+ setSecurityInfo.invoke(theHandler, securityInfo);
+ }
+ catch (Throwable e)
+ {
+ if (trace)
+ log.trace("Failed to create/setSecurityInfo on handler", e);
+ LoginException le = new LoginException("Failed to setSecurityInfo on handler");
+ le.initCause(e);
+ throw le;
+ }
+ Subject subject = new Subject();
+ LoginContext lc = null;
+ if (trace)
+ log.trace("defaultLogin, principal=" + principal);
+ lc = SubjectActions.createLoginContext(securityDomain, subject, theHandler);
+ lc.login();
+ if (trace)
+ log.trace("defaultLogin, lc=" + lc + ", subject=" + SubjectActions.toString(subject));
+ return lc;
+ }
+
+ /**
+ * Updates the cache either by inserting a new entry or by replacing
+ * an invalid (expired) entry.
+ *
+ * @param loginContext {@link LoginContext} of the authentication
+ * @param subject {@link Subject} resulted from JAAS login
+ * @param principal {@link Principal} representing the user's identity
+ * @param credential user's proof of identity
+ * @return authenticated {@link Subject}
+ */
+ private Subject updateCache(LoginContext loginContext, Subject subject, Principal principal, Object credential)
+ {
+ // If we don't have a cache there is nothing to update
+ if (domainCache == null)
+ return subject;
+
+ DomainInfo info = new DomainInfo();
+ info.loginContext = loginContext;
+ info.subject = new Subject();
+ SubjectActions.copySubject(subject, info.subject, true, this.deepCopySubjectOption);
+ info.credential = credential;
+
+ if (trace)
+ {
+ log.trace("updateCache, inputSubject=" + SubjectActions.toString(subject) + ", cacheSubject="
+ + SubjectActions.toString(info.subject));
+ }
+
+ // Get the Subject callerPrincipal by looking for a Group called 'CallerPrincipal'
+ Set<Group> subjectGroups = subject.getPrincipals(Group.class);
+ Iterator<Group> iter = subjectGroups.iterator();
+ while (iter.hasNext())
+ {
+ Group grp = iter.next();
+ String name = grp.getName();
+ if (name.equals("CallerPrincipal"))
+ {
+ Enumeration<? extends Principal> members = grp.members();
+ if (members.hasMoreElements())
+ info.callerPrincipal = members.nextElement();
+ }
+ }
+
+ // Handle null principals with no callerPrincipal. This is an indication
+ // of an user that has not provided any authentication info, but
+ // has been authenticated by the domain login module stack. Here we look
+ // for the first non-Group Principal and use that.
+ if (info.callerPrincipal == null)
+ {
+ Set<Principal> subjectPrincipals = subject.getPrincipals(Principal.class);
+ Iterator<? extends Principal> iterPrincipals = subjectPrincipals.iterator();
+ while (iterPrincipals.hasNext())
+ {
+ Principal p = iterPrincipals.next();
+ if (!(p instanceof Group))
+ {
+ info.callerPrincipal = p;
+ break;
+ }
+ }
+ }
+
+ // If the user already exists another login is active. Currently
+ // only one is allowed so remove the old and insert the new
+ domainCache.put(info.callerPrincipal, info);
+ if (trace)
+ log.trace("Inserted cache info: " + info);
+ return info.subject;
+ }
+
+ /**
+ * A cache value. Holds information about the authentication process.
+ *
+ * @author <a href="mmoyses at redhat.com">Marcus Moyses</a>
+ */
+ public static class DomainInfo implements Serializable
+ {
+
+ private static final long serialVersionUID = 7402775370244483773L;
+
+ protected LoginContext loginContext;
+
+ protected Subject subject;
+
+ protected Object credential;
+
+ protected Principal callerPrincipal;
+ }
+
+}
Added: trunk/picketbox-infinispan/src/main/java/org/jboss/security/authentication/SubjectActions.java
===================================================================
--- trunk/picketbox-infinispan/src/main/java/org/jboss/security/authentication/SubjectActions.java (rev 0)
+++ trunk/picketbox-infinispan/src/main/java/org/jboss/security/authentication/SubjectActions.java 2011-03-31 14:09:00 UTC (rev 180)
@@ -0,0 +1,365 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2005, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.security.authentication;
+
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.Principal;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+import javax.security.jacc.PolicyContext;
+import javax.security.jacc.PolicyContextException;
+
+import org.jboss.security.SecurityAssociation;
+import org.jboss.security.SecurityConstants;
+import org.jboss.security.SecurityContext;
+import org.jboss.security.SecurityContextAssociation;
+import org.jboss.security.SecurityContextFactory;
+
+/**
+ * Common PrivilegedAction used by classes in this package.
+ *
+ * @author Scott.Stark at jboss.org
+ * @author Anil.Saldhana at redhat.com
+ */
+class SubjectActions
+{
+ private static class ToStringSubjectAction implements PrivilegedAction<String>
+ {
+ Subject subject;
+
+ ToStringSubjectAction(Subject subject)
+ {
+ this.subject = subject;
+ }
+
+ public String run()
+ {
+ StringBuffer tmp = new StringBuffer();
+ tmp.append("Subject(");
+ tmp.append(System.identityHashCode(subject));
+ tmp.append(").principals=");
+ Iterator<Principal> principals = subject.getPrincipals().iterator();
+ while (principals.hasNext())
+ {
+ Object p = principals.next();
+ Class<?> c = p.getClass();
+ tmp.append(c.getName());
+ tmp.append('@');
+ tmp.append(System.identityHashCode(c));
+ tmp.append('(');
+ tmp.append(p);
+ tmp.append(')');
+ }
+ return tmp.toString();
+ }
+ }
+
+ private static class GetSubjectAction implements PrivilegedExceptionAction<Subject>
+ {
+ static PrivilegedExceptionAction<Subject> ACTION = new GetSubjectAction();
+
+ public Subject run() throws PolicyContextException
+ {
+ return (Subject) PolicyContext.getContext(SecurityConstants.SUBJECT_CONTEXT_KEY);
+ }
+ }
+
+ private static class CopySubjectAction implements PrivilegedAction<Object>
+ {
+ Subject fromSubject;
+
+ Subject toSubject;
+
+ boolean setReadOnly;
+
+ boolean deepCopy;
+
+ CopySubjectAction(Subject fromSubject, Subject toSubject, boolean setReadOnly)
+ {
+ this.fromSubject = fromSubject;
+ this.toSubject = toSubject;
+ this.setReadOnly = setReadOnly;
+ }
+
+ public void setDeepCopy(boolean flag)
+ {
+ this.deepCopy = flag;
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public Object run()
+ {
+ Set principals = fromSubject.getPrincipals();
+ Set principals2 = toSubject.getPrincipals();
+ Iterator<Principal> iter = principals.iterator();
+ while (iter.hasNext())
+ principals2.add(getCloneIfNeeded(iter.next()));
+ Set privateCreds = fromSubject.getPrivateCredentials();
+ Set privateCreds2 = toSubject.getPrivateCredentials();
+ iter = privateCreds.iterator();
+ while (iter.hasNext())
+ privateCreds2.add(getCloneIfNeeded(iter.next()));
+ Set publicCreds = fromSubject.getPublicCredentials();
+ Set publicCreds2 = toSubject.getPublicCredentials();
+ iter = publicCreds.iterator();
+ while (iter.hasNext())
+ publicCreds2.add(getCloneIfNeeded(iter.next()));
+ if (setReadOnly == true)
+ toSubject.setReadOnly();
+ return null;
+ }
+
+ /** Check if the deepCopy flag is ON && Object implements {@link Cloneable} and return cloned object */
+ private Object getCloneIfNeeded(Object obj)
+ {
+ Object clonedObject = null;
+ if (this.deepCopy && obj instanceof Cloneable)
+ {
+ Class<?> clazz = obj.getClass();
+ try
+ {
+ Method cloneMethod = clazz.getMethod("clone", (Class[]) null);
+ clonedObject = cloneMethod.invoke(obj, (Object[]) null);
+ }
+ catch (Exception e)
+ {
+ // Ignore non-cloneable issues
+ }
+ }
+ if (clonedObject == null)
+ clonedObject = obj;
+ return clonedObject;
+ }
+ }
+
+ private static class LoginContextAction implements PrivilegedExceptionAction<LoginContext>
+ {
+ String securityDomain;
+
+ Subject subject;
+
+ CallbackHandler handler;
+
+ LoginContextAction(String securityDomain, Subject subject, CallbackHandler handler)
+ {
+ this.securityDomain = securityDomain;
+ this.subject = subject;
+ this.handler = handler;
+ }
+
+ public LoginContext run() throws Exception
+ {
+ LoginContext lc = new LoginContext(securityDomain, subject, handler);
+ return lc;
+ }
+ }
+
+ private static class GetTCLAction implements PrivilegedAction<ClassLoader>
+ {
+ static PrivilegedAction<ClassLoader> ACTION = new GetTCLAction();
+
+ public ClassLoader run()
+ {
+ ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ return loader;
+ }
+ }
+
+ private static class SetContextInfoAction implements PrivilegedAction<Object>
+ {
+ String key;
+
+ Object value;
+
+ SetContextInfoAction(String key, Object value)
+ {
+ this.key = key;
+ this.value = value;
+ }
+
+ public Object run()
+ {
+ // Set it on the current security context also
+ SecurityContext sc = SecurityContextAssociation.getSecurityContext();
+ if (sc != null)
+ {
+ sc.getData().put(key, value);
+ }
+ return SecurityAssociation.setContextInfo(key, value);
+ }
+ }
+
+ interface PrincipalInfoAction
+ {
+ PrincipalInfoAction PRIVILEGED = new PrincipalInfoAction()
+ {
+ public void push(final Principal principal, final Object credential, final Subject subject,
+ final String securityDomain)
+ {
+ AccessController.doPrivileged(new PrivilegedAction<Object>()
+ {
+ public Object run()
+ {
+ SecurityContext sc = SecurityContextAssociation.getSecurityContext();
+ if (sc == null)
+ {
+ try
+ {
+ sc = SecurityContextFactory.createSecurityContext(principal, credential, subject,
+ securityDomain);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ SecurityContextAssociation.setSecurityContext(sc);
+ return null;
+ }
+ });
+ }
+
+ public void pop()
+ {
+ AccessController.doPrivileged(new PrivilegedAction<Object>()
+ {
+ public Object run()
+ {
+ SecurityContextAssociation.clearSecurityContext();
+ return null;
+ }
+ });
+ }
+ };
+
+ PrincipalInfoAction NON_PRIVILEGED = new PrincipalInfoAction()
+ {
+ public void push(Principal principal, Object credential, Subject subject, String securityDomain)
+ {
+ SecurityContext sc = SecurityContextAssociation.getSecurityContext();
+ if (sc == null)
+ {
+ try
+ {
+ sc = SecurityContextFactory.createSecurityContext(principal, credential, subject, securityDomain);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ else
+ {
+ sc.getUtil().createSubjectInfo(principal, credential, subject);
+ }
+ SecurityContextAssociation.setSecurityContext(sc);
+ }
+
+ public void pop()
+ {
+ SecurityContextAssociation.clearSecurityContext();
+ }
+ };
+
+ void push(Principal principal, Object credential, Subject subject, String securityDomain);
+
+ void pop();
+ }
+
+ static Subject getActiveSubject() throws PrivilegedActionException
+ {
+ Subject subject = (Subject) AccessController.doPrivileged(GetSubjectAction.ACTION);
+ return subject;
+ }
+
+ static void copySubject(Subject fromSubject, Subject toSubject)
+ {
+ copySubject(fromSubject, toSubject, false);
+ }
+
+ static void copySubject(Subject fromSubject, Subject toSubject, boolean setReadOnly)
+ {
+ CopySubjectAction action = new CopySubjectAction(fromSubject, toSubject, setReadOnly);
+ if (System.getSecurityManager() != null)
+ AccessController.doPrivileged(action);
+ else
+ action.run();
+ }
+
+ static void copySubject(Subject fromSubject, Subject toSubject, boolean setReadOnly, boolean deepCopy)
+ {
+ CopySubjectAction action = new CopySubjectAction(fromSubject, toSubject, setReadOnly);
+ action.setDeepCopy(deepCopy);
+ if (System.getSecurityManager() != null)
+ AccessController.doPrivileged(action);
+ else
+ action.run();
+ }
+
+ static LoginContext createLoginContext(String securityDomain, Subject subject, CallbackHandler handler)
+ throws LoginException
+ {
+ LoginContextAction action = new LoginContextAction(securityDomain, subject, handler);
+ try
+ {
+ LoginContext lc = (LoginContext) AccessController.doPrivileged(action);
+ return lc;
+ }
+ catch (PrivilegedActionException e)
+ {
+ Exception ex = e.getException();
+ if (ex instanceof LoginException)
+ throw (LoginException) ex;
+ else
+ throw new LoginException(ex.getMessage());
+ }
+ }
+
+ static ClassLoader getContextClassLoader()
+ {
+ ClassLoader loader = (ClassLoader) AccessController.doPrivileged(GetTCLAction.ACTION);
+ return loader;
+ }
+
+ static Object setContextInfo(String key, Object value)
+ {
+ SetContextInfoAction action = new SetContextInfoAction(key, value);
+ Object prevInfo = AccessController.doPrivileged(action);
+ return prevInfo;
+ }
+
+ static String toString(Subject subject)
+ {
+ ToStringSubjectAction action = new ToStringSubjectAction(subject);
+ String info = (String) AccessController.doPrivileged(action);
+ return info;
+ }
+}
\ No newline at end of file
Added: trunk/picketbox-infinispan/src/test/java/org/jboss/security/test/authentication/JBossCachedAuthenticationManagerUnitTestCase.java
===================================================================
--- trunk/picketbox-infinispan/src/test/java/org/jboss/security/test/authentication/JBossCachedAuthenticationManagerUnitTestCase.java (rev 0)
+++ trunk/picketbox-infinispan/src/test/java/org/jboss/security/test/authentication/JBossCachedAuthenticationManagerUnitTestCase.java 2011-03-31 14:09:00 UTC (rev 180)
@@ -0,0 +1,201 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2011, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.security.test.authentication;
+
+import java.security.Principal;
+import java.util.HashMap;
+
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
+
+import junit.framework.TestCase;
+
+import org.infinispan.Cache;
+import org.infinispan.manager.DefaultCacheManager;
+import org.infinispan.manager.EmbeddedCacheManager;
+import org.jboss.security.AuthenticationManager;
+import org.jboss.security.CacheableManager;
+import org.jboss.security.SimplePrincipal;
+import org.jboss.security.auth.callback.AppCallbackHandler;
+import org.jboss.security.authentication.JBossCachedAuthenticationManager;
+import org.jboss.security.authentication.JBossCachedAuthenticationManager.DomainInfo;
+
+/**
+ * Unit tests for the JBossCachedAuthenticationManager.
+ *
+ * @author <a href="mmoyses at redhat.com">Marcus Moyses</a>
+ * @author Anil.Saldhana at redhat.com
+ */
+public class JBossCachedAuthenticationManagerUnitTestCase extends TestCase
+{
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ establishSecurityConfiguration();
+ }
+
+ public void testSecurityDomain() throws Exception
+ {
+ AuthenticationManager am = new JBossCachedAuthenticationManager("test1", new AppCallbackHandler("a",
+ "b".toCharArray()));
+ assertEquals("test1", am.getSecurityDomain());
+ }
+
+ public void testLogin() throws Exception
+ {
+ Principal p = new SimplePrincipal("jduke");
+ AppCallbackHandler acbh = new AppCallbackHandler("jduke", "theduke".toCharArray());
+ AuthenticationManager am = new JBossCachedAuthenticationManager("test", acbh);
+ assertTrue(am.isValid(p, "theduke"));
+ }
+
+ public void testUnsuccessfulLogin() throws Exception
+ {
+ Principal p = new SimplePrincipal("jduke");
+ AppCallbackHandler acbh = new AppCallbackHandler("jduke", "bad".toCharArray());
+ AuthenticationManager am = new JBossCachedAuthenticationManager("test", acbh);
+ assertFalse(am.isValid(p, "bad"));
+ }
+
+ public void testCacheHit() throws Exception
+ {
+ Principal p = new SimplePrincipal("jduke");
+ AppCallbackHandler acbh = new AppCallbackHandler("jduke", "theduke".toCharArray());
+ AuthenticationManager am = new JBossCachedAuthenticationManager("test", acbh);
+
+ EmbeddedCacheManager cacheManager = new DefaultCacheManager();
+ org.infinispan.config.Configuration configuration = new org.infinispan.config.Configuration();
+ configuration.setExpirationMaxIdle(2000);
+ cacheManager.defineConfiguration("test", configuration);
+ Cache<Principal, DomainInfo> cache = cacheManager.getCache("test");
+ @SuppressWarnings("unchecked")
+ CacheableManager<Cache<Principal, DomainInfo>, Principal> cm = (CacheableManager<Cache<Principal, DomainInfo>, Principal>) am;
+ cm.setCache(cache);
+
+ assertTrue(am.isValid(p, "theduke"));
+ assertTrue(cm.containsKey(p));
+ Thread.sleep(1000);
+ assertTrue(cm.containsKey(p));
+ }
+
+ public void testCacheIdleTimeExpiration() throws Exception
+ {
+ Principal p = new SimplePrincipal("jduke");
+ AppCallbackHandler acbh = new AppCallbackHandler("jduke", "theduke".toCharArray());
+ AuthenticationManager am = new JBossCachedAuthenticationManager("test", acbh);
+
+ EmbeddedCacheManager cacheManager = new DefaultCacheManager();
+ org.infinispan.config.Configuration configuration = new org.infinispan.config.Configuration();
+ configuration.setExpirationMaxIdle(1000);
+ cacheManager.defineConfiguration("test", configuration);
+ Cache<Principal, DomainInfo> cache = cacheManager.getCache("test");
+ @SuppressWarnings("unchecked")
+ CacheableManager<Cache<Principal, DomainInfo>, Principal> cm = (CacheableManager<Cache<Principal, DomainInfo>, Principal>) am;
+ cm.setCache(cache);
+
+ assertTrue(am.isValid(p, "theduke"));
+ assertTrue(cm.containsKey(p));
+ Thread.sleep(2000);
+ assertFalse(cm.containsKey(p));
+ }
+
+ public void testCacheIdleTimeUpdate() throws Exception
+ {
+ Principal p = new SimplePrincipal("jduke");
+ AppCallbackHandler acbh = new AppCallbackHandler("jduke", "theduke".toCharArray());
+ AuthenticationManager am = new JBossCachedAuthenticationManager("test", acbh);
+
+ EmbeddedCacheManager cacheManager = new DefaultCacheManager();
+ org.infinispan.config.Configuration configuration = new org.infinispan.config.Configuration();
+ configuration.setExpirationMaxIdle(2000);
+ cacheManager.defineConfiguration("test", configuration);
+ Cache<Principal, DomainInfo> cache = cacheManager.getCache("test");
+ @SuppressWarnings("unchecked")
+ CacheableManager<Cache<Principal, DomainInfo>, Principal> cm = (CacheableManager<Cache<Principal, DomainInfo>, Principal>) am;
+ cm.setCache(cache);
+
+ assertTrue(am.isValid(p, "theduke"));
+ assertTrue(cm.containsKey(p));
+ Thread.sleep(1000);
+ assertTrue(cm.containsKey(p));
+ Thread.sleep(1000);
+ assertTrue(cm.containsKey(p));
+ Thread.sleep(1000);
+ assertTrue(cm.containsKey(p));
+ Thread.sleep(3000);
+ assertFalse(cm.containsKey(p));
+ }
+
+ public void testCacheLifespanExpiration() throws Exception
+ {
+ Principal p = new SimplePrincipal("jduke");
+ AppCallbackHandler acbh = new AppCallbackHandler("jduke", "theduke".toCharArray());
+ AuthenticationManager am = new JBossCachedAuthenticationManager("test", acbh);
+
+ EmbeddedCacheManager cacheManager = new DefaultCacheManager();
+ org.infinispan.config.Configuration configuration = new org.infinispan.config.Configuration();
+ configuration.setExpirationMaxIdle(2000);
+ configuration.setExpirationLifespan(3000);
+ cacheManager.defineConfiguration("test", configuration);
+ Cache<Principal, DomainInfo> cache = cacheManager.getCache("test");
+ @SuppressWarnings("unchecked")
+ CacheableManager<Cache<Principal, DomainInfo>, Principal> cm = (CacheableManager<Cache<Principal, DomainInfo>, Principal>) am;
+ cm.setCache(cache);
+
+ assertTrue(am.isValid(p, "theduke"));
+ assertTrue(cm.containsKey(p));
+ Thread.sleep(1000);
+ assertTrue(cm.containsKey(p));
+ Thread.sleep(1000);
+ assertTrue(cm.containsKey(p));
+ Thread.sleep(1000);
+ assertFalse(cm.containsKey(p));
+ }
+
+ private void establishSecurityConfiguration()
+ {
+ SecurityActions.setJAASConfiguration((Configuration) new TestConfig());
+ }
+
+ public class TestConfig extends Configuration
+ {
+ @Override
+ public AppConfigurationEntry[] getAppConfigurationEntry(String name)
+ {
+ HashMap<String, Object> map = new HashMap<String, Object>();
+ map.put("usersProperties", "users.properties");
+ map.put("rolesProperties", "roles.properties");
+ String moduleName = "org.jboss.security.auth.spi.UsersRolesLoginModule";
+ AppConfigurationEntry ace = new AppConfigurationEntry(moduleName, LoginModuleControlFlag.REQUIRED, map);
+
+ return new AppConfigurationEntry[]
+ {ace};
+ }
+
+ @Override
+ public void refresh()
+ {
+ }
+ }
+}
Added: trunk/picketbox-infinispan/src/test/java/org/jboss/security/test/authentication/SecurityActions.java
===================================================================
--- trunk/picketbox-infinispan/src/test/java/org/jboss/security/test/authentication/SecurityActions.java (rev 0)
+++ trunk/picketbox-infinispan/src/test/java/org/jboss/security/test/authentication/SecurityActions.java 2011-03-31 14:09:00 UTC (rev 180)
@@ -0,0 +1,77 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2007, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.security.test.authentication;
+
+import java.security.AccessController;
+import java.security.Principal;
+import java.security.PrivilegedAction;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.Configuration;
+import javax.security.jacc.PolicyContext;
+
+//$Id$
+
+/**
+ * Privileged Blocks
+ * @author Anil.Saldhana at redhat.com
+ * @since Sep 25, 2007
+ * @version $Revision$
+ */
+public class SecurityActions
+{
+ public static void addPrincipalToSubject(final Subject subj, final Principal p)
+ {
+ AccessController.doPrivileged(new PrivilegedAction<Object>()
+ {
+ public Object run()
+ {
+ subj.getPrincipals().add(p);
+ return null;
+ }
+ });
+ }
+
+ public static void setJAASConfiguration(final Configuration configuration)
+ {
+ AccessController.doPrivileged(new PrivilegedAction<Object>()
+ {
+ public Object run()
+ {
+ Configuration.setConfiguration(configuration);
+ return null;
+ }
+ });
+ }
+
+ public static void setPolicyContextID(final String contextID)
+ {
+ AccessController.doPrivileged(new PrivilegedAction<Object>()
+ {
+ public Object run()
+ {
+ PolicyContext.setContextID(contextID);
+ return null;
+ }
+ });
+ }
+}
Added: trunk/picketbox-infinispan/src/test/resources/roles.properties
===================================================================
--- trunk/picketbox-infinispan/src/test/resources/roles.properties (rev 0)
+++ trunk/picketbox-infinispan/src/test/resources/roles.properties 2011-03-31 14:09:00 UTC (rev 180)
@@ -0,0 +1,12 @@
+scott=Echo
+stark=Java,Coder
+stark.CallerPrincipal=callerStark
+
+starksm.Roles=ProjectUser
+starksm.CallerPrincipal=callerStarksm
+scott.Roles=ProjectUser
+scott.CallerPrincipal=callerScott
+
+jduke=Role1,Role2
+jdukeman=Role2,Role3
+jdukeman.CallerPrincipal=callerJdukeman
\ No newline at end of file
Added: trunk/picketbox-infinispan/src/test/resources/users.properties
===================================================================
--- trunk/picketbox-infinispan/src/test/resources/users.properties (rev 0)
+++ trunk/picketbox-infinispan/src/test/resources/users.properties 2011-03-31 14:09:00 UTC (rev 180)
@@ -0,0 +1,4 @@
+scott=echoman
+stark=javaman
+jduke=theduke
+jdukeman=anotherduke
\ No newline at end of file
Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml 2011-03-31 13:49:41 UTC (rev 179)
+++ trunk/pom.xml 2011-03-31 14:09:00 UTC (rev 180)
@@ -18,6 +18,7 @@
<module>security-spi</module>
<module>security-jboss-sx</module>
<module>picketbox</module>
+ <module>picketbox-infinispan</module>
<module>assembly</module>
</modules>
</project>
More information about the jboss-cvs-commits
mailing list