[jboss-cvs] jboss-seam/src/main/org/jboss/seam/web ...
Shane Bryzak
sbryzak at redhat.com
Tue May 22 23:44:25 EDT 2007
User: sbryzak2
Date: 07/05/22 23:44:25
Modified: src/main/org/jboss/seam/web HttpAuthFilter.java
Log:
JBSEAM-743 still todo: testing, documentation, config
Revision Changes Path
1.2 +113 -5 jboss-seam/src/main/org/jboss/seam/web/HttpAuthFilter.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: HttpAuthFilter.java
===================================================================
RCS file: /cvsroot/jboss/jboss-seam/src/main/org/jboss/seam/web/HttpAuthFilter.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- HttpAuthFilter.java 21 May 2007 03:47:38 -0000 1.1
+++ HttpAuthFilter.java 23 May 2007 03:44:25 -0000 1.2
@@ -5,6 +5,8 @@
import static org.jboss.seam.annotations.Install.BUILT_IN;
import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
@@ -16,16 +18,27 @@
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.WebSessionContext;
+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.httpAuthFilter")
@@ -36,10 +49,15 @@
{
private static final String DEFAULT_REALM = "seamApp";
+ @Logger Log log;
+
public enum AuthType {basic, digest}
private String realmName = DEFAULT_REALM;
+ private String key;
+ private int nonceValiditySeconds = 300;
+
private AuthType authType = AuthType.basic;
public void setRealmName(String realmName)
@@ -62,6 +80,26 @@
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
{
@@ -108,7 +146,6 @@
}
// Only reauthenticate if username doesn't match Identity.username and user isn't authenticated
-
if (!username.equals(identity.getUsername()) || !identity.isLoggedIn())
{
identity.setUsername(username);
@@ -134,10 +171,81 @@
HttpServletResponse response, FilterChain chain)
throws IOException, ServletException
{
+ Context ctx = new WebSessionContext(new ServletSessionImpl(request.getSession()));
+ Identity identity = (Identity) ctx.get(Identity.class);
+
+ boolean failed = false;
+ boolean nonceExpired = false;
+
String header = request.getHeader("Authorization");
- if (!header.startsWith("Digest "))
+ if (header != null && header.startsWith("Digest "))
{
- throw new IllegalArgumentException("Request contains invalid authorization type");
+ String section212response = header.substring(7);
+
+ String[] headerEntries = section212response.split(",");
+ Map<String,String> headerMap = new HashMap<String,String>();
+ for (String entry : headerEntries)
+ {
+ String[] vals = entry.split("=");
+ headerMap.put(vals[0].trim(), vals[1].replace("\"", "").trim());
+ }
+
+ identity.setUsername(headerMap.get("username"));
+
+ DigestRequest digestRequest = new DigestRequest();
+ digestRequest.setSystemRealm(realmName);
+ 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);
+ }
+ catch (DigestValidationException ex)
+ {
+ log.error(String.format("Digest validation failed, header [%s]: %s",
+ section212response, ex.getMessage()));
+ failed = true;
+
+ if (ex.isNonceExpired()) nonceExpired = true;
+ }
+ }
+
+ if (!failed)
+ {
+ try
+ {
+ chain.doFilter(request, response);
+ return;
+ }
+ catch (NotLoggedInException ex) {}
+ }
+
+ if (failed || !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=\"" + realmName + "\", " + "qop=\"auth\", nonce=\""
+ + nonceValueBase64 + "\"";
+
+ if (nonceExpired) authenticateHeader = authenticateHeader + ", stale=\"true\"";
+
+ response.addHeader("WWW-Authenticate", authenticateHeader);
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
}
}
More information about the jboss-cvs-commits
mailing list