1 28 29 package com.caucho.server.security; 30 31 import com.caucho.util.Base64; 32 import com.caucho.util.CharBuffer; 33 import com.caucho.util.CharCursor; 34 import com.caucho.util.RandomUtil; 35 import com.caucho.util.StringCharCursor; 36 import com.caucho.xml.XmlChar; 37 38 import javax.servlet.ServletContext ; 39 import javax.servlet.ServletException ; 40 import javax.servlet.http.HttpServletRequest ; 41 import javax.servlet.http.HttpServletResponse ; 42 import java.io.IOException ; 43 import java.security.Principal ; 44 import java.util.logging.Level ; 45 46 50 public class DigestLogin extends AbstractLogin { 51 protected String _realm; 52 53 56 public void setRealmName(String realm) 57 { 58 _realm = realm; 59 } 60 61 64 public String getRealmName() 65 { 66 return _realm; 67 } 68 69 72 public String getAuthType() 73 { 74 return "Digest"; 75 } 76 77 88 public Principal authenticate(HttpServletRequest request, 89 HttpServletResponse response, 90 ServletContext application) 91 throws ServletException , IOException 92 { 93 Principal user; 94 95 user = getAuthenticator().getUserPrincipal(request, response, application); 97 if (user != null) 98 return user; 99 100 user = getDigestPrincipal(request, response, application); 101 102 if (user != null) 103 return user; 104 105 sendDigestChallenge(response, application); 106 107 return null; 108 } 109 110 119 public Principal getUserPrincipal(HttpServletRequest request, 120 HttpServletResponse response, 121 ServletContext application) 122 throws ServletException 123 { 124 ServletAuthenticator auth = getAuthenticator(); 125 126 Principal user = auth.getUserPrincipal(request, response, application); 127 128 if (user != null) 129 return user; 130 131 return getDigestPrincipal(request, response, application); 132 } 133 134 137 protected void sendDigestChallenge(HttpServletResponse res, 138 ServletContext application) 139 throws ServletException , IOException 140 { 141 String realm = getRealmName(); 142 if (realm == null) 143 realm = "resin"; 144 145 CharBuffer cb = CharBuffer.allocate(); 146 Base64.encode(cb, getRandomLong(application)); 147 String nonce = cb.toString(); 148 cb.clear(); 149 cb.append("Digest "); 150 cb.append("realm=\""); 151 cb.append(realm); 152 cb.append("\", qop=\"auth\", "); 153 cb.append("nonce=\""); 154 cb.append(nonce); 155 cb.append("\""); 156 157 res.setHeader("WWW-Authenticate", cb.close()); 158 159 res.sendError(res.SC_UNAUTHORIZED); 160 } 161 162 protected long getRandomLong(ServletContext application) 163 { 164 return RandomUtil.getRandomLong(); 165 } 166 167 172 protected Principal getDigestPrincipal(HttpServletRequest request, 173 HttpServletResponse response, 174 ServletContext application) 175 throws ServletException 176 { 177 String value = request.getHeader("authorization"); 178 179 if (value == null) 180 return null; 181 182 String username = null; 183 String realm = null; 184 String uri = null; 185 String nonce = null; 186 String cnonce = null; 187 String nc = null; 188 String qop = null; 189 String digest = null; 190 191 CharCursor cursor = new StringCharCursor(value); 192 193 String key = scanKey(cursor); 194 195 if (! "Digest".equalsIgnoreCase(key)) 196 return null; 197 198 while ((key = scanKey(cursor)) != null) { 199 value = scanValue(cursor); 200 201 if (key.equals("username")) 202 username = value; 203 else if (key.equals("realm")) 204 realm = value; 205 else if (key.equals("uri")) 206 uri = value; 207 else if (key.equals("nonce")) 208 nonce = value; 209 else if (key.equals("response")) 210 digest = value; 211 else if (key.equals("cnonce")) 212 cnonce = value; 213 else if (key.equals("nc")) 214 nc = value; 215 else if (key.equals("qop")) 216 qop = value; 217 } 218 219 byte []clientDigest = decodeDigest(digest); 220 221 if (clientDigest == null || username == null || 222 uri == null || nonce == null) 223 return null; 224 225 ServletAuthenticator auth = getAuthenticator(); 226 Principal principal = auth.loginDigest(request, response, application, 227 username, realm, nonce, uri, 228 qop, nc, cnonce, 229 clientDigest); 230 231 if (log.isLoggable(Level.FINE)) 232 log.fine("digest: " + username + " -> " + principal); 233 234 return principal; 235 } 236 237 protected byte []decodeDigest(String digest) 238 { 239 if (digest == null) 240 return null; 241 242 int len = (digest.length() + 1) / 2; 243 byte []clientDigest = new byte[len]; 244 245 for (int i = 0; i + 1 < digest.length(); i += 2) { 246 int ch1 = digest.charAt(i); 247 int ch2 = digest.charAt(i + 1); 248 249 int b = 0; 250 if (ch1 >= '0' && ch1 <= '9') 251 b += ch1 - '0'; 252 else if (ch1 >= 'a' && ch1 <= 'f') 253 b += ch1 - 'a' + 10; 254 255 b *= 16; 256 257 if (ch2 >= '0' && ch2 <= '9') 258 b += ch2 - '0'; 259 else if (ch2 >= 'a' && ch2 <= 'f') 260 b += ch2 - 'a' + 10; 261 262 clientDigest[i / 2] = (byte) b; 263 } 264 265 return clientDigest; 266 } 267 268 protected String scanKey(CharCursor cursor) 269 throws ServletException 270 { 271 int ch; 272 while (XmlChar.isWhitespace((ch = cursor.current())) || ch == ',') { 273 cursor.next(); 274 } 275 276 ch = cursor.current(); 277 if (ch == cursor.DONE) 278 return null; 279 280 if (! XmlChar.isNameStart(ch)) 281 throw new ServletException ("bad key: " + (char) ch + " " + cursor); 282 283 CharBuffer cb = CharBuffer.allocate(); 284 while (XmlChar.isNameChar(ch = cursor.read())) { 285 cb.append((char) ch); 286 } 287 if (ch != cursor.DONE) 288 cursor.previous(); 289 290 return cb.close(); 291 } 292 293 protected String scanValue(CharCursor cursor) 294 throws ServletException 295 { 296 int ch; 297 skipWhitespace(cursor); 298 299 ch = cursor.read(); 300 if (ch != '=') 301 throw new ServletException ("expected '='"); 302 303 skipWhitespace(cursor); 304 305 CharBuffer cb = CharBuffer.allocate(); 306 307 ch = cursor.read(); 308 if (ch == '"') 309 while ((ch = cursor.read()) != cursor.DONE && ch != '"') 310 cb.append((char) ch); 311 else { 312 for (; 313 ch != cursor.DONE && ch != ',' && ! XmlChar.isWhitespace(ch); 314 ch = cursor.read()) 315 cb.append((char) ch); 316 317 if (ch != cursor.DONE) 318 cursor.previous(); 319 } 320 321 return cb.close(); 322 } 323 324 protected void skipWhitespace(CharCursor cursor) 325 { 326 while (XmlChar.isWhitespace(cursor.current())) { 327 cursor.next(); 328 } 329 } 330 } 331 | Popular Tags |