Annotation of java/classes/org/w3c/jigsaw/acl/DigestAuthPrincipal.java, revision 1.9

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

Webmaster