--- /dev/null
+// DigestAuthPrincipal.java\r
+// $Id: DigestQopAuthPrincipal.java,v 1.1 2010/06/15 12:22:07 smhuang Exp $\r
+// (c) COPYRIGHT MIT, INRIA and Keio, 1999.\r
+// Please first read the full copyright statement in file COPYRIGHT.html\r
+\r
+package org.w3c.jigsaw.acl;\r
+\r
+import java.io.UnsupportedEncodingException;\r
+import java.security.Principal;\r
+import java.security.MessageDigest;\r
+import java.security.NoSuchAlgorithmException;\r
+\r
+import org.w3c.jigsaw.http.Request;\r
+import org.w3c.www.http.HttpCredential;\r
+import org.w3c.util.StringUtils;\r
+\r
+/**\r
+ * @version $Revision: 1.1 $\r
+ * @author Benoît Mahé (bmahe@w3.org)\r
+ */\r
+public class DigestQopAuthPrincipal extends DigestAuthPrincipal {\r
+\r
+ String dac_opaque = null;\r
+ String dac_cnonce = null;\r
+ String dac_nc = null;\r
+ String dac_qop = null;\r
+\r
+ /**\r
+ * Check that the challenge matches with the provided nonce\r
+ * @return true if it matches\r
+ */\r
+ private boolean checkDigest2617(String username, String realm , \r
+ String password, String nonce) {\r
+ // check if the user knows the right passwd\r
+ String a1, a2, ha1, ha2;\r
+ // "auth" case\r
+ StringBuffer sb = new StringBuffer(256);\r
+ // a1 = unq(username-value) ":" unq(realm-value) ":" passwd\r
+ sb.append(username).append(':').append(realm);\r
+ sb.append(':').append(password);\r
+ a1 = sb.toString();\r
+ // A2 = Method ":" digest-uri-value\r
+ sb = new StringBuffer(256);\r
+ sb.append(dac_method).append(':').append(dac_uri);\r
+ a2 = sb.toString();\r
+ MessageDigest md = null;\r
+ try {\r
+ md = MessageDigest.getInstance(this.algo);\r
+ } catch (NoSuchAlgorithmException algex) {\r
+ // fatal error, can't authenticate\r
+ return false;\r
+ }\r
+ try {\r
+ md.update(a1.getBytes("ISO-8859-1"));\r
+ ha1 = StringUtils.toHexString(md.digest());\r
+ md.reset();\r
+ md.update(a2.getBytes("ISO-8859-1"));\r
+ ha2 = StringUtils.toHexString(md.digest());\r
+ md.reset();\r
+ String kd, hkd;\r
+ // KD( H(A1), unq(nonce-value) ":" nc-value ":" unq(cnonce-value)\r
+ // ":" unq(qop-value)" ":" H(A2) )\r
+ sb = new StringBuffer(256);\r
+ sb.append(ha1).append(':').append(dac_nonce).append(':');\r
+ sb.append(dac_nc).append(':').append(dac_cnonce).append(':');\r
+ sb.append(dac_qop).append(':').append(ha2);\r
+ kd = sb.toString();\r
+ md.update(kd.getBytes("ISO-8859-1"));\r
+ hkd = StringUtils.toHexString(md.digest());\r
+ return hkd.equals(dac_response);\r
+ } catch (Exception ex) {\r
+ // in case iso-8859-1 is not known...\r
+ }\r
+ return false;\r
+ }\r
+ \r
+\r
+ public boolean equals(Object another) {\r
+ if (no_user)\r
+ return false;\r
+ if (another instanceof AclPrincipal) {\r
+ AclPrincipal aclp = (AclPrincipal) another;\r
+ String username = aclp.getName();\r
+ String realm = aclp.getRealm();\r
+ String passwd = aclp.getPassword();\r
+ \r
+ if (!dac_user.equals(username))\r
+ return false;\r
+ if (!dac_realm.equals(realm))\r
+ return false;\r
+ if (dac_algorithm != null && !dac_algorithm.equals(this.algo))\r
+ return false;\r
+ // are we using the current nonce?\r
+ if (!dac_nonce.equals(this.nonce)) {\r
+ // no, is it the old one?\r
+ if (dac_nonce.equals(this.old_nonce)) {\r
+ // yes, does it matches?\r
+ if (checkDigest2617(username, realm, passwd, old_nonce)) {\r
+ // it doesn't mean that we are validating an old nonce\r
+ // but it is a trick, allowing two nonces at the same\r
+ // time to populate "AuthenticationInfo" with the\r
+ // next nonce.\r
+ stale = true;\r
+ return true;\r
+ }\r
+ } else {\r
+ // reject but mark as atale if auth is ok with nonce.\r
+ if (checkDigest2617(username, realm, passwd, dac_nonce)) {\r
+ System.out.println("** stale!");\r
+ stale = true;\r
+ }\r
+ }\r
+ return false;\r
+ }\r
+ return checkDigest2617(username, realm, passwd, nonce);\r
+ } else if (another instanceof DigestQopAuthPrincipal) {\r
+ return false;\r
+ }\r
+ return false;\r
+ }\r
+\r
+ public DigestQopAuthPrincipal(Request request, \r
+ String nonce, \r
+ String old_nonce,\r
+ String algo)\r
+ throws InvalidAuthException\r
+ {\r
+ super(request, algo);\r
+ this.request = request;\r
+ HttpCredential credential = (request.isProxy()\r
+ ? request.getProxyAuthorization()\r
+ : request.getAuthorization());\r
+ if ((credential == null) ||\r
+ ( ! credential.getScheme().equalsIgnoreCase("Digest"))) {\r
+ no_user = true;\r
+ } else {\r
+ no_user = false;\r
+ dac_user = credential.getAuthParameter("username");\r
+ dac_uri = credential.getAuthParameter("uri");\r
+ dac_response = credential.getAuthParameter("response");\r
+ dac_realm = credential.getAuthParameter("realm");\r
+ dac_method = request.getMethod();\r
+ dac_nonce = credential.getAuthParameter("nonce");\r
+ dac_opaque = credential.getAuthParameter("opaque");\r
+ dac_cnonce = credential.getAuthParameter("cnonce");\r
+ dac_nc = credential.getAuthParameter("nc");\r
+ dac_qop = credential.getAuthParameter("qop");\r
+ if (dac_qop == null) {\r
+ dac_qop = "auth";\r
+ } else {\r
+ if (!dac_qop.equals("auth")) {\r
+ String msg = "qop value not supported";\r
+ throw new InvalidAuthException(msg);\r
+ }\r
+ }\r
+ this.nonce = nonce;\r
+ this.old_nonce = old_nonce;\r
+ this.algo = algo;\r
+ if (dac_user == null || dac_uri == null || dac_response == null ||\r
+ dac_realm == null || dac_cnonce == null) {\r
+ String msg = ("Invalid authentication header");\r
+ throw new InvalidAuthException(msg);\r
+ }\r
+ }\r
+ }\r
+\r
+ public DigestQopAuthPrincipal(Request request)\r
+ throws InvalidAuthException\r
+ {\r
+ super(request);\r
+ throw new InvalidAuthException("Bad call for authentification");\r
+ }\r
+}\r