Package org.jboss.seam.web

Source Code of org.jboss.seam.web.AuthenticationFilter

package org.jboss.seam.web;

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

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.security.auth.login.LoginException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.jboss.seam.annotations.Install;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.jboss.seam.annotations.web.Filter;
import org.jboss.seam.contexts.Context;
import org.jboss.seam.contexts.SessionContext;
import org.jboss.seam.log.Log;
import org.jboss.seam.security.Credentials;
import org.jboss.seam.security.Identity;
import org.jboss.seam.security.NotLoggedInException;
import org.jboss.seam.security.digest.DigestRequest;
import org.jboss.seam.security.digest.DigestUtils;
import org.jboss.seam.security.digest.DigestValidationException;
import org.jboss.seam.servlet.ContextualHttpServletRequest;
import org.jboss.seam.servlet.ServletRequestSessionMap;
import org.jboss.seam.util.Base64;
import org.jboss.seam.util.Strings;

/**
* Seam Servlet Filter supporting HTTP Basic and Digest authentication. Some code
* adapted from Acegi.
* @author Shane Bryzak
*/
@Scope(APPLICATION)
@Name("org.jboss.seam.web.authenticationFilter")
@Install(value = false, precedence = BUILT_IN)
@BypassInterceptors
@Filter(within = "org.jboss.seam.web.exceptionFilter")
public class AuthenticationFilter extends AbstractFilter
{
   private static final String DEFAULT_REALM = "seamApp";
  
   private static final String AUTH_TYPE_BASIC = "basic";
   private static final String AUTH_TYPE_DIGEST = "digest";
  
   @Logger Log log;
  
   public enum AuthType {basic, digest}
  
   private String realm = DEFAULT_REALM;
  
   private String key;
   private int nonceValiditySeconds = 300;
  
   private String authType = AUTH_TYPE_BASIC;
  
   public void setRealm(String realm)
   {
      this.realm = realm;
   }
  
   public String getRealm()
   {
      return realm;
   }
  
   public void setAuthType(String authType)
   {
      this.authType = authType;
   }
  
   public String getAuthType()
   {
      return authType;
   }
  
   public String getKey()
   {
      return key;
   }
  
   public void setKey(String key)
   {
      this.key = key;
   }
  
   public int getNonceValiditySeconds()
   {
      return nonceValiditySeconds;
   }
  
   public void setNonceValiditySeconds(int value)
   {
      this.nonceValiditySeconds = value;
   }
  
   public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException
   {
      if (!(request instanceof HttpServletRequest))
      {
         throw new ServletException("This filter can only process HttpServletRequest requests");
      }

      HttpServletRequest httpRequest = (HttpServletRequest) request;
      HttpServletResponse httpResponse = (HttpServletResponse) response;

      // Force session creation
      httpRequest.getSession();
     
      if (AUTH_TYPE_BASIC.equals(authType))
         processBasicAuth(httpRequest, httpResponse, chain);
      else if (AUTH_TYPE_DIGEST.equals(authType))
         processDigestAuth(httpRequest, httpResponse, chain);
      else
         throw new ServletException("Invalid authentication type");
   }
  
   private void processBasicAuth(HttpServletRequest request,
            HttpServletResponse response, FilterChain chain)
      throws IOException, ServletException
   {
      Context ctx = new SessionContext( new ServletRequestSessionMap(request) );
      Identity identity = (Identity) ctx.get(Identity.class);

      if (identity == null)
      {
         throw new ServletException("Identity not found - please ensure that the Identity component is created on startup.");
      }
     
      Credentials credentials = (Credentials) ctx.get(Credentials.class);
     
      boolean requireAuth = false;
     
      String header = request.getHeader("Authorization");
      if (header != null && header.startsWith("Basic "))
      {
         String base64Token = header.substring(6);
         String token = new String(Base64.decode(base64Token));

         String username = "";
         String password = "";
         int delim = token.indexOf(":");

         if (delim != -1)
         {
             username = token.substring(0, delim);
             password = token.substring(delim + 1);
         }

         // Only reauthenticate if username doesn't match Identity.username and user isn't authenticated
         if (!username.equals(credentials.getUsername()) || !identity.isLoggedIn())
         {
            try
            {
               credentials.setPassword(password);
               authenticate( request, username );
            }        
            catch (Exception ex)
            {
               log.warn("Error authenticating: " + ex.getMessage());
               requireAuth = true;
           
         }
      }
     
      if (!identity.isLoggedIn() && !credentials.isSet())
      {
         requireAuth = true;
      }
     
      try
      {
         if (!requireAuth)
         {
            chain.doFilter(request, response);
            return;
         }
      }
      catch (NotLoggedInException ex)
      {
         requireAuth = true;
      }
     
      if ((requireAuth && !identity.isLoggedIn()))
      {
         response.addHeader("WWW-Authenticate", "Basic realm=\"" + realm + "\"");
         response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Not authorized");        
      }              
   }

   private void processDigestAuth(HttpServletRequest request,
            HttpServletResponse response, FilterChain chain)
      throws IOException, ServletException
   {
      Context ctx = new SessionContext( new ServletRequestSessionMap(request) );
      Identity identity = (Identity) ctx.get(Identity.class);
     
      if (identity == null)
      {
         throw new ServletException("Identity not found - please ensure that the Identity component is created on startup.");
      }     
     
      Credentials credentials = (Credentials) ctx.get(Credentials.class);
     
      boolean requireAuth = false;   
      boolean nonceExpired = false;
     
      String header = request.getHeader("Authorization");     
      if (header != null && header.startsWith("Digest "))
      {       
         String section212response = header.substring(7);

         String[] headerEntries = section212response.split(",");
         Map<String,String> headerMap = new HashMap<String,String>();
         for (String entry : headerEntries)
         {
            String[] vals = split(entry, "=");
            headerMap.put(vals[0].trim(), vals[1].replace("\"", "").trim());
         }
        

         DigestRequest digestRequest = new DigestRequest();
         digestRequest.setHttpMethod(request.getMethod());
         digestRequest.setSystemRealm(realm);
         digestRequest.setRealm(headerMap.get("realm"));        
         digestRequest.setKey(key);
         digestRequest.setNonce(headerMap.get("nonce"));
         digestRequest.setUri(headerMap.get("uri"));
         digestRequest.setClientDigest(headerMap.get("response"));
         digestRequest.setQop(headerMap.get("qop"));
         digestRequest.setNonceCount(headerMap.get("nc"));
         digestRequest.setClientNonce(headerMap.get("cnonce"));
                 
         try
         {
            digestRequest.validate();
            request.getSession().setAttribute(DigestRequest.DIGEST_REQUEST, digestRequest);
            authenticate( request, headerMap.get("username") );
         }
         catch (DigestValidationException ex)
         {
            log.warn(String.format("Digest validation failed, header [%s]: %s",
                     section212response, ex.getMessage()));
            requireAuth = true;
           
            if (ex.isNonceExpired()) nonceExpired = true;
         }           
         catch (Exception ex)
         {
            log.warn("Error authenticating: " + ex.getMessage());
            requireAuth = true;
         }
      }  

      if (!identity.isLoggedIn() && !credentials.isSet())
      {
         requireAuth = true;
      }
     
      try
      {
         if (!requireAuth)
         {
            chain.doFilter(request, response);
            return;
         }
      }
      catch (NotLoggedInException ex)
      {
         requireAuth = true;
      }
     
      if ((requireAuth && !identity.isLoggedIn()))
      {     
         long expiryTime = System.currentTimeMillis() + (nonceValiditySeconds * 1000);
        
         String signatureValue = DigestUtils.md5Hex(expiryTime + ":" + key);
         String nonceValue = expiryTime + ":" + signatureValue;
         String nonceValueBase64 = Base64.encodeBytes(nonceValue.getBytes());

         // qop is quality of protection, as defined by RFC 2617.
         // we do not use opaque due to IE violation of RFC 2617 in not
         // representing opaque on subsequent requests in same session.
         String authenticateHeader = "Digest realm=\"" + realm + "\", " + "qop=\"auth\", nonce=\""
             + nonceValueBase64 + "\"";

         if (nonceExpired) authenticateHeader = authenticateHeader + ", stale=\"true\"";

         response.addHeader("WWW-Authenticate", authenticateHeader);
         response.sendError(HttpServletResponse.SC_UNAUTHORIZED);     
      }            
   }
  
   private void authenticate(HttpServletRequest request, final String username)
      throws ServletException, IOException
   {
      new ContextualHttpServletRequest(request)
      {
         @Override
         public void process() throws ServletException, IOException, LoginException
         {
            Identity identity = Identity.instance();
            identity.getCredentials().setUsername(username);
            identity.authenticate();
         }
      }.run()
   }
  
   private String[] split(String toSplit, String delimiter)
   {
      if (delimiter.length() != 1)
      {
          throw new IllegalArgumentException("Delimiter can only be one character in length");
      }

      int offset = toSplit.indexOf(delimiter);

      if (offset < 0) {
          return null;
      }

      String beforeDelimiter = toSplit.substring(0, offset);
      String afterDelimiter = toSplit.substring(offset + 1);

      return new String[] {beforeDelimiter, afterDelimiter};
  }  
}
TOP

Related Classes of org.jboss.seam.web.AuthenticationFilter

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.