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