Annotation of java/classes/org/w3c/jigsaw/acl/DigestAuthPrincipal.java, revision 1.8
1.1 bmahe 1: // DigestAuthPrincipal.java
1.8 ! ylafon 2: // $Id: DigestAuthPrincipal.java,v 1.7 2004/12/17 15:12:05 ylafon Exp $
1.1 bmahe 3: // (c) COPYRIGHT MIT, INRIA and Keio, 1999.
4: // Please first read the full copyright statement in file COPYRIGHT.html
1.6 ylafon 5:
1.1 bmahe 6: package org.w3c.jigsaw.acl;
7:
1.8 ! ylafon 8: import java.io.UnsupportedEncodingException;
1.1 bmahe 9: import java.security.Principal;
1.2 bmahe 10: import java.security.MessageDigest;
11: import java.security.NoSuchAlgorithmException;
1.1 bmahe 12:
13: import org.w3c.jigsaw.http.Request;
1.2 bmahe 14: import org.w3c.www.http.HttpCredential;
15: import org.w3c.util.StringUtils;
1.1 bmahe 16:
17: /**
1.8 ! ylafon 18: * @version $Revision: 1.7 $
1.1 bmahe 19: * @author Benoît Mahé (bmahe@w3.org)
1.7 ylafon 20: * This algorithm used is based on RFC 2069
1.1 bmahe 21: */
1.5 ylafon 22: public class DigestAuthPrincipal extends HTTPPrincipal {
1.6 ylafon 23:
1.8 ! ylafon 24: protected
1.2 bmahe 25: String dac_user = null;
26: String dac_realm = null;
27: String dac_nonce = null;
28: String dac_uri = null;
29: String dac_response = null;
30: String dac_algorithm = null;
31: String dac_method = null;
32: String nonce = null;
33: String old_nonce = null;
34: String algo = null;
35: boolean stale = false;
1.4 bmahe 36: boolean no_user = false;
1.2 bmahe 37:
1.1 bmahe 38: public boolean isStale() {
1.2 bmahe 39: return stale;
1.1 bmahe 40: }
1.8 ! ylafon 41:
! 42: /**
! 43: * Check that the challenge matches with the provided nonce
! 44: * @return true if it matches
! 45: */
! 46: private boolean checkDigest2069(String username, String realm ,
! 47: String password, String nonce) {
! 48: // check if the user knows the right passwd
! 49: String a1, a2, ha1, ha2;
! 50: StringBuffer sb = new StringBuffer(256);
! 51: // a1 = unq(username-value) ":" unq(realm-value) ":" passwd
! 52: sb.append(username).append(':').append(realm);
! 53: sb.append(':').append(password);
! 54: a1 = sb.toString();
! 55: // A2 = Method ":" digest-uri-value
! 56: sb = new StringBuffer(256);
! 57: sb.append(dac_method).append(':').append(dac_uri);
! 58: a2 = sb.toString();
! 59: MessageDigest md = null;
! 60: try {
! 61: md = MessageDigest.getInstance(this.algo);
! 62: } catch (NoSuchAlgorithmException algex) {
! 63: // fatal error, can't authenticate
! 64: return false;
! 65: }
! 66: try {
! 67: md.update(a1.getBytes("ISO-8859-1"));
! 68: ha1 = StringUtils.toHexString(md.digest());
! 69: md.reset();
! 70: md.update(a2.getBytes("ISO-8859-1"));
! 71: ha2 = StringUtils.toHexString(md.digest());
! 72: md.reset();
! 73: String kd, hkd;
! 74: // KD( H(A1), unq(nonce-value) ":" H(A2)
! 75: sb = new StringBuffer(256);
! 76: sb.append(ha1).append(':').append(nonce).append(':').append(ha2);
! 77: kd = sb.toString();
! 78: md.update(kd.getBytes("ISO-8859-1"));
! 79: hkd = StringUtils.toHexString(md.digest());
! 80: return hkd.equals(dac_response);
! 81: } catch (UnsupportedEncodingException ex) {
! 82: // in case iso-8859-1 is not known...
! 83: }
! 84: return false;
! 85: }
! 86:
1.1 bmahe 87: public boolean equals(Object another) {
1.4 bmahe 88: if (no_user)
89: return false;
1.2 bmahe 90: if (another instanceof AclPrincipal) {
91: AclPrincipal aclp = (AclPrincipal) another;
92: String username = aclp.getName();
93: String realm = aclp.getRealm();
94: String passwd = aclp.getPassword();
1.8 ! ylafon 95:
1.2 bmahe 96: if (!dac_user.equals(username))
97: return false;
98: if (!dac_realm.equals(realm))
99: return false;
100: if (dac_algorithm != null && !dac_algorithm.equals(this.algo))
101: return false;
1.8 ! ylafon 102: // are we using the current nonce?
1.2 bmahe 103: if (!dac_nonce.equals(this.nonce)) {
1.8 ! ylafon 104: // no, is it the old one?
! 105: if (dac_nonce.equals(this.old_nonce)) {
! 106: // yes, does it matches?
! 107: if (checkDigest2069(username, realm, passwd, old_nonce)) {
! 108: // it doesn't mean that we are validating an old nonce
! 109: // but it is a trick, allowing two nonces at the same
! 110: // time to populate "AuthenticationInfo" with the
! 111: // next nonce.
! 112: stale = true;
! 113: return true;
1.2 bmahe 114: }
115: } else {
1.8 ! ylafon 116: // reject but mark as atale if auth is ok with nonce.
! 117: if (checkDigest2069(username, realm, passwd, dac_nonce)) {
! 118: stale = true;
! 119: }
1.2 bmahe 120: }
121: return false;
122: }
1.8 ! ylafon 123: return checkDigest2069(username, realm, passwd, nonce);
1.2 bmahe 124: } else if (another instanceof DigestAuthPrincipal) {
125: return false;
126: }
1.1 bmahe 127: return false;
128: }
129:
130: public String toString() {
1.4 bmahe 131: if (dac_user != null)
132: return dac_user;
1.1 bmahe 133: return "Digest";
134: }
135:
136: public int hashCode() {
1.4 bmahe 137: if (dac_nonce != null)
138: return dac_nonce.hashCode();
139: else return -1;
1.1 bmahe 140: }
141:
142: public String getName() {
1.4 bmahe 143: return dac_user;
1.1 bmahe 144: }
145:
1.2 bmahe 146: public DigestAuthPrincipal(Request request,
147: String nonce,
148: String old_nonce,
149: String algo)
1.1 bmahe 150: throws InvalidAuthException
151: {
1.5 ylafon 152: super(request);
1.2 bmahe 153: HttpCredential credential = (request.isProxy()
154: ? request.getProxyAuthorization()
155: : request.getAuthorization());
1.4 bmahe 156: if ((credential == null) ||
157: ( ! credential.getScheme().equalsIgnoreCase("Digest"))) {
158: no_user = true;
1.2 bmahe 159: } else {
1.4 bmahe 160: no_user = false;
1.2 bmahe 161: dac_user = credential.getAuthParameter("username");
162: dac_uri = credential.getAuthParameter("uri");
163: dac_response = credential.getAuthParameter("response");
164: dac_realm = credential.getAuthParameter("realm");
165: dac_method = request.getMethod();
166: dac_nonce = credential.getAuthParameter("nonce");
167: this.nonce = nonce;
168: this.old_nonce = old_nonce;
169: this.algo = algo;
170: if (dac_user == null || dac_uri == null || dac_response == null ||
171: dac_realm == null) {
172: String msg = ("Invalid authentication header");
173: throw new InvalidAuthException(msg);
174: }
175: }
1.1 bmahe 176: }
177:
1.5 ylafon 178: public DigestAuthPrincipal(Request request)
179: throws InvalidAuthException
180: {
181: super(request);
182: throw new InvalidAuthException("Bad call for authentification");
183: }
1.8 ! ylafon 184:
! 185: protected DigestAuthPrincipal(Request request, String internal)
! 186: throws InvalidAuthException
! 187: {
! 188: super(request);
! 189: }
1.1 bmahe 190: }
Webmaster