digestlogin.java

来自「RESIN 3.2 最新源码」· Java 代码 · 共 331 行

JAVA
331
字号
/* * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT.  See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the *   Free SoftwareFoundation, Inc. *   59 Temple Place, Suite 330 *   Boston, MA 02111-1307  USA * * @author Scott Ferguson */package com.caucho.server.security;import com.caucho.util.Base64;import com.caucho.util.CharBuffer;import com.caucho.util.CharCursor;import com.caucho.util.RandomUtil;import com.caucho.util.StringCharCursor;import com.caucho.xml.XmlChar;import javax.servlet.ServletContext;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.security.Principal;import java.util.logging.Level;/** * Implements the "digest" auth-method.  Basic uses the * HTTP authentication with WWW-Authenticate and SC_UNAUTHORIZE. */public class DigestLogin extends AbstractLogin {  protected String _realm;    /**   * Sets the login realm.   */  public void setRealmName(String realm)  {    _realm = realm;  }  /**   * Gets the realm.   */  public String getRealmName()  {    return _realm;  }  /**   * Returns the authentication type.   */  public String getAuthType()  {    return "Digest";  }    /**   * Logs a user in with a user name and a password.  Basic authentication   * extracts the user and password from the authorization header.  If   * the user/password is missing, authenticate will send a basic challenge.   *   * @param request servlet request   * @param response servlet response, in case any cookie need sending.   * @param application servlet application   *   * @return the logged in principal on success, null on failure.   */  public Principal authenticate(HttpServletRequest request,                                HttpServletResponse response,                                ServletContext application)    throws ServletException, IOException  {    Principal user;    // If the user is already logged-in, return the user    user = getAuthenticator().getUserPrincipal(request, response, application);    if (user != null)      return user;        user = getDigestPrincipal(request, response, application);    if (user != null)      return user;    sendDigestChallenge(response, application);        return null;  }    /**   * Returns the current user with the user name and password.   *   * @param request servlet request   * @param response servlet response, in case any cookie need sending.   * @param application servlet application   *   * @return the logged in principal on success, null on failure.   */  public Principal getUserPrincipal(HttpServletRequest request,                                    HttpServletResponse response,                                    ServletContext application)    throws ServletException  {    ServletAuthenticator auth = getAuthenticator();        Principal user = auth.getUserPrincipal(request, response, application);    if (user != null)      return user;        return getDigestPrincipal(request, response, application);  }  /**   * Sends a challenge for basic authentication.   */  protected void sendDigestChallenge(HttpServletResponse res,                                     ServletContext application)    throws ServletException, IOException  {    String realm = getRealmName();    if (realm == null)      realm = "resin";    CharBuffer cb = CharBuffer.allocate();    Base64.encode(cb, getRandomLong(application));    String nonce = cb.toString();    cb.clear();    cb.append("Digest ");    cb.append("realm=\"");    cb.append(realm);    cb.append("\", qop=\"auth\", ");    cb.append("nonce=\"");    cb.append(nonce);    cb.append("\"");    res.setHeader("WWW-Authenticate", cb.close());        res.sendError(res.SC_UNAUTHORIZED);  }  protected long getRandomLong(ServletContext application)  {    return RandomUtil.getRandomLong();  }  /**   * Returns the principal from a basic authentication   *   * @param auth the authenticator for this application.   */  protected Principal getDigestPrincipal(HttpServletRequest request,                                         HttpServletResponse response,                                         ServletContext application)    throws ServletException  {    String value = request.getHeader("authorization");    if (value == null)      return null;    String username = null;    String realm = null;    String uri = null;    String nonce = null;    String cnonce = null;    String nc = null;    String qop = null;    String digest = null;    CharCursor cursor = new StringCharCursor(value);    String key = scanKey(cursor);    if (! "Digest".equalsIgnoreCase(key))      return null;          while ((key = scanKey(cursor)) != null) {      value = scanValue(cursor);      if (key.equals("username"))        username = value;      else if (key.equals("realm"))        realm = value;      else if (key.equals("uri"))        uri = value;      else if (key.equals("nonce"))        nonce = value;      else if (key.equals("response"))        digest = value;      else if (key.equals("cnonce"))        cnonce = value;      else if (key.equals("nc"))        nc = value;      else if (key.equals("qop"))        qop = value;    }    byte []clientDigest = decodeDigest(digest);    if (clientDigest == null || username == null ||        uri == null || nonce == null)      return null;    ServletAuthenticator auth = getAuthenticator();    Principal principal = auth.loginDigest(request, response, application,                                           username, realm, nonce, uri,                                           qop, nc, cnonce,                                           clientDigest);        if (log.isLoggable(Level.FINE))      log.fine("digest: " + username + " -> " + principal);    return principal;  }  protected byte []decodeDigest(String digest)  {    if (digest == null)      return null;        int len = (digest.length() + 1) / 2;    byte []clientDigest = new byte[len];    for (int i = 0; i + 1 < digest.length(); i += 2) {      int ch1 = digest.charAt(i);      int ch2 = digest.charAt(i + 1);      int b = 0;      if (ch1 >= '0' && ch1 <= '9')        b += ch1 - '0';      else if (ch1 >= 'a' && ch1 <= 'f')        b += ch1 - 'a' + 10;      b *= 16;            if (ch2 >= '0' && ch2 <= '9')        b += ch2 - '0';      else if (ch2 >= 'a' && ch2 <= 'f')        b += ch2 - 'a' + 10;      clientDigest[i / 2] = (byte) b;    }    return clientDigest;  }  protected String scanKey(CharCursor cursor)    throws ServletException  {    int ch;    while (XmlChar.isWhitespace((ch = cursor.current())) || ch == ',') {      cursor.next();    }    ch = cursor.current();    if (ch == cursor.DONE)      return null;        if (! XmlChar.isNameStart(ch))      throw new ServletException("bad key: " + (char) ch + " " + cursor);    CharBuffer cb = CharBuffer.allocate();    while (XmlChar.isNameChar(ch = cursor.read())) {      cb.append((char) ch);    }    if (ch != cursor.DONE)      cursor.previous();    return cb.close();  }  protected String scanValue(CharCursor cursor)    throws ServletException  {    int ch;    skipWhitespace(cursor);    ch = cursor.read();    if (ch != '=')      throw new ServletException("expected '='");    skipWhitespace(cursor);        CharBuffer cb = CharBuffer.allocate();        ch = cursor.read();    if (ch == '"')      while ((ch = cursor.read()) != cursor.DONE && ch != '"')        cb.append((char) ch);    else {      for (;           ch != cursor.DONE && ch != ',' && ! XmlChar.isWhitespace(ch);           ch = cursor.read())        cb.append((char) ch);      if (ch != cursor.DONE)	cursor.previous();    }    return cb.close();  }  protected void skipWhitespace(CharCursor cursor)  {    while (XmlChar.isWhitespace(cursor.current())) {      cursor.next();    }  }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?