KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > winstone > auth > DigestAuthenticationHandler


1 /*
2  * Copyright 2003-2006 Rick Knowles <winstone-devel at lists sourceforge net>
3  * Distributed under the terms of either:
4  * - the common development and distribution license (CDDL), v1.0; or
5  * - the GNU Lesser General Public License, v2.1 or later
6  */

7 package winstone.auth;
8
9 import java.io.IOException JavaDoc;
10 import java.io.UnsupportedEncodingException JavaDoc;
11 import java.security.MessageDigest JavaDoc;
12 import java.security.NoSuchAlgorithmException JavaDoc;
13 import java.util.List JavaDoc;
14 import java.util.Random JavaDoc;
15 import java.util.Set JavaDoc;
16 import java.util.StringTokenizer JavaDoc;
17
18 import javax.servlet.http.HttpServletRequest JavaDoc;
19 import javax.servlet.http.HttpServletRequestWrapper JavaDoc;
20 import javax.servlet.http.HttpServletResponse JavaDoc;
21
22 import org.w3c.dom.Node JavaDoc;
23
24 import winstone.AuthenticationPrincipal;
25 import winstone.AuthenticationRealm;
26 import winstone.Logger;
27 import winstone.WinstoneRequest;
28 import winstone.WinstoneResourceBundle;
29
30 /**
31  * Implements the MD5 digest version of authentication
32  *
33  * @author <a HREF="mailto:rick_knowles@hotmail.com">Rick Knowles</a>
34  * @version $Id: DigestAuthenticationHandler.java,v 1.3 2004/05/22 06:53:45
35  * rickknowles Exp $
36  */

37 public class DigestAuthenticationHandler extends BaseAuthenticationHandler {
38     private MessageDigest JavaDoc md5Digester;
39
40     public DigestAuthenticationHandler(Node JavaDoc loginConfigNode,
41             List JavaDoc constraintNodes, Set JavaDoc rolesAllowed,
42             AuthenticationRealm realm) throws NoSuchAlgorithmException JavaDoc {
43         super(loginConfigNode, constraintNodes, rolesAllowed, realm);
44         this.md5Digester = MessageDigest.getInstance("MD5");
45         Logger.log(Logger.DEBUG, AUTH_RESOURCES,
46                 "DigestAuthenticationHandler.Initialised", realmName);
47     }
48
49     /**
50      * Call this once we know that we need to authenticate
51      */

52     protected void requestAuthentication(HttpServletRequest JavaDoc request,
53             HttpServletResponse JavaDoc response, String JavaDoc pathRequested)
54             throws IOException JavaDoc {
55         // Generate the one time token
56
String JavaDoc oneTimeToken = "WinstoneToken:"
57                 + (new Random JavaDoc().nextDouble() * System.currentTimeMillis());
58
59         // Need to write the www-authenticate header
60
String JavaDoc authHeader = "Digest realm=\"" + this.realmName
61                 + "\", qop=\"auth\", " + "nonce=\"" + oneTimeToken
62                 + "\", opaque=\"" + md5Encode(oneTimeToken) + "\"";
63         response.setHeader("WWW-Authenticate", authHeader);
64
65         // Return unauthorized
66
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, AUTH_RESOURCES
67                 .getString("DigestAuthenticationHandler.UnauthorizedMessage"));
68     }
69
70     /**
71      * Handling the (possible) response
72      *
73      * @return True if the request should continue, or false if we have
74      * intercepted it
75      */

76     protected boolean validatePossibleAuthenticationResponse(
77             HttpServletRequest JavaDoc request, HttpServletResponse JavaDoc response,
78             String JavaDoc pathRequested) throws IOException JavaDoc {
79         String JavaDoc authorization = request.getHeader("Authorization");
80         if (authorization == null)
81             return true;
82
83         // Logger.log(Logger.FULL_DEBUG, "Authorization: " + authorization);
84
if (!authorization.startsWith("Digest"))
85             return true;
86
87         // Extract tokens from auth string
88
String JavaDoc userName = null;
89         String JavaDoc realm = null;
90         String JavaDoc qop = null;
91         String JavaDoc algorithm = null;
92         String JavaDoc uri = null;
93         String JavaDoc nOnce = null;
94         String JavaDoc nc = null;
95         String JavaDoc cnOnce = null;
96         String JavaDoc clientResponseDigest = null;
97
98         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(authorization.substring(6)
99                 .trim(), ",");
100         while (st.hasMoreTokens()) {
101             String JavaDoc token = st.nextToken().trim();
102             int equalPos = token.indexOf('=');
103             String JavaDoc paramName = token.substring(0, equalPos);
104             if (paramName.equals("username"))
105                 userName = WinstoneResourceBundle.globalReplace(token
106                         .substring(equalPos + 1).trim(), "\"", "");
107             else if (paramName.equals("realm"))
108                 realm = WinstoneResourceBundle.globalReplace(token.substring(
109                         equalPos + 1).trim(), "\"", "");
110             else if (paramName.equals("qop"))
111                 qop = WinstoneResourceBundle.globalReplace(token.substring(
112                         equalPos + 1).trim(), "\"", "");
113             else if (paramName.equals("algorithm"))
114                 algorithm = WinstoneResourceBundle.globalReplace(token
115                         .substring(equalPos + 1).trim(), "\"", "");
116             else if (paramName.equals("uri"))
117                 uri = WinstoneResourceBundle.globalReplace(token.substring(
118                         equalPos + 1).trim(), "\"", "");
119             else if (paramName.equals("nonce"))
120                 nOnce = WinstoneResourceBundle.globalReplace(token.substring(
121                         equalPos + 1).trim(), "\"", "");
122             else if (paramName.equals("nc"))
123                 nc = WinstoneResourceBundle.globalReplace(token.substring(
124                         equalPos + 1).trim(), "\"", "");
125             else if (paramName.equals("cnonce"))
126                 cnOnce = WinstoneResourceBundle.globalReplace(token.substring(
127                         equalPos + 1).trim(), "\"", "");
128             else if (paramName.equals("response"))
129                 clientResponseDigest = WinstoneResourceBundle.globalReplace(
130                         token.substring(equalPos + 1).trim(), "\"", "");
131         }
132
133         // Throw out bad attempts
134
if ((userName == null) || (realm == null) || (qop == null)
135                 || (uri == null) || (nOnce == null) || (nc == null)
136                 || (cnOnce == null) || (clientResponseDigest == null))
137             return true;
138         else if ((algorithm != null) && !algorithm.equals("MD5"))
139             return true;
140
141         // Get a user matching the username
142
AuthenticationPrincipal principal = this.realm.retrieveUser(userName);
143         if (principal == null)
144             return true;
145
146         // Compute the 2 digests and compare
147
String JavaDoc userRealmPasswordDigest = md5Encode(userName + ":" + realm + ":"
148                 + principal.getPassword());
149         String JavaDoc methodURIDigest = md5Encode(request.getMethod() + ":" + uri);
150         String JavaDoc serverResponseDigest = md5Encode(userRealmPasswordDigest + ":"
151                 + nOnce + ":" + nc + ":" + cnOnce + ":" + qop + ":"
152                 + methodURIDigest);
153         if (serverResponseDigest.equals(clientResponseDigest)) {
154             principal.setAuthType(HttpServletRequest.DIGEST_AUTH);
155             if (request instanceof WinstoneRequest)
156                 ((WinstoneRequest) request).setRemoteUser(principal);
157             else if (request instanceof HttpServletRequestWrapper JavaDoc) {
158                 HttpServletRequestWrapper JavaDoc wrapper = (HttpServletRequestWrapper JavaDoc) request;
159                 if (wrapper.getRequest() instanceof WinstoneRequest)
160                     ((WinstoneRequest) wrapper.getRequest())
161                             .setRemoteUser(principal);
162                 else
163                     Logger.log(Logger.WARNING, AUTH_RESOURCES,
164                             "DigestAuthenticationHandler.CantSetUser", wrapper
165                                     .getRequest().getClass().getName());
166             } else
167                 Logger.log(Logger.WARNING, AUTH_RESOURCES,
168                         "DigestAuthenticationHandler.CantSetUser", request
169                                 .getClass().getName());
170         }
171         return true;
172     }
173
174     /**
175      * Returns a hex encoded MD5 digested version of the input string
176      * @param input The string to encode
177      * @return MD5 digested, hex encoded version of the input
178      */

179     public String JavaDoc md5Encode(String JavaDoc input) throws UnsupportedEncodingException JavaDoc {
180         // Digest
181
byte digestBytes[] = this.md5Digester.digest(input.getBytes("8859_1"));
182
183         // Write out in hex format
184
char outArray[] = new char[32];
185         for (int n = 0; n < digestBytes.length; n++) {
186             int hiNibble = (digestBytes[n] & 0xFF) >> 4;
187             int loNibble = (digestBytes[n] & 0xF);
188             outArray[2 * n] = (hiNibble > 9 ? (char) (hiNibble + 87)
189                     : (char) (hiNibble + 48));
190             outArray[2 * n + 1] = (loNibble > 9 ? (char) (loNibble + 87)
191                     : (char) (loNibble + 48));
192         }
193         return new String JavaDoc(outArray);
194     }
195 }
196
Popular Tags