[jboss-cvs] jboss-seam/src/main/org/jboss/seam/web ...

Shane Bryzak sbryzak at redhat.com
Tue May 29 20:52:59 EDT 2007


  User: sbryzak2
  Date: 07/05/29 20:52:59

  Added:       src/main/org/jboss/seam/web   AuthenticationFilter.java
  Removed:     src/main/org/jboss/seam/web   HttpAuthFilter.java
  Log:
  rename authentication filter, fix compiler error
  
  Revision  Changes    Path
  1.1      date: 2007/05/30 00:52:59;  author: sbryzak2;  state: Exp;jboss-seam/src/main/org/jboss/seam/web/AuthenticationFilter.java
  
  Index: AuthenticationFilter.java
  ===================================================================
  package org.jboss.seam.web;
  
  import static org.jboss.seam.InterceptionType.NEVER;
  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.faces.event.PhaseId;
  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 javax.servlet.http.HttpSession;
  
  import org.jboss.seam.annotations.Filter;
  import org.jboss.seam.annotations.Install;
  import org.jboss.seam.annotations.Intercept;
  import org.jboss.seam.annotations.Logger;
  import org.jboss.seam.annotations.Name;
  import org.jboss.seam.annotations.Scope;
  import org.jboss.seam.annotations.Startup;
  import org.jboss.seam.contexts.Context;
  import org.jboss.seam.contexts.Lifecycle;
  import org.jboss.seam.contexts.WebSessionContext;
  import org.jboss.seam.core.Manager;
  import org.jboss.seam.log.Log;
  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.ServletSessionImpl;
  import org.jboss.seam.util.Base64;
  
  /**
   * Seam Servlet Filter supporting HTTP Basic and Digest authentication. Some code
   * adapted from Acegi.
   *  
   * @author Shane Bryzak
   */
  @Startup
  @Scope(APPLICATION)
  @Name("org.jboss.seam.web.authenticationFilter")
  @Install(value = false, precedence = BUILT_IN)
  @Intercept(NEVER)
  @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;
  
        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 WebSessionContext(new ServletSessionImpl(request.getSession()));
        Identity identity = (Identity) ctx.get(Identity.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(identity.getUsername()) || !identity.isLoggedIn()) 
           {
              identity.setUsername(username);
              identity.setPassword(password);
           }         
        }
        
        if (!identity.isLoggedIn() && !identity.isCredentialsSet())
        {
           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 WebSessionContext(new ServletSessionImpl(request.getSession()));
        Identity identity = (Identity) ctx.get(Identity.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());
           }
           
           identity.setUsername(headerMap.get("username"));
  
           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();
              ctx.set(DigestRequest.DIGEST_REQUEST, digestRequest);
              authenticate(request, identity);
           }
           catch (DigestValidationException ex)
           {
              log.error(String.format("Digest validation failed, header [%s]: %s",
                       section212response, ex.getMessage()));
              requireAuth = true;
              
              if (ex.isNonceExpired()) nonceExpired = true;
           }            
           catch (Exception ex)
           {
              log.error("Error authenticating: " + ex.getMessage());
              requireAuth = true;
           }
        }   
  
        if (!identity.isLoggedIn() && !identity.isCredentialsSet())
        {
           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, Identity identity)
        throws Exception
     {
        try
        {
           HttpSession session = request.getSession(true);
           Lifecycle.setPhaseId(PhaseId.INVOKE_APPLICATION);
           Lifecycle.setServletRequest(request);
           Lifecycle.beginRequest(getServletContext(), session, request);
           Manager.instance().restoreConversation( request.getParameterMap() );
           Lifecycle.resumeConversation(session);
           Manager.instance().handleConversationPropagation( request.getParameterMap() );   
           identity.authenticate();
        }
        catch (Exception ex) 
        {
           Lifecycle.endRequest();
           throw ex;
        }      
        finally
        {
           Lifecycle.setServletRequest(null);
           Lifecycle.setPhaseId(null);
        }      
     }
     
     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};
    }   
  }
  
  
  



More information about the jboss-cvs-commits mailing list