[seam-commits] Seam SVN: r12453 - modules/security/trunk/impl/src/main/java/org/jboss/seam/security.

seam-commits at lists.jboss.org seam-commits at lists.jboss.org
Tue Apr 13 06:40:41 EDT 2010


Author: shane.bryzak at jboss.com
Date: 2010-04-13 06:40:40 -0400 (Tue, 13 Apr 2010)
New Revision: 12453

Added:
   modules/security/trunk/impl/src/main/java/org/jboss/seam/security/Authenticator.java
   modules/security/trunk/impl/src/main/java/org/jboss/seam/security/AuthorizationException.java
   modules/security/trunk/impl/src/main/java/org/jboss/seam/security/Credentials.java
   modules/security/trunk/impl/src/main/java/org/jboss/seam/security/EntityAction.java
   modules/security/trunk/impl/src/main/java/org/jboss/seam/security/EntityPermissionChecker.java
   modules/security/trunk/impl/src/main/java/org/jboss/seam/security/EntitySecurityListener.java
   modules/security/trunk/impl/src/main/java/org/jboss/seam/security/HibernateSecurityInterceptor.java
   modules/security/trunk/impl/src/main/java/org/jboss/seam/security/JaasConfiguration.java
   modules/security/trunk/impl/src/main/java/org/jboss/seam/security/JpaTokenStore.java
   modules/security/trunk/impl/src/main/java/org/jboss/seam/security/NotLoggedInException.java
   modules/security/trunk/impl/src/main/java/org/jboss/seam/security/RememberMe.java
   modules/security/trunk/impl/src/main/java/org/jboss/seam/security/RequestSecurityState.java
   modules/security/trunk/impl/src/main/java/org/jboss/seam/security/Role.java
   modules/security/trunk/impl/src/main/java/org/jboss/seam/security/RunAsOperation.java
   modules/security/trunk/impl/src/main/java/org/jboss/seam/security/Secure.java
   modules/security/trunk/impl/src/main/java/org/jboss/seam/security/SecurityEventMessages.java
   modules/security/trunk/impl/src/main/java/org/jboss/seam/security/SecurityException.java
   modules/security/trunk/impl/src/main/java/org/jboss/seam/security/SecurityInterceptor.java
   modules/security/trunk/impl/src/main/java/org/jboss/seam/security/SimpleGroup.java
   modules/security/trunk/impl/src/main/java/org/jboss/seam/security/SimplePrincipal.java
   modules/security/trunk/impl/src/main/java/org/jboss/seam/security/TokenStore.java
Log:
added classes


Added: modules/security/trunk/impl/src/main/java/org/jboss/seam/security/Authenticator.java
===================================================================
--- modules/security/trunk/impl/src/main/java/org/jboss/seam/security/Authenticator.java	                        (rev 0)
+++ modules/security/trunk/impl/src/main/java/org/jboss/seam/security/Authenticator.java	2010-04-13 10:40:40 UTC (rev 12453)
@@ -0,0 +1,11 @@
+package org.jboss.seam.security;
+
+/**
+ * Authenticator bean type
+ *  
+ * @author Shane Bryzak
+ */
+public interface Authenticator
+{
+   boolean authenticate();
+}

Added: modules/security/trunk/impl/src/main/java/org/jboss/seam/security/AuthorizationException.java
===================================================================
--- modules/security/trunk/impl/src/main/java/org/jboss/seam/security/AuthorizationException.java	                        (rev 0)
+++ modules/security/trunk/impl/src/main/java/org/jboss/seam/security/AuthorizationException.java	2010-04-13 10:40:40 UTC (rev 12453)
@@ -0,0 +1,16 @@
+package org.jboss.seam.security;
+
+/**
+ * Thrown when an authenticated user has insufficient rights to carry out an action.
+ * 
+ * @author Shane Bryzak
+ */
+public class AuthorizationException extends SecurityException
+{ 
+   private static final long serialVersionUID = -981091398588455903L;
+
+   public AuthorizationException(String message)
+   {
+      super(message);
+   }
+}

Added: modules/security/trunk/impl/src/main/java/org/jboss/seam/security/Credentials.java
===================================================================
--- modules/security/trunk/impl/src/main/java/org/jboss/seam/security/Credentials.java	                        (rev 0)
+++ modules/security/trunk/impl/src/main/java/org/jboss/seam/security/Credentials.java	2010-04-13 10:40:40 UTC (rev 12453)
@@ -0,0 +1,103 @@
+package org.jboss.seam.security;
+
+import java.io.Serializable;
+
+import javax.enterprise.context.SessionScoped;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.jboss.seam.security.events.CredentialsInitializedEvent;
+import org.jboss.seam.security.events.CredentialsUpdatedEvent;
+
+ at Named//("org.jboss.seam.security.credentials")
+ at SessionScoped
+public class Credentials implements Serializable
+{
+   private static final long serialVersionUID = -2271248957776488426L;
+   
+   @Inject BeanManager manager;
+   
+   private String username;
+   private String password;
+   
+   private boolean invalid;
+   
+   private boolean initialized;
+   
+   public Credentials() {}
+   
+   public boolean isInitialized()
+   {
+      return initialized;
+   }
+   
+   public void setInitialized(boolean initialized)
+   {
+      this.initialized = initialized;
+   }
+   
+   public String getUsername()
+   {
+      if (!isInitialized())
+      {
+         setInitialized(true);
+         manager.fireEvent(new CredentialsInitializedEvent(this));
+      }
+      
+      return username;
+   }
+   
+   public void setUsername(String username)
+   {
+      if (this.username != username && (this.username == null || !this.username.equals(username)))
+      {
+         this.username = username;
+         invalid = false;
+         manager.fireEvent(new CredentialsUpdatedEvent());
+      }
+   }
+   
+   public String getPassword()
+   {
+      return password;
+   }
+   
+   public void setPassword(String password)
+   {
+      if (this.password != password && (this.password == null || !this.password.equals(password)))
+      {
+         this.password = password;
+         invalid = false;
+         manager.fireEvent(new CredentialsUpdatedEvent());
+      }
+   }
+   
+   public boolean isSet()
+   {
+      return getUsername() != null && password != null;
+   }
+   
+   public boolean isInvalid()
+   {
+      return invalid;
+   }
+   
+   public void invalidate()
+   {
+      invalid = true;
+   }
+   
+   public void clear()
+   {
+      username = null;
+      password = null;
+      initialized = false;
+   }
+   
+   @Override
+   public String toString()
+   {
+      return "Credentials[" + username + "]";
+   }
+}

Added: modules/security/trunk/impl/src/main/java/org/jboss/seam/security/EntityAction.java
===================================================================
--- modules/security/trunk/impl/src/main/java/org/jboss/seam/security/EntityAction.java	                        (rev 0)
+++ modules/security/trunk/impl/src/main/java/org/jboss/seam/security/EntityAction.java	2010-04-13 10:40:40 UTC (rev 12453)
@@ -0,0 +1,23 @@
+package org.jboss.seam.security;
+
+/**
+ * Actions that may be performed upon entities
+ * in JPA or Hibernate.
+ * 
+ * @author Shane Bryzak
+ * 
+ */
+public enum EntityAction { 
+   
+   READ, 
+   INSERT, 
+   UPDATE, 
+   DELETE;
+   
+   @Override
+   public String toString()
+   {
+      return super.name().toLowerCase();
+   }
+   
+}
\ No newline at end of file

Added: modules/security/trunk/impl/src/main/java/org/jboss/seam/security/EntityPermissionChecker.java
===================================================================
--- modules/security/trunk/impl/src/main/java/org/jboss/seam/security/EntityPermissionChecker.java	                        (rev 0)
+++ modules/security/trunk/impl/src/main/java/org/jboss/seam/security/EntityPermissionChecker.java	2010-04-13 10:40:40 UTC (rev 12453)
@@ -0,0 +1,87 @@
+package org.jboss.seam.security;
+
+import javax.enterprise.context.ApplicationScoped;
+
+/**
+ * Entity permission checks
+ * 
+ * @author Shane Bryzak
+ */
+ at ApplicationScoped
+public class EntityPermissionChecker
+{
+   /*
+   private String entityManagerName = "entityManager";
+  
+   @Current Manager manager;
+   
+   private EntityManager getEntityManager()
+   {
+      return (EntityManager) Component.getInstance(entityManagerName);
+   }
+   
+   public String getEntityManagerName()
+   {
+      return entityManagerName;
+   }
+   
+   public void setEntityManagerName(String name)
+   {
+      this.entityManagerName = name;
+   }
+   
+   public void checkEntityPermission(Object entity, EntityAction action)
+   {
+      if (!Identity.isSecurityEnabled()) return;
+      
+      Identity identity = manager.getInstanceByType(Identity.class);
+      identity.tryLogin();
+      
+      PersistenceProvider provider = manager.getInstanceByType(PersistenceProvider.class);
+      
+      Class beanClass = provider.getBeanClass(entity);
+      
+      if (beanClass != null)
+      {
+         Method m = null;
+         switch (action)
+         {
+            case READ:
+               m = provider.getPostLoadMethod(entity, getEntityManager());
+               break;
+            case INSERT:
+               m = provider.getPrePersistMethod(entity, getEntityManager());
+               break;
+            case UPDATE:
+               m = provider.getPreUpdateMethod(entity, getEntityManager());
+               break;
+            case DELETE:
+               m = provider.getPreRemoveMethod(entity, getEntityManager());
+         }
+         
+         Restrict restrict = null;
+         
+         if (m != null && m.isAnnotationPresent(Restrict.class))
+         {
+            restrict = m.getAnnotation(Restrict.class);
+         }
+         else if (entity.getClass().isAnnotationPresent(Restrict.class))
+         {
+            restrict = entity.getClass().getAnnotation(Restrict.class);
+         }
+
+         if (restrict != null)
+         {
+            if (Strings.isEmpty(restrict.value()))
+            {
+               identity.checkPermission(entity, action.toString());
+            }
+            else
+            {
+               identity.checkRestriction(restrict.value());
+            }
+         }
+      }
+   }
+   */
+}

Added: modules/security/trunk/impl/src/main/java/org/jboss/seam/security/EntitySecurityListener.java
===================================================================
--- modules/security/trunk/impl/src/main/java/org/jboss/seam/security/EntitySecurityListener.java	                        (rev 0)
+++ modules/security/trunk/impl/src/main/java/org/jboss/seam/security/EntitySecurityListener.java	2010-04-13 10:40:40 UTC (rev 12453)
@@ -0,0 +1,46 @@
+package org.jboss.seam.security;
+
+import static org.jboss.seam.security.EntityAction.DELETE;
+import static org.jboss.seam.security.EntityAction.INSERT;
+import static org.jboss.seam.security.EntityAction.READ;
+import static org.jboss.seam.security.EntityAction.UPDATE;
+
+import javax.persistence.PostLoad;
+import javax.persistence.PrePersist;
+import javax.persistence.PreRemove;
+import javax.persistence.PreUpdate;
+
+
+/**
+ * Facilitates security checks for entity beans.
+ * 
+ * @author Shane Bryzak
+ */
+public class EntitySecurityListener
+{
+   /*
+   @PostLoad
+   public void postLoad(Object entity)
+   {
+      EntityPermissionChecker.instance().checkEntityPermission(entity, READ);
+   }
+   
+   @PrePersist
+   public void prePersist(Object entity)
+   { 
+      EntityPermissionChecker.instance().checkEntityPermission(entity, INSERT);
+   }
+   
+   @PreUpdate
+   public void preUpdate(Object entity)
+   {
+      EntityPermissionChecker.instance().checkEntityPermission(entity, UPDATE);
+   }
+   
+   @PreRemove
+   public void preRemove(Object entity)
+   {
+      EntityPermissionChecker.instance().checkEntityPermission(entity, DELETE);
+   }
+   */
+}

Added: modules/security/trunk/impl/src/main/java/org/jboss/seam/security/HibernateSecurityInterceptor.java
===================================================================
--- modules/security/trunk/impl/src/main/java/org/jboss/seam/security/HibernateSecurityInterceptor.java	                        (rev 0)
+++ modules/security/trunk/impl/src/main/java/org/jboss/seam/security/HibernateSecurityInterceptor.java	2010-04-13 10:40:40 UTC (rev 12453)
@@ -0,0 +1,102 @@
+package org.jboss.seam.security;
+
+import static org.jboss.seam.security.EntityAction.DELETE;
+import static org.jboss.seam.security.EntityAction.INSERT;
+import static org.jboss.seam.security.EntityAction.READ;
+import static org.jboss.seam.security.EntityAction.UPDATE;
+
+import java.io.Serializable;
+
+import org.hibernate.EmptyInterceptor;
+import org.hibernate.Interceptor;
+import org.hibernate.type.Type;
+//import org.jboss.seam.Entity.NotEntityException;
+
+/**
+ * Facilitates security checks for Hibernate entities
+ * 
+ * @author Shane Bryzak
+ *
+ */
+public class HibernateSecurityInterceptor extends EmptyInterceptor
+{
+   /*
+   private Interceptor wrappedInterceptor;
+   
+   public HibernateSecurityInterceptor(Interceptor wrappedInterceptor)
+   {
+      this.wrappedInterceptor = wrappedInterceptor;
+   }
+   
+   @Override
+   public boolean onLoad(Object entity, Serializable id, Object[] state,
+                      String[] propertyNames, Type[] types)
+   {
+      try
+      {
+         EntityPermissionChecker.instance().checkEntityPermission(entity, READ);
+      }
+      catch (NotEntityException e) 
+      {
+         // Not a JPA entity
+      }
+      
+      return wrappedInterceptor != null ? 
+               wrappedInterceptor.onLoad(entity, id, state, propertyNames, types) : 
+               false;
+   }
+   
+   @Override
+   public void onDelete(Object entity, Serializable id, Object[] state, 
+                        String[] propertyNames, Type[] types)
+   {
+      try
+      {
+         EntityPermissionChecker.instance().checkEntityPermission(entity, DELETE);
+      }
+      catch (NotEntityException e) 
+      {
+         // Not a JPA entity
+      }
+      
+      if (wrappedInterceptor != null)
+         wrappedInterceptor.onDelete(entity, id, state, propertyNames, types);
+   }
+   
+   @Override
+   public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState,
+                   Object[] previousState, String[] propertyNames, Type[] types)
+   {
+      try
+      {
+         EntityPermissionChecker.instance().checkEntityPermission(entity, UPDATE);
+      }
+      catch (NotEntityException e) 
+      {
+         // Not a JPA entity
+      }
+      
+      return wrappedInterceptor != null ? 
+               wrappedInterceptor.onFlushDirty(entity, id, currentState, 
+                        previousState, propertyNames, types) : false;
+   }
+   
+   @Override
+   public boolean onSave(Object entity, Serializable id, Object[] state,
+                      String[] propertyNames, Type[] types)
+   {
+      try
+      {
+         EntityPermissionChecker.instance().checkEntityPermission(entity, INSERT);
+      }
+      catch (NotEntityException e) 
+      {
+         // Not a JPA entity
+      }
+      
+      return wrappedInterceptor != null ? 
+               wrappedInterceptor.onSave(entity, id, state, propertyNames, types) : 
+               false;
+   }
+   */       
+}

Added: modules/security/trunk/impl/src/main/java/org/jboss/seam/security/JaasConfiguration.java
===================================================================
--- modules/security/trunk/impl/src/main/java/org/jboss/seam/security/JaasConfiguration.java	                        (rev 0)
+++ modules/security/trunk/impl/src/main/java/org/jboss/seam/security/JaasConfiguration.java	2010-04-13 10:40:40 UTC (rev 12453)
@@ -0,0 +1,53 @@
+package org.jboss.seam.security;
+
+import java.util.HashMap;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Produces;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
+
+import org.jboss.seam.security.jaas.SeamLoginModule;
+
+/**
+ * Producer for the JAAS Configuration used by Seam Security.
+ * 
+ * @author Shane Bryzak
+ *
+ */
+public class JaasConfiguration
+{
+   static final String DEFAULT_JAAS_CONFIG_NAME = "default";
+
+   protected Configuration createConfiguration()
+   {
+      return new Configuration()
+      {
+         private AppConfigurationEntry[] aces = { createAppConfigurationEntry() };
+         
+         @Override
+         public AppConfigurationEntry[] getAppConfigurationEntry(String name)
+         {
+            return DEFAULT_JAAS_CONFIG_NAME.equals(name) ? aces : null;
+         }
+         
+         @Override
+         public void refresh() {}
+      };
+   }
+
+   protected AppConfigurationEntry createAppConfigurationEntry()
+   {
+      return new AppConfigurationEntry(
+            SeamLoginModule.class.getName(),
+            LoginModuleControlFlag.REQUIRED,
+            new HashMap<String,String>()
+         );
+   }
+   
+   @Produces @ApplicationScoped Configuration getConfiguration()
+   {
+      return createConfiguration();
+   }
+}

Added: modules/security/trunk/impl/src/main/java/org/jboss/seam/security/JpaTokenStore.java
===================================================================
--- modules/security/trunk/impl/src/main/java/org/jboss/seam/security/JpaTokenStore.java	                        (rev 0)
+++ modules/security/trunk/impl/src/main/java/org/jboss/seam/security/JpaTokenStore.java	2010-04-13 10:40:40 UTC (rev 12453)
@@ -0,0 +1,145 @@
+package org.jboss.seam.security;
+
+import java.io.Serializable;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import javax.enterprise.inject.Instance;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
+import javax.persistence.Query;
+
+import org.jboss.seam.security.annotations.TokenUsername;
+import org.jboss.seam.security.annotations.TokenValue;
+import org.jboss.seam.security.management.IdentityManagementException;
+import org.jboss.seam.security.util.AnnotatedBeanProperty;
+
+/**
+ * A TokenStore implementation, stores tokens inside a database table.
+ * 
+ * @author Shane Bryzak
+ */
+ at ApplicationScoped
+public class JpaTokenStore implements TokenStore, Serializable
+{
+   private static final long serialVersionUID = -1984227349549914828L;
+
+   private Class<?> tokenEntityClass;
+   
+   private AnnotatedBeanProperty<TokenUsername> tokenUsernameProperty;
+   private AnnotatedBeanProperty<TokenValue> tokenValueProperty;
+   
+   @Inject BeanManager manager;
+   
+   @Inject Instance<EntityManager> entityManagerInstance;
+   
+   @Inject
+   public void create()
+   {
+      tokenUsernameProperty = new AnnotatedBeanProperty<TokenUsername>(tokenEntityClass, TokenUsername.class);
+      tokenValueProperty = new AnnotatedBeanProperty<TokenValue>(tokenEntityClass, TokenValue.class);
+      
+      if (!tokenUsernameProperty.isSet())
+      {
+         throw new IllegalStateException("Invalid tokenClass " + tokenEntityClass.getName() +
+               " - required annotation @TokenUsername not found on any Field or Method.");
+      }
+      
+      if (!tokenValueProperty.isSet())
+      {
+         throw new IllegalStateException("Invalid tokenClass " + tokenEntityClass.getName() +
+               " - required annotation @TokenValue not found on any Field or Method.");
+      }
+   }
+   
+   public void createToken(String username, String value)
+   {
+      if (tokenEntityClass == null)
+      {
+         throw new IllegalStateException("Could not create token, tokenEntityClass not set");
+      }
+      
+      try
+      {
+         Object token = tokenEntityClass.newInstance();
+         
+         tokenUsernameProperty.setValue(token, username);
+         tokenValueProperty.setValue(token, value);
+         
+         lookupEntityManager().persist(token);
+      }
+      catch (Exception ex)
+      {
+         if (ex instanceof IdentityManagementException)
+         {
+            throw (IdentityManagementException) ex;
+         }
+         else
+         {
+            throw new IdentityManagementException("Could not create account", ex);
+         }
+      }
+   }
+   
+   public boolean validateToken(String username, String value)
+   {
+      return lookupToken(username, value) != null;
+   }
+   
+   public void invalidateToken(String username, String value)
+   {
+      Object token = lookupToken(username, value);
+      if (token != null)
+      {
+         lookupEntityManager().remove(token);
+      }
+   }
+   
+   public void invalidateAll(String username)
+   {
+      Query query = lookupEntityManager().createQuery(
+         "select t from " + tokenEntityClass.getName() + " t where " + tokenUsernameProperty.getName() +
+         " = :username")
+         .setParameter("username", username);
+      
+      for (Object token : query.getResultList())
+      {
+         lookupEntityManager().remove(token);
+      }
+   }
+   
+   public Object lookupToken(String username, String value)
+   {
+      try
+      {
+         Object token = lookupEntityManager().createQuery(
+            "select t from " + tokenEntityClass.getName() + " t where " + tokenUsernameProperty.getName() +
+            " = :username and " + tokenValueProperty.getName() + " = :value")
+            .setParameter("username", username)
+            .setParameter("value", value)
+            .getSingleResult();
+         
+         return token;
+      }
+      catch (NoResultException ex)
+      {
+         return null;
+      }
+   }
+   
+   public Class<?> getTokenEntityClass()
+   {
+      return tokenEntityClass;
+   }
+   
+   public void setTokenEntityClass(Class<?> tokenEntityClass)
+   {
+      this.tokenEntityClass = tokenEntityClass;
+   }
+   
+   private EntityManager lookupEntityManager()
+   {
+      return entityManagerInstance.get();
+   }
+}

Added: modules/security/trunk/impl/src/main/java/org/jboss/seam/security/NotLoggedInException.java
===================================================================
--- modules/security/trunk/impl/src/main/java/org/jboss/seam/security/NotLoggedInException.java	                        (rev 0)
+++ modules/security/trunk/impl/src/main/java/org/jboss/seam/security/NotLoggedInException.java	2010-04-13 10:40:40 UTC (rev 12453)
@@ -0,0 +1,11 @@
+package org.jboss.seam.security;
+
+//import javax.ejb.ApplicationException;
+
+/**
+ * Thrown when an unauthenticated user attempts to execute a restricted action. 
+ * 
+ * @author Shane Bryzak
+ */
+//@ApplicationException(rollback=true)
+public class NotLoggedInException extends SecurityException {}

Added: modules/security/trunk/impl/src/main/java/org/jboss/seam/security/RememberMe.java
===================================================================
--- modules/security/trunk/impl/src/main/java/org/jboss/seam/security/RememberMe.java	                        (rev 0)
+++ modules/security/trunk/impl/src/main/java/org/jboss/seam/security/RememberMe.java	2010-04-13 10:40:40 UTC (rev 12453)
@@ -0,0 +1,361 @@
+package org.jboss.seam.security;
+
+import java.io.Serializable;
+import java.rmi.server.UID;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import javax.enterprise.context.SessionScoped;
+import javax.enterprise.event.Observes;
+import javax.inject.Inject;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.inject.Named;
+
+import org.jboss.seam.security.events.CredentialsInitializedEvent;
+import org.jboss.seam.security.events.LoggedOutEvent;
+import org.jboss.seam.security.events.PostAuthenticateEvent;
+import org.jboss.seam.security.events.QuietLoginEvent;
+import org.jboss.seam.security.management.IdentityManager;
+import org.jboss.seam.security.util.Base64;
+//import org.jboss.seam.web.ManagedCookie;
+
+/**
+ * Remember-me functionality is provided by this class, in two different flavours.  The first mode
+ * provides username-only persistence, and is considered to be secure as the user (or their browser)
+ * is still required to provide a password.  The second mode provides an auto-login feature, however
+ * is NOT considered to be secure and is vulnerable to XSS attacks compromising the user's account.
+ * 
+ * Use the auto-login mode with caution!
+ * 
+ * 
+ * @author Shane Bryzak
+ */
+ at Named
+ at SessionScoped
+public class RememberMe implements Serializable
+{
+   private static final long serialVersionUID = 2242379431576068199L;
+   
+   public enum Mode { disabled, usernameOnly, autoLogin}
+
+   @Inject BeanManager manager;
+   @Inject Identity identity;
+   @Inject Credentials credentials;
+   @Inject IdentityManager identityManager;
+   
+   // Heaps of stuff commented out here because we need to add generic cookie support
+
+   //private ManagedCookie usernameSelector;
+   //private ManagedCookie tokenSelector;
+   
+   private TokenStore tokenStore;
+   
+   private boolean enabled;
+
+   //private int cookieMaxAge = ManagedCookie.DEFAULT_MAX_AGE;
+   
+   private boolean autoLoggedIn;
+   
+   private Random random = new Random(System.currentTimeMillis());
+   
+   private Mode mode = Mode.usernameOnly;
+   
+   public RememberMe() {}
+   
+   /*
+   public
+   @Inject
+   void create()
+   {
+      if (mode.equals(Mode.usernameOnly))
+      {
+         usernameSelector = (ManagedCookie) BeanManagerHelper.getInstanceByType(manager, ManagedCookie.class);
+         usernameSelector.setCookieName("org.jboss.seam.security.username");
+         usernameSelector.setCookieEnabled(enabled);
+      }
+      else if (mode.equals(Mode.autoLogin))
+      {
+         tokenSelector = (ManagedCookie) BeanManagerHelper.getInstanceByType(manager, ManagedCookie.class);
+         tokenSelector.setCookieName("org.jboss.seam.security.authtoken");
+         tokenSelector.setCookieEnabled(enabled);
+         
+         // Default to JpaTokenStore
+         if (tokenStore == null)
+         {
+            tokenStore = BeanManagerHelper.getInstanceByType(manager,JpaTokenStore.class);
+         }
+      }
+   }
+     
+   public void initCredentials(@Observes CredentialsInitializedEvent event)
+   {
+      // FIXME use the context path as the cookie path
+      // String cookiePath = getCookiePath();
+      String cookiePath = "/";
+      
+      if (mode.equals(Mode.usernameOnly))
+      {
+         if (cookiePath != null)
+         {
+            usernameSelector.setCookiePath(cookiePath);
+         }
+         
+         String username = usernameSelector.getCookieValue();
+         if (username!=null)
+         {
+            setEnabled(true);
+            event.getCredentials().setUsername(username);
+         }
+      }
+      else if (mode.equals(Mode.autoLogin))
+      {
+         if (cookiePath != null)
+         {
+            tokenSelector.setCookiePath(cookiePath);
+         }
+         
+         String token = tokenSelector.getCookieValue();
+         if (token != null)
+         {
+            setEnabled(true);
+            
+            DecodedToken decoded = new DecodedToken(token);
+
+            if (tokenStore.validateToken(decoded.getUsername(), decoded.getValue()))
+            {
+               event.getCredentials().setUsername(decoded.getUsername());
+               event.getCredentials().setPassword(decoded.getValue());
+            }
+            else
+            {
+               // Have we been compromised? Just in case, invalidate all authentication tokens
+               tokenStore.invalidateAll(decoded.getUsername());
+            }
+         }
+      }
+   }*/
+
+   public void quietLogin(@Observes QuietLoginEvent event)
+   {
+      if (mode.equals(Mode.autoLogin) && isEnabled())
+      {
+         final String username = credentials.getUsername();
+         final BoolWrapper userEnabled = new BoolWrapper();
+         final List<String> roles = new ArrayList<String>();
+         
+         // Double check our credentials again
+         if (tokenStore.validateToken(username, credentials.getPassword()))
+         {
+            identity.runAs(new RunAsOperation(true) {
+               @Override
+               public void execute()
+               {
+                  if (identityManager.isUserEnabled(username))
+                  {
+                     userEnabled.value = true;
+
+                     for (String role : identityManager.getImpliedRoles(username))
+                     {
+                        roles.add(role);
+                     }
+                  }
+               }
+            });
+            
+            if (userEnabled.value)
+            {
+               identity.unAuthenticate();
+               identity.preAuthenticate();
+               
+               // populate the roles
+               for (String role : roles)
+               {
+                  identity.addRole(role);
+               }
+   
+               // Set the principal
+               identity.getSubject().getPrincipals().add(new SimplePrincipal(username));
+               identity.postAuthenticate();
+            
+               autoLoggedIn = true;
+            }
+         }
+      }
+   }
+   /*
+   public void postAuthenticate(@Observes PostAuthenticateEvent event)
+   {
+      if (mode.equals(Mode.usernameOnly))
+      {
+         if ( !enabled )
+         {
+            usernameSelector.clearCookieValue();
+         }
+         else
+         {
+            usernameSelector.setCookieMaxAge(cookieMaxAge);
+            usernameSelector.setCookieValueIfEnabled( credentials.getUsername() );
+         }
+      }
+      else if (mode.equals(Mode.autoLogin))
+      {
+         DecodedToken decoded = new DecodedToken(tokenSelector.getCookieValue());
+         
+         // Invalidate the current token (if it exists) whether enabled or not
+         if (decoded.getUsername() != null)
+         {
+            tokenStore.invalidateToken(decoded.getUsername(), decoded.getValue());
+         }
+         
+         if ( !enabled )
+         {
+            tokenSelector.clearCookieValue();
+         }
+         else
+         {
+            String value = generateTokenValue();
+            tokenStore.createToken(identity.getPrincipal().getName(), value);
+            tokenSelector.setCookieEnabled(enabled);
+            tokenSelector.setCookieMaxAge(cookieMaxAge);
+            tokenSelector.setCookieValueIfEnabled(encodeToken(identity.getPrincipal().getName(), value));
+         }
+      }
+   }
+   */
+   
+   /*
+   public void loggedOut(@Observes LoggedOutEvent event)
+   {
+      if (mode.equals(Mode.autoLogin))
+      {
+         tokenSelector.clearCookieValue();
+      }
+   }*/
+
+   public Mode getMode()
+   {
+      return mode;
+   }
+   
+   public void setMode(Mode mode)
+   {
+      this.mode = mode;
+   }
+   
+   public boolean isEnabled()
+   {
+      return enabled;
+   }
+   
+   public void setEnabled(boolean enabled)
+   {
+      this.enabled = enabled;
+   }
+   
+   /*
+   public void setEnabled(boolean enabled)
+   {
+      if (this.enabled != enabled)
+      {
+         this.enabled = enabled;
+         // selector is null during component initialization (setup handled in @Create method)
+         if (usernameSelector != null && mode.equals(Mode.usernameOnly))
+         {
+            usernameSelector.setCookieEnabled(enabled);
+         }
+         // selector is null during component initialization (setup handled in @Create method)
+         else if (tokenSelector != null && mode.equals(Mode.autoLogin))
+         {
+            tokenSelector.setCookieEnabled(enabled);
+         }
+      }
+   }*/
+
+   /*
+   public int getCookieMaxAge() {
+       return cookieMaxAge;
+   }
+
+   public void setCookieMaxAge(int cookieMaxAge) {
+       this.cookieMaxAge = cookieMaxAge;
+   }*/
+   
+   public TokenStore getTokenStore()
+   {
+      return tokenStore;
+   }
+   
+   public void setTokenStore(TokenStore tokenStore)
+   {
+      this.tokenStore = tokenStore;
+   }
+   
+   /**
+    * A flag that an application can use to protect sensitive operations if the user has been
+    * auto-authenticated.
+    */
+   public boolean isAutoLoggedIn()
+   {
+      return autoLoggedIn;
+   }
+   
+   protected String generateTokenValue()
+   {
+      StringBuilder sb = new StringBuilder();
+      sb.append(new UID().toString());
+      sb.append(":");
+      sb.append(random.nextLong());
+      return sb.toString();
+   }
+   
+   protected String encodeToken(String username, String value)
+   {
+      StringBuilder sb = new StringBuilder();
+      sb.append(username);
+      sb.append(":");
+      sb.append(value);
+      return Base64.encodeBytes(sb.toString().getBytes());
+   }
+   
+   /**
+    * I hate these hacks...
+    */
+   private class BoolWrapper
+   {
+      boolean value;
+   }
+   
+   private class DecodedToken
+   {
+      private String username;
+      private String value;
+      
+      public DecodedToken(String cookieValue)
+      {
+         if (cookieValue != null)
+         {
+            try
+            {
+               String decoded = new String(Base64.decode(cookieValue));
+               username = decoded.substring(0, decoded.indexOf(':'));
+               value = decoded.substring(decoded.indexOf(':') + 1);
+            }
+            catch (Exception ex)
+            {
+               // intentionally swallow
+            }
+         }
+      }
+      
+      public String getUsername()
+      {
+         return username;
+      }
+      
+      public String getValue()
+      {
+         return value;
+      }
+   }
+}

Added: modules/security/trunk/impl/src/main/java/org/jboss/seam/security/RequestSecurityState.java
===================================================================
--- modules/security/trunk/impl/src/main/java/org/jboss/seam/security/RequestSecurityState.java	                        (rev 0)
+++ modules/security/trunk/impl/src/main/java/org/jboss/seam/security/RequestSecurityState.java	2010-04-13 10:40:40 UTC (rev 12453)
@@ -0,0 +1,35 @@
+package org.jboss.seam.security;
+
+import javax.enterprise.context.RequestScoped;
+
+/**
+ * Contains the authentication state of the current request
+ * 
+ * @author Shane Bryzak
+ */
+ at RequestScoped
+public class RequestSecurityState
+{
+   private boolean silentLogin;
+   private boolean loginTried;
+   
+   public boolean isSilentLogin()
+   {
+      return silentLogin;
+   }
+   
+   public void setSilentLogin(boolean silentLogin)
+   {
+      this.silentLogin = silentLogin;
+   }
+   
+   public boolean isLoginTried()
+   {
+      return loginTried;
+   }
+   
+   public void setLoginTried(boolean loginTried)
+   {
+      this.loginTried = loginTried;
+   }
+}

Added: modules/security/trunk/impl/src/main/java/org/jboss/seam/security/Role.java
===================================================================
--- modules/security/trunk/impl/src/main/java/org/jboss/seam/security/Role.java	                        (rev 0)
+++ modules/security/trunk/impl/src/main/java/org/jboss/seam/security/Role.java	2010-04-13 10:40:40 UTC (rev 12453)
@@ -0,0 +1,30 @@
+package org.jboss.seam.security;
+
+/**
+ * Represents a user role.  A conditional role is a special type of role that is assigned to a user
+ * based on the contextual state of a permission check.
+ *  
+ * @author Shane Bryzak
+ */
+public class Role extends SimplePrincipal
+{   
+   private static final long serialVersionUID = 1187276024036531700L;
+   
+   private boolean conditional;
+   
+   public Role(String name)
+   {
+      super(name);
+   }   
+   
+   public Role(String name, boolean conditional)
+   {
+      this(name);
+      this.conditional = conditional;
+   }
+   
+   public boolean isConditional()
+   {
+      return conditional;
+   }
+}

Added: modules/security/trunk/impl/src/main/java/org/jboss/seam/security/RunAsOperation.java
===================================================================
--- modules/security/trunk/impl/src/main/java/org/jboss/seam/security/RunAsOperation.java	                        (rev 0)
+++ modules/security/trunk/impl/src/main/java/org/jboss/seam/security/RunAsOperation.java	2010-04-13 10:40:40 UTC (rev 12453)
@@ -0,0 +1,72 @@
+package org.jboss.seam.security;
+
+import java.security.Principal;
+import java.security.acl.Group;
+
+import javax.security.auth.Subject;
+
+/**
+ * Defines a security operation that can be executed within a particular 
+ * security context.
+ * 
+ * @author Shane Bryzak
+ */
+public abstract class RunAsOperation
+{
+   private Principal principal;
+   private Subject subject;
+   
+   private boolean systemOp = false;
+      
+   public RunAsOperation()
+   {
+      principal = new SimplePrincipal(null);  
+      subject = new Subject();
+   }
+   
+   /**
+    * A system operation allows any security checks to pass
+    * 
+    * @param systemOp
+    */
+   public RunAsOperation(boolean systemOp)
+   {      
+      this();
+      this.systemOp = systemOp;
+   }
+   
+   public abstract void execute();
+   
+   public Principal getPrincipal()
+   {
+      return principal;
+   }
+   
+   public Subject getSubject()
+   {
+      return subject;
+   }
+   
+   public RunAsOperation addRole(String role)
+   {
+      for ( Group sg : getSubject().getPrincipals(Group.class) )      
+      {
+         if ( Identity.ROLES_GROUP.equals( sg.getName() ) )
+         {
+            sg.addMember(new SimplePrincipal(role));
+            break;
+         }
+      }
+               
+      SimpleGroup roleGroup = new SimpleGroup(Identity.ROLES_GROUP);
+      roleGroup.addMember(new SimplePrincipal(role));
+      getSubject().getPrincipals().add(roleGroup); 
+      
+      return this;
+   }
+   
+   public boolean isSystemOperation()
+   {
+      return systemOp;
+   }
+}

Added: modules/security/trunk/impl/src/main/java/org/jboss/seam/security/Secure.java
===================================================================
--- modules/security/trunk/impl/src/main/java/org/jboss/seam/security/Secure.java	                        (rev 0)
+++ modules/security/trunk/impl/src/main/java/org/jboss/seam/security/Secure.java	2010-04-13 10:40:40 UTC (rev 12453)
@@ -0,0 +1,24 @@
+package org.jboss.seam.security;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import javax.interceptor.InterceptorBinding;
+
+/**
+ * 
+ * @author Shane Bryzak
+ */
+ at Inherited
+ at InterceptorBinding
+ at Target({TYPE, METHOD})
+ at Retention(RUNTIME)
+public @interface Secure
+{
+
+}

Added: modules/security/trunk/impl/src/main/java/org/jboss/seam/security/SecurityEventMessages.java
===================================================================
--- modules/security/trunk/impl/src/main/java/org/jboss/seam/security/SecurityEventMessages.java	                        (rev 0)
+++ modules/security/trunk/impl/src/main/java/org/jboss/seam/security/SecurityEventMessages.java	2010-04-13 10:40:40 UTC (rev 12453)
@@ -0,0 +1,130 @@
+package org.jboss.seam.security;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import javax.enterprise.event.Observes;
+
+//import org.jboss.seam.international.StatusMessages;
+//import org.jboss.seam.international.StatusMessage.Severity;
+import org.jboss.seam.security.events.AlreadyLoggedInEvent;
+import org.jboss.seam.security.events.LoggedInEvent;
+import org.jboss.seam.security.events.LoginFailedEvent;
+import org.jboss.seam.security.events.NotLoggedInEvent;
+import org.jboss.seam.security.events.PostAuthenticateEvent;
+
+/**
+ * Produces FacesMessages in response of certain security events, and helps to
+ * decouple the Identity component from JSF.
+ * 
+ * @author Shane Bryzak
+ */
+public
+ at ApplicationScoped
+class SecurityEventMessages
+{
+   private static final String LOGIN_FAILED_MESSAGE_KEY = "org.jboss.seam.loginFailed";
+   private static final String LOGIN_SUCCESSFUL_MESSAGE_KEY = "org.jboss.seam.loginSuccessful";
+   private static final String ALREADY_LOGGED_IN_MESSAGE_KEY = "org.jboss.seam.alreadyLoggedIn";
+   private static final String NOT_LOGGED_IN_MESSAGE_KEY = "org.jboss.seam.notLoggedIn";
+   
+   private static final String DEFAULT_LOGIN_FAILED_MESSAGE = "Login failed.";
+   private static final String DEFAULT_LOGIN_SUCCESSFUL_MESSAGE = "Welcome, {0}.";
+   private static final String DEFAULT_ALREADY_LOGGED_IN_MESSAGE = "You're already logged in. Please log out first if you wish to log in again.";
+   private static final String DEFAULT_NOT_LOGGED_IN_MESSAGE = "Please log in first.";
+   
+   //@Inject StatusMessages statusMessages;
+   @Inject Credentials credentials;
+
+   public void postAuthenticate(@Observes PostAuthenticateEvent event)
+   {
+      // org.jboss.security.saml.SSOManager.processManualLoginNotification(
+      // ServletContexts.instance().getRequest(),
+      // identity.getPrincipal().getName());
+   }
+
+   public void addLoginFailedMessage(@Observes LoginFailedEvent event)
+   {
+      //statusMessages.addFromResourceBundleOrDefault(getLoginFailedMessageSeverity(), getLoginFailedMessageKey(), getDefaultLoginFailedMessage(), event.getLoginException());
+   }
+   
+   public void addLoginSuccessMessage(@Observes LoggedInEvent event)
+   {
+   //   statusMessages.addFromResourceBundleOrDefault(getLoginSuccessfulMessageSeverity(), getLoginSuccessfulMessageKey(), getDefaultLoginSuccessfulMessage(), credentials.getUsername());
+   }
+   
+   public void addAlreadyLoggedInMessage(@Observes AlreadyLoggedInEvent event)
+   {
+      //statusMessages.addFromResourceBundleOrDefault(getAlreadyLoggedInMessageSeverity(), getAlreadyLoggedInMessageKey(), getDefaultAlreadyLoggedInMessage());
+   }
+   
+   public void addNotLoggedInMessage(@Observes NotLoggedInEvent event)
+   {
+      //statusMessages.addFromResourceBundleOrDefault(getNotLoggedInMessageSeverity(), getNotLoggedInMessageKey(), getDefaultNotLoggedInMessage());
+   }
+   
+   // TODO the following methods should probably be moved to the seam-jsf module,
+   // or otherwise message severities should be abstracted in seam-international
+   
+   /*public Severity getLoginFailedMessageSeverity()
+   {
+      return Severity.INFO;
+   }
+
+   public Severity getLoginSuccessfulMessageSeverity()
+   {
+      return Severity.INFO;
+   }
+   
+   public Severity getAlreadyLoggedInMessageSeverity()
+   {
+      return Severity.INFO;
+   }
+      
+   public Severity getNotLoggedInMessageSeverity()
+   {
+      return Severity.WARN;
+   }
+*/   
+   
+   public String getLoginFailedMessageKey()
+   {
+      return LOGIN_FAILED_MESSAGE_KEY;
+   }
+
+   public String getDefaultLoginFailedMessage()
+   {
+      return DEFAULT_LOGIN_FAILED_MESSAGE;
+   }
+   
+   
+   public String getLoginSuccessfulMessageKey()
+   {
+      return LOGIN_SUCCESSFUL_MESSAGE_KEY;
+   }
+
+   public String getDefaultLoginSuccessfulMessage()
+   {
+      return DEFAULT_LOGIN_SUCCESSFUL_MESSAGE;
+   }
+
+   public String getAlreadyLoggedInMessageKey()
+   {
+      return ALREADY_LOGGED_IN_MESSAGE_KEY;
+   }
+   
+   public String getDefaultAlreadyLoggedInMessage()
+   {
+      return DEFAULT_ALREADY_LOGGED_IN_MESSAGE;
+   }
+   
+   public String getNotLoggedInMessageKey()
+   {
+      return NOT_LOGGED_IN_MESSAGE_KEY;
+   }
+   
+   public String getDefaultNotLoggedInMessage()
+   {
+      return DEFAULT_NOT_LOGGED_IN_MESSAGE;
+   }
+
+}

Added: modules/security/trunk/impl/src/main/java/org/jboss/seam/security/SecurityException.java
===================================================================
--- modules/security/trunk/impl/src/main/java/org/jboss/seam/security/SecurityException.java	                        (rev 0)
+++ modules/security/trunk/impl/src/main/java/org/jboss/seam/security/SecurityException.java	2010-04-13 10:40:40 UTC (rev 12453)
@@ -0,0 +1,31 @@
+package org.jboss.seam.security;
+
+/**
+ * Any exception that is raised by the security module extends from this runtime
+ * exception class, making it easy for other modules and extensions to catch all
+ * security-related exceptions in a single catch block, if need be.
+ * 
+ * @author Dan Allen
+ */
+public abstract class SecurityException extends RuntimeException
+{
+   public SecurityException()
+   {
+      super();
+   }
+
+   public SecurityException(String message, Throwable cause)
+   {
+      super(message, cause);
+   }
+
+   public SecurityException(String message)
+   {
+      super(message);
+   }
+
+   public SecurityException(Throwable cause)
+   {
+      super(cause);
+   }
+}

Added: modules/security/trunk/impl/src/main/java/org/jboss/seam/security/SecurityInterceptor.java
===================================================================
--- modules/security/trunk/impl/src/main/java/org/jboss/seam/security/SecurityInterceptor.java	                        (rev 0)
+++ modules/security/trunk/impl/src/main/java/org/jboss/seam/security/SecurityInterceptor.java	2010-04-13 10:40:40 UTC (rev 12453)
@@ -0,0 +1,302 @@
+package org.jboss.seam.security;
+
+import java.io.Serializable;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.inject.Inject;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.Interceptor;
+import javax.interceptor.InvocationContext;
+
+import org.jboss.seam.security.annotations.PermissionCheck;
+import org.jboss.seam.security.annotations.Restrict;
+import org.jboss.seam.security.annotations.RoleCheck;
+import org.jboss.seam.security.util.Strings;
+
+/**
+ * Provides authorization services for component invocations.
+ * 
+ * @author Shane Bryzak
+ */
+ at Secure @Interceptor
+public class SecurityInterceptor implements Serializable
+{
+   private static final long serialVersionUID = -6567750187000766925L;
+   
+   /**
+    * You may encounter a JVM bug where the field initializer is not evaluated for a transient field after deserialization.
+    * @see "http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6252102"
+    */
+   private transient volatile Map<Method,Restriction> restrictions = new HashMap<Method,Restriction>();
+   
+   @Inject BeanManager manager;
+   @Inject Identity identity;
+   
+   private class Restriction
+   {
+      private String expression;
+      
+      private String permissionTarget;
+      private String permissionAction;
+      
+      private Map<String, Object> methodRestrictions;
+      private Map<Integer,Set<String>> paramRestrictions;
+      private Set<String> roleRestrictions;
+            
+      public void setExpression(String expression)
+      {
+         this.expression = expression;
+      }
+      
+      public void setPermissionTarget(String target)
+      {
+         this.permissionTarget = target;
+      }
+      
+      public void setPermissionAction(String action)
+      {
+         this.permissionAction = action;
+      }
+      
+      public void addMethodRestriction(Object target, String action)
+      {
+         if (methodRestrictions == null)
+         {
+            methodRestrictions = new HashMap<String, Object>();
+         }
+         
+         methodRestrictions.put(action, target);
+      }
+      
+      public void addRoleRestriction(String role)
+      {
+         if (roleRestrictions == null)
+         {
+            roleRestrictions = new HashSet<String>();
+         }
+         
+         roleRestrictions.add(role);
+      }
+      
+      public void addParameterRestriction(int index, String action)
+      {
+         Set<String> actions = null;
+         
+         if (paramRestrictions == null)
+         {
+            paramRestrictions = new HashMap<Integer,Set<String>>();
+         }
+         
+         if (!paramRestrictions.containsKey(index))
+         {
+            actions = new HashSet<String>();
+            paramRestrictions.put(index, actions);
+         }
+         else
+         {
+            actions = paramRestrictions.get(index);
+         }
+         
+         actions.add(action);
+      }
+      
+      public void check(Identity identity, Object[] parameters)
+      {
+         if (Identity.isSecurityEnabled())
+         {
+            // TODO rewrite EL based restrictions
+            /*if (expression != null)
+            {
+               identity.checkRestriction(expression);
+            }*/
+            
+            if (methodRestrictions != null)
+            {
+               for (String action : methodRestrictions.keySet())
+               {
+                  identity.checkPermission(methodRestrictions.get(action), action);
+               }
+            }
+            
+            if (paramRestrictions != null)
+            {
+               for (Integer idx : paramRestrictions.keySet())
+               {
+                  Set<String> actions = paramRestrictions.get(idx);
+                  for (String action : actions)
+                  {
+                     identity.checkPermission(parameters[idx], action);
+                  }
+               }
+            }
+            
+            if (roleRestrictions != null)
+            {
+               for (String role : roleRestrictions)
+               {
+                  identity.checkRole(role);
+               }
+            }
+            
+            if (permissionTarget != null && permissionAction != null)
+            {
+               identity.checkPermission(permissionTarget, permissionAction);
+            }
+         }
+      }
+   }
+   
+   @AroundInvoke
+   public Object aroundInvoke(InvocationContext invocation) throws Exception
+   {
+      Method interfaceMethod = invocation.getMethod();
+      
+      if (!"hashCode".equals(interfaceMethod.getName()))
+      {
+         Restriction restriction = getRestriction(interfaceMethod);
+         if ( restriction != null )
+         {
+            
+            restriction.check(identity, invocation.getParameters());
+         }
+      }
+
+      return invocation.proceed();
+   }
+   
+   private Restriction getRestriction(Method interfaceMethod) throws Exception
+   {
+      // see field declaration as to why this is done
+      if (restrictions == null)
+      {
+         synchronized(this)
+         {
+            restrictions = new HashMap<Method, Restriction>();
+         }
+      }
+      
+      if (!restrictions.containsKey(interfaceMethod))
+      {
+         synchronized(restrictions)
+         {
+            // FIXME this logic should be abstracted rather than sitting in the middle of this interceptor
+            if (!restrictions.containsKey(interfaceMethod))
+            {
+               Restriction restriction = null;
+               
+               /*Method method = getComponent().getBeanClass().getMethod(
+                     interfaceMethod.getName(), interfaceMethod.getParameterTypes() );*/
+               
+               Restrict restrict = null;
+               
+               if ( interfaceMethod.isAnnotationPresent(Restrict.class) )
+               {
+                  restrict = interfaceMethod.getAnnotation(Restrict.class);
+               }
+               else if ( interfaceMethod.getDeclaringClass().isAnnotationPresent(Restrict.class) )
+               {
+                   restrict = interfaceMethod.getDeclaringClass().getAnnotation(Restrict.class);
+               }
+               
+               if (restrict != null)
+               {
+                  if (restriction == null) restriction = new Restriction();
+                  
+                  if ( Strings.isEmpty(restrict.value()) )
+                  {
+                     Bean<?> bean = manager.getBeans(interfaceMethod.getDeclaringClass()).iterator().next();
+                     restriction.setPermissionTarget(bean.getName());
+                     restriction.setPermissionAction(interfaceMethod.getName());
+                  }
+                  else
+                  {
+                     restriction.setExpression(restrict.value());
+                  }
+               }
+               
+               for (Annotation annotation : interfaceMethod.getDeclaringClass().getAnnotations())
+               {
+                  if (annotation.annotationType().isAnnotationPresent(RoleCheck.class))
+                  {
+                     if (restriction == null) restriction = new Restriction();
+                     restriction.addRoleRestriction(annotation.annotationType().getSimpleName().toLowerCase());
+                  }
+               }
+               
+               for (Annotation annotation : interfaceMethod.getAnnotations())
+               {
+                  if (annotation.annotationType().isAnnotationPresent(PermissionCheck.class))
+                  {
+                     PermissionCheck permissionCheck = annotation.annotationType().getAnnotation(
+                           PermissionCheck.class);
+                     
+                     Method valueMethod = null;
+                     for (Method m : annotation.annotationType().getDeclaredMethods())
+                     {
+                        valueMethod = m;
+                        break;
+                     }
+                     
+                     if (valueMethod != null)
+                     {
+                        if (restriction == null) restriction = new Restriction();
+                        Object target = valueMethod.invoke(annotation);
+                        if (!target.equals(void.class))
+                        {
+                           if (restriction == null) restriction = new Restriction();
+                           restriction.addMethodRestriction(target,
+                                 getPermissionAction(permissionCheck, annotation));
+                        }
+                     }
+                  }
+                  if (annotation.annotationType().isAnnotationPresent(RoleCheck.class))
+                  {
+                     if (restriction == null) restriction = new Restriction();
+                     restriction.addRoleRestriction(annotation.annotationType().getSimpleName().toLowerCase());
+                  }
+               }
+               
+               for (int i = 0; i < interfaceMethod.getParameterAnnotations().length; i++)
+               {
+                  Annotation[] annotations = interfaceMethod.getParameterAnnotations()[i];
+                  for (Annotation annotation : annotations)
+                  {
+                     if (annotation.annotationType().isAnnotationPresent(PermissionCheck.class))
+                     {
+                        PermissionCheck permissionCheck = annotation.annotationType().getAnnotation(
+                              PermissionCheck.class);
+                        if (restriction == null) restriction = new Restriction();
+                        restriction.addParameterRestriction(i,
+                              getPermissionAction(permissionCheck, annotation));
+                     }
+                  }
+               }
+               
+               restrictions.put(interfaceMethod, restriction);
+               return restriction;
+            }
+         }
+      }
+      return restrictions.get(interfaceMethod);
+   }
+
+   
+   private String getPermissionAction(PermissionCheck check, Annotation annotation)
+   {
+      if (!"".equals(check.value()))
+      {
+         return check.value();
+      }
+      else
+      {
+         return annotation.annotationType().getSimpleName().toLowerCase();
+      }
+   }
+}

Added: modules/security/trunk/impl/src/main/java/org/jboss/seam/security/SimpleGroup.java
===================================================================
--- modules/security/trunk/impl/src/main/java/org/jboss/seam/security/SimpleGroup.java	                        (rev 0)
+++ modules/security/trunk/impl/src/main/java/org/jboss/seam/security/SimpleGroup.java	2010-04-13 10:40:40 UTC (rev 12453)
@@ -0,0 +1,93 @@
+package org.jboss.seam.security;
+
+import java.io.Serializable;
+import java.security.Principal;
+import java.security.acl.Group;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Implementation of the Group interface, used for holding roles etc.
+ * 
+ * @author Shane Bryzak
+ */
+public class SimpleGroup implements Group, Serializable
+{
+   private static final long serialVersionUID = 5766373925836425908L;
+
+   /**
+    * The name of the group
+    */
+   private String name;
+
+   /**
+    * The members of this group
+    */
+   private Set<Principal> members = new HashSet<Principal>();
+
+   public SimpleGroup(String name)
+   {
+      this.name = name;
+   }
+
+   public boolean addMember(Principal user)
+   {
+      return members.add(user);
+   }
+
+   public boolean isMember(Principal member)
+   {
+      if ( members.contains(member) )
+      {
+         return true;
+      }
+      else
+      {
+         for (Principal m : members)
+         {
+            if (m instanceof Group && ((Group) m).isMember(member))
+            {
+               return true;
+            }
+         }
+      }
+      return false;
+   }
+
+   public Enumeration<? extends Principal> members()
+   {
+      return Collections.enumeration(members);
+   }
+
+   public boolean removeMember(Principal user)
+   {
+      return members.remove(user);
+   }
+
+   public String getName()
+   {
+      return name;
+   }
+
+   @Override
+   public boolean equals(Object obj)
+   {
+      if (obj instanceof SimpleGroup)
+      {
+         SimpleGroup other = (SimpleGroup) obj;
+         return other.name.equals(name);
+      }
+      else
+      {
+         return false;
+      }
+   }
+
+   @Override
+   public int hashCode()
+   {
+      return name.hashCode();
+   }
+}

Added: modules/security/trunk/impl/src/main/java/org/jboss/seam/security/SimplePrincipal.java
===================================================================
--- modules/security/trunk/impl/src/main/java/org/jboss/seam/security/SimplePrincipal.java	                        (rev 0)
+++ modules/security/trunk/impl/src/main/java/org/jboss/seam/security/SimplePrincipal.java	2010-04-13 10:40:40 UTC (rev 12453)
@@ -0,0 +1,54 @@
+package org.jboss.seam.security;
+
+import java.io.Serializable;
+import java.security.Principal;
+
+/**
+ * Simple implementation of the Principal interface, supporting a named user.
+ * 
+ * @author Shane Bryzak
+ */
+public class SimplePrincipal implements Principal, Serializable
+{
+   private static final long serialVersionUID = 5609375932836425908L;   
+   
+   private String name;
+   
+   public SimplePrincipal(String name)
+   {
+      this.name = name;
+   }
+   
+   public String getName()
+   {
+      return name;
+   }
+
+   @Override
+   public boolean equals(Object obj)
+   {
+      if (obj instanceof Principal)
+      {
+         Principal other = (Principal) obj;
+         return name == null ?
+                  other.getName() == null :
+                  name.equals( other.getName() );
+      }
+      else
+      {
+         return false;
+      }
+   }
+
+   @Override
+   public int hashCode()
+   {
+      return name != null ? name.hashCode() : super.hashCode();
+   }
+
+   @Override
+   public String toString()
+   {
+      return name;
+   }   
+}

Added: modules/security/trunk/impl/src/main/java/org/jboss/seam/security/TokenStore.java
===================================================================
--- modules/security/trunk/impl/src/main/java/org/jboss/seam/security/TokenStore.java	                        (rev 0)
+++ modules/security/trunk/impl/src/main/java/org/jboss/seam/security/TokenStore.java	2010-04-13 10:40:40 UTC (rev 12453)
@@ -0,0 +1,15 @@
+package org.jboss.seam.security;
+
+/**
+ * A store containing user authentication tokens.  Used in conjunction with the RememberMe
+ * component to auto-login users that present a valid cookie-based token.
+ * 
+ * @author Shane Bryzak
+ */
+public interface TokenStore
+{
+   void createToken(String username, String value);
+   boolean validateToken(String username, String value);
+   void invalidateToken(String username, String value);
+   void invalidateAll(String username);
+}



More information about the seam-commits mailing list