Package org.jboss.seam.security

Source Code of org.jboss.seam.security.RememberMe

package org.jboss.seam.security;

import static org.jboss.seam.ScopeType.SESSION;
import static org.jboss.seam.annotations.Install.BUILT_IN;

import java.io.Serializable;
import java.rmi.server.UID;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.faces.context.FacesContext;

import org.jboss.seam.Component;
import org.jboss.seam.annotations.Create;
import org.jboss.seam.annotations.Install;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Observer;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.jboss.seam.faces.Selector;
import org.jboss.seam.security.management.IdentityManager;
import org.jboss.seam.util.Base64;

/**
* 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
*/
@Name("org.jboss.seam.security.rememberMe")
@Scope(SESSION)
@Install(precedence = BUILT_IN, classDependencies = "javax.faces.context.FacesContext")
@BypassInterceptors
public class RememberMe implements Serializable
{
   class UsernameSelector extends Selector
   {
      @Override
      public String getCookieName()
      {
         return "org.jboss.seam.security.username";
      }      
     
      @Override
      public void setDirty()
      {
         super.setDirty();
      }
     
      @Override
      public String getCookieValue()
      {
         return super.getCookieValue();
      }
     
      @Override
      public void clearCookieValue()
      {
         super.clearCookieValue();
      }
     
      @Override
      public void setCookieValueIfEnabled(String value)
      {
         super.setCookieValueIfEnabled(value);
      }
   }
  
   class TokenSelector extends UsernameSelector
   {
      @Override
      public String getCookieName()
      {
         return "org.jboss.seam.security.authtoken";
      }
   }
  
   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)
            {
               // swallow
            }
         }
      }
     
      public String getUsername()
      {
         return username;
      }
     
      public String getValue()
      {
         return value;
      }
   }
     
   private UsernameSelector usernameSelector;
  
   private TokenSelector tokenSelector;  
   private TokenStore tokenStore;
     
   private boolean enabled;
  
   private boolean autoLoggedIn;
  
   private Random random = new Random(System.currentTimeMillis());
  
   public enum Mode { disabled, usernameOnly, autoLogin}
  
   private Mode mode = Mode.usernameOnly;
  
   public Mode getMode()
   {
      return mode;
   }
  
   public void setMode(Mode mode)
   {
      this.mode = mode;
   }
  
   public boolean isEnabled()
   {
      return enabled;
   }
  
   public void setEnabled(boolean enabled)
   {
      if (this.enabled != enabled)
      {
         this.enabled = enabled;
         if (mode.equals(Mode.usernameOnly))
         {
            usernameSelector.setCookieEnabled(enabled);
            usernameSelector.setDirty();
         }
         else if (mode.equals(Mode.autoLogin))
         {
            tokenSelector.setCookieEnabled(enabled);
            tokenSelector.setDirty();
         }
      }     
   }
  
   public TokenStore getTokenStore()
   {
      return tokenStore;
   }
  
   public void setTokenStore(TokenStore tokenStore)
   {
      this.tokenStore = tokenStore;
   }
  
   @Create
   public void create()
   {
      if (mode.equals(Mode.usernameOnly))
      {     
         usernameSelector = new UsernameSelector();
      }
      else if (mode.equals(Mode.autoLogin))
      {
         tokenSelector = new TokenSelector();

         // Default to JpaTokenStore
         if (tokenStore == null)
         {
            tokenStore = (TokenStore) Component.getInstance(JpaTokenStore.class, true);
         }        
      }
   }
  
   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());     
   }
  
   @Observer(Credentials.EVENT_INIT_CREDENTIALS)
   public void initCredentials(Credentials credentials)
   {            
      if (mode.equals(Mode.usernameOnly))
      {
         FacesContext ctx = FacesContext.getCurrentInstance();
         if (ctx != null)
         {
            usernameSelector.setCookiePath(ctx.getExternalContext().getRequestContextPath());
         }
        
         String username = usernameSelector.getCookieValue();
         if (username!=null)
         {
            setEnabled(true);
            credentials.setUsername(username);
         }
              
         usernameSelector.setDirty();
      }
      else if (mode.equals(Mode.autoLogin))
      {
         FacesContext ctx = FacesContext.getCurrentInstance();
         if (ctx != null)
         {
            tokenSelector.setCookiePath(ctx.getExternalContext().getRequestContextPath());
         }
        
         String token = tokenSelector.getCookieValue();
         if (token != null)
         {
            setEnabled(true);
           
            DecodedToken decoded = new DecodedToken(token);

            if (tokenStore.validateToken(decoded.getUsername(), decoded.getValue()))
            {
               credentials.setUsername(decoded.getUsername());
               credentials.setPassword(decoded.getValue());              
            }
            else
            {
               // Have we been compromised? Just in case, invalidate all authentication tokens
               tokenStore.invalidateAll(decoded.getUsername());
            }
         }
      }
   }
  
   /**
    * I hate these hacks...
    */
   private class BoolWrapper
   {
      boolean value;
   }
  
   @Observer(Identity.EVENT_QUIET_LOGIN)
   public void quietLogin()
   {
      final Identity identity = Identity.instance();
     
      if (mode.equals(Mode.autoLogin) && isEnabled())
      {
         final String username = identity.getCredentials().getUsername();   
         final BoolWrapper userEnabled = new BoolWrapper();
         final List<String> roles = new ArrayList<String>();
        
         // Double check our credentials again
         if (tokenStore.validateToken(username, identity.getCredentials().getPassword()))
         {           
            new RunAsOperation(true) {
               @Override
               public void execute()
               {       
                  if (IdentityManager.instance().isUserEnabled(username))
                  {
                     userEnabled.value = true;

                     for (String role : IdentityManager.instance().getImpliedRoles(username))
                     {
                        roles.add(role);
                     }
                  }
               }
            }.run();
           
            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;
            }
         }           
      }
   }
  
   @Observer(Identity.EVENT_LOGGED_OUT)
   public void loggedOut()
   {
      if (mode.equals(Mode.autoLogin))
      {
         tokenSelector.clearCookieValue();
      }
   }
  
   @Observer(Identity.EVENT_POST_AUTHENTICATE)
   public void postAuthenticate(Identity identity)
   {
      if (mode.equals(Mode.usernameOnly))
      {
         // Password is set to null during authentication, so we set dirty
         usernameSelector.setDirty();
              
         if ( !enabled ) usernameSelector.clearCookieValue();
         usernameSelector.setCookieValueIfEnabled( Identity.instance().getCredentials().getUsername() );
      }
      else if (mode.equals(Mode.autoLogin))
      {
         tokenSelector.setDirty();
        
         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.setCookieValueIfEnabled(encodeToken(identity.getPrincipal().getName(), value));           
         }
      }
   }       
  
   @Observer(Credentials.EVENT_CREDENTIALS_UPDATED)
   public void credentialsUpdated()
   {
      if (mode.equals(Mode.usernameOnly))
      {
         usernameSelector.setDirty();
      }     
   }     
  
   /**
    * A flag that an application can use to protect sensitive operations if the user has been
    * auto-authenticated.
    */
   public boolean isAutoLoggedIn()
   {
      return autoLoggedIn;
   }
}
TOP

Related Classes of org.jboss.seam.security.RememberMe

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.