001: // DigestAuthPrincipal.java
002: // $Id: DigestQopAuthPrincipal.java,v 1.3 2005/02/18 21:03:57 ylafon Exp $
003: // (c) COPYRIGHT MIT, INRIA and Keio, 1999.
004: // Please first read the full copyright statement in file COPYRIGHT.html
005:
006: package org.w3c.jigsaw.acl;
007:
008: import java.io.UnsupportedEncodingException;
009: import java.security.Principal;
010: import java.security.MessageDigest;
011: import java.security.NoSuchAlgorithmException;
012:
013: import org.w3c.jigsaw.http.Request;
014: import org.w3c.www.http.HttpCredential;
015: import org.w3c.util.StringUtils;
016:
017: /**
018: * @version $Revision: 1.3 $
019: * @author Benoît Mahé (bmahe@w3.org)
020: */
021: public class DigestQopAuthPrincipal extends DigestAuthPrincipal {
022:
023: String dac_opaque = null;
024: String dac_cnonce = null;
025: String dac_nc = null;
026: String dac_qop = null;
027:
028: /**
029: * Check that the challenge matches with the provided nonce
030: * @return true if it matches
031: */
032: private boolean checkDigest2617(String username, String realm,
033: String password, String nonce) {
034: // check if the user knows the right passwd
035: String a1, a2, ha1, ha2;
036: // "auth" case
037: StringBuffer sb = new StringBuffer(256);
038: // a1 = unq(username-value) ":" unq(realm-value) ":" passwd
039: sb.append(username).append(':').append(realm);
040: sb.append(':').append(password);
041: a1 = sb.toString();
042: // A2 = Method ":" digest-uri-value
043: sb = new StringBuffer(256);
044: sb.append(dac_method).append(':').append(dac_uri);
045: a2 = sb.toString();
046: MessageDigest md = null;
047: try {
048: md = MessageDigest.getInstance(this .algo);
049: } catch (NoSuchAlgorithmException algex) {
050: // fatal error, can't authenticate
051: return false;
052: }
053: try {
054: md.update(a1.getBytes("ISO-8859-1"));
055: ha1 = StringUtils.toHexString(md.digest());
056: md.reset();
057: md.update(a2.getBytes("ISO-8859-1"));
058: ha2 = StringUtils.toHexString(md.digest());
059: md.reset();
060: String kd, hkd;
061: // KD( H(A1), unq(nonce-value) ":" nc-value ":" unq(cnonce-value)
062: // ":" unq(qop-value)" ":" H(A2) )
063: sb = new StringBuffer(256);
064: sb.append(ha1).append(':').append(dac_nonce).append(':');
065: sb.append(dac_nc).append(':').append(dac_cnonce)
066: .append(':');
067: sb.append(dac_qop).append(':').append(ha2);
068: kd = sb.toString();
069: md.update(kd.getBytes("ISO-8859-1"));
070: hkd = StringUtils.toHexString(md.digest());
071: return hkd.equals(dac_response);
072: } catch (Exception ex) {
073: // in case iso-8859-1 is not known...
074: }
075: return false;
076: }
077:
078: public boolean equals(Object another) {
079: if (no_user)
080: return false;
081: if (another instanceof AclPrincipal) {
082: AclPrincipal aclp = (AclPrincipal) another;
083: String username = aclp.getName();
084: String realm = aclp.getRealm();
085: String passwd = aclp.getPassword();
086:
087: if (!dac_user.equals(username))
088: return false;
089: if (!dac_realm.equals(realm))
090: return false;
091: if (dac_algorithm != null
092: && !dac_algorithm.equals(this .algo))
093: return false;
094: // are we using the current nonce?
095: if (!dac_nonce.equals(this .nonce)) {
096: // no, is it the old one?
097: if (dac_nonce.equals(this .old_nonce)) {
098: // yes, does it matches?
099: if (checkDigest2617(username, realm, passwd,
100: old_nonce)) {
101: // it doesn't mean that we are validating an old nonce
102: // but it is a trick, allowing two nonces at the same
103: // time to populate "AuthenticationInfo" with the
104: // next nonce.
105: stale = true;
106: return true;
107: }
108: } else {
109: // reject but mark as atale if auth is ok with nonce.
110: if (checkDigest2617(username, realm, passwd,
111: dac_nonce)) {
112: System.out.println("** stale!");
113: stale = true;
114: }
115: }
116: return false;
117: }
118: return checkDigest2617(username, realm, passwd, nonce);
119: } else if (another instanceof DigestQopAuthPrincipal) {
120: return false;
121: }
122: return false;
123: }
124:
125: public DigestQopAuthPrincipal(Request request, String nonce,
126: String old_nonce, String algo) throws InvalidAuthException {
127: super (request, algo);
128: this .request = request;
129: HttpCredential credential = (request.isProxy() ? request
130: .getProxyAuthorization() : request.getAuthorization());
131: if ((credential == null)
132: || (!credential.getScheme().equalsIgnoreCase("Digest"))) {
133: no_user = true;
134: } else {
135: no_user = false;
136: dac_user = credential.getAuthParameter("username");
137: dac_uri = credential.getAuthParameter("uri");
138: dac_response = credential.getAuthParameter("response");
139: dac_realm = credential.getAuthParameter("realm");
140: dac_method = request.getMethod();
141: dac_nonce = credential.getAuthParameter("nonce");
142: dac_opaque = credential.getAuthParameter("opaque");
143: dac_cnonce = credential.getAuthParameter("cnonce");
144: dac_nc = credential.getAuthParameter("nc");
145: dac_qop = credential.getAuthParameter("qop");
146: if (dac_qop == null) {
147: dac_qop = "auth";
148: } else {
149: if (!dac_qop.equals("auth")) {
150: String msg = "qop value not supported";
151: throw new InvalidAuthException(msg);
152: }
153: }
154: this .nonce = nonce;
155: this .old_nonce = old_nonce;
156: this .algo = algo;
157: if (dac_user == null || dac_uri == null
158: || dac_response == null || dac_realm == null
159: || dac_cnonce == null) {
160: String msg = ("Invalid authentication header");
161: throw new InvalidAuthException(msg);
162: }
163: }
164: }
165:
166: public DigestQopAuthPrincipal(Request request)
167: throws InvalidAuthException {
168: super (request);
169: throw new InvalidAuthException("Bad call for authentification");
170: }
171: }
|