Package com.jeecms.common.security.rememberme

Source Code of com.jeecms.common.security.rememberme.AbstractRememberMeServices

package com.jeecms.common.security.rememberme;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import com.jeecms.common.security.AccountStatusException;
import com.jeecms.common.security.UsernameNotFoundException;
import com.jeecms.common.security.userdetails.AccountStatusUserDetailsChecker;
import com.jeecms.common.security.userdetails.UserDetails;
import com.jeecms.common.security.userdetails.UserDetailsChecker;
import com.jeecms.common.security.userdetails.UserDetailsService;

public abstract class AbstractRememberMeServices implements RememberMeService,
    InitializingBean {
  public static final String REMEMBER_ME_COOKIE_KEY = "remember_me_cookie";
  private static final String DELIMITER = ":";
  public static final String DEFAULT_PARAMETER = "remember_me";
  public static final int TWO_WEEKS_S = 1209600;
  private String cookieName = REMEMBER_ME_COOKIE_KEY;
  private String parameter = DEFAULT_PARAMETER;
  private int tokenValiditySeconds = TWO_WEEKS_S;
  private boolean alwaysRemember;
  private boolean alwaysRememberCookie;
  private String key;
  private UserDetailsChecker userDetailsChecker = new AccountStatusUserDetailsChecker();

  private UserDetailsService userDetailsService;
  protected final Logger logger = LoggerFactory.getLogger(getClass());

  public final UserDetails autoLogin(HttpServletRequest request,
      HttpServletResponse response) throws CookieTheftException {
    String rememberMeCookie = extractRememberMeCookie(request);

    if (rememberMeCookie == null) {
      return null;
    }

    logger.debug("Remember-me cookie detected");

    UserDetails user = null;

    String[] cookieTokens;
    try {
      cookieTokens = decodeCookie(rememberMeCookie);
      user = processAutoLoginCookie(cookieTokens, request, response);
      userDetailsChecker.check(user);
    } catch (CookieTheftException cte) {
      cancelCookie(request, response);
      throw cte;
    } catch (UsernameNotFoundException noUser) {
      cancelCookie(request, response);
      logger.debug("Remember-me login was valid"
          + " but corresponding user not found.", noUser);
      return null;
    } catch (InvalidCookieException invalidCookie) {
      cancelCookie(request, response);
      logger.debug("Invalid remember-me cookie: "
          + invalidCookie.getMessage());
      return null;
    } catch (AccountStatusException statusInvalid) {
      cancelCookie(request, response);
      logger.debug("Invalid UserDetails: " + statusInvalid.getMessage());
      return null;
    } catch (RememberMeAuthenticationException e) {
      cancelCookie(request, response);
      logger.debug(e.getMessage());
      return null;
    }
    logger.debug("Remember-me cookie accepted");
    return user;
  }

  /**
   * Examines the incoming request and checks for the presence of the
   * configured "remember me" parameter. If it's present, or if
   * <tt>alwaysRemember</tt> is set to true, calls <tt>onLoginSucces</tt>.
   */
  public final boolean loginSuccess(HttpServletRequest request,
      HttpServletResponse response, UserDetails user) {

    if (!rememberMeRequested(request, parameter)) {
      logger.debug("Remember-me login not requested.");
      return false;
    }

    return onLoginSuccess(request, response, user);
  }

  public final void loginFail(HttpServletRequest request,
      HttpServletResponse response) {
    logger.debug("Interactive login attempt was unsuccessful.");
    cancelCookie(request, response);
    onLoginFail(request, response);
  }

  public void logout(HttpServletRequest request, HttpServletResponse response) {
    logger.debug("Remember-me logout.");
    cancelCookie(request, response);
    onLogout(request, response);
  }

  /**
   * Locates the Spring Security remember me cookie in the request and returns
   * its value.
   *
   * @param request
   *            the submitted request which is to be authenticated
   * @return the cookie value (if present), null otherwise.
   */
  protected String extractRememberMeCookie(HttpServletRequest request) {
    Cookie[] cookies = request.getCookies();

    if ((cookies == null) || (cookies.length == 0)) {
      return null;
    }

    for (int i = 0; i < cookies.length; i++) {
      if (cookieName.equals(cookies[i].getName())) {
        return cookies[i].getValue();
      }
    }
    return null;
  }

  /**
   * Allows customization of whether a remember-me login has been requested.
   * The default is to return true if <tt>alwaysRemember</tt> is set or the
   * configured parameter name has been included in the request and is set to
   * the value "true".
   *
   * @param request
   *            the request submitted from an interactive login, which may
   *            include additional information indicating that a persistent
   *            login is desired.
   * @param parameter
   *            the configured remember-me parameter name.
   *
   * @return true if the request includes information indicating that a
   *         persistent login has been requested.
   */
  protected boolean rememberMeRequested(HttpServletRequest request,
      String parameter) {
    if (alwaysRemember) {
      return true;
    }

    String paramValue = request.getParameter(parameter);

    if (paramValue != null) {
      if (paramValue.equalsIgnoreCase("true")
          || paramValue.equalsIgnoreCase("on")
          || paramValue.equalsIgnoreCase("yes")
          || paramValue.equals("1")) {
        return true;
      }
    }

    if (logger.isDebugEnabled()) {
      logger.debug("Did not send remember-me cookie"
          + " (principal did not set parameter '" + parameter + "')");
    }

    return false;
  }

  /**
   * Sets the cookie on the response
   *
   * @param tokens
   *            the tokens which will be encoded to make the cookie value.
   * @param maxAge
   *            the value passed to {@link Cookie#setMaxAge(int)}
   * @param request
   *            the request
   * @param response
   *            the response to add the cookie to.
   */
  protected void setCookie(String[] tokens, int maxAge,
      HttpServletRequest request, HttpServletResponse response) {
    String cookieValue = encodeCookie(tokens);
    Cookie cookie = new Cookie(cookieName, cookieValue);
    String ctx = request.getContextPath();
    cookie.setPath(StringUtils.hasText(ctx) ? ctx : "/");
    cookie.setMaxAge(maxAge);
    response.addCookie(cookie);
  }

  /**
   * Sets a "cancel cookie" (with maxAge = 0) on the response to disable
   * persistent logins.
   *
   * @param request
   * @param response
   */
  protected void cancelCookie(HttpServletRequest request,
      HttpServletResponse response) {
    logger.debug("Cancelling cookie");
    Cookie cookie = new Cookie(cookieName, null);
    String ctx = request.getContextPath();
    cookie.setPath(StringUtils.hasText(ctx) ? ctx : "/");
    cookie.setMaxAge(0);
    response.addCookie(cookie);
  }

  /**
   * Decodes the cookie and splits it into a set of token strings using the
   * ":" delimiter.
   *
   * @param cookieValue
   *            the value obtained from the submitted cookie
   * @return the array of tokens.
   * @throws InvalidCookieException
   *             if the cookie was not base64 encoded.
   */
  protected String[] decodeCookie(String cookieValue)
      throws InvalidCookieException {
    StringBuilder sb = new StringBuilder(cookieValue.length() + 3)
        .append(cookieValue);
    for (int j = 0; j < sb.length() % 4; j++) {
      sb.append("=");
    }
    cookieValue = sb.toString();
    if (!Base64.isArrayByteBase64(cookieValue.getBytes())) {
      throw new InvalidCookieException(
          "Cookie token was not Base64 encoded; value was '"
              + cookieValue + "'");
    }

    String cookieAsPlainText = new String(Base64.decodeBase64(cookieValue
        .getBytes()));

    return StringUtils.delimitedListToStringArray(cookieAsPlainText,
        DELIMITER);
  }

  /**
   * Inverse operation of decodeCookie.
   *
   * @param cookieTokens
   *            the tokens to be encoded.
   * @return base64 encoding of the tokens concatenated with the ":"
   *         delimiter.
   */
  protected String encodeCookie(String[] cookieTokens) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < cookieTokens.length; i++) {
      sb.append(cookieTokens[i]);

      if (i < cookieTokens.length - 1) {
        sb.append(DELIMITER);
      }
    }

    String value = sb.toString();

    sb = new StringBuilder(
        new String(Base64.encodeBase64(value.getBytes())));

    while (sb.charAt(sb.length() - 1) == '=') {
      sb.deleteCharAt(sb.length() - 1);
    }

    return sb.toString();
  }

  /**
   * Called from autoLogin to process the submitted persistent login cookie.
   * Subclasses should validate the cookie and perform any additional
   * management required.
   *
   * @param cookieTokens
   *            the decoded and tokenized cookie value
   * @param request
   *            the request
   * @param response
   *            the response, to allow the cookie to be modified if required.
   * @return the UserDetails for the corresponding user account if the cookie
   *         was validated successfully.
   * @throws RememberMeAuthenticationException
   *             if the cookie is invalid or the login is invalid for some
   *             other reason.
   * @throws UsernameNotFoundException
   *             if the user account corresponding to the login cookie
   *             couldn't be found (for example if the user has been removed
   *             from the system).
   */
  protected abstract UserDetails processAutoLoginCookie(
      String[] cookieTokens, HttpServletRequest request,
      HttpServletResponse response)
      throws RememberMeAuthenticationException, UsernameNotFoundException;

  /**
   * Called from loginSuccess when a remember-me login has been requested.
   * Typically implemented by subclasses to set a remember-me cookie and
   * potentially store a record of it if the implementation requires this.
   */
  protected abstract boolean onLoginSuccess(HttpServletRequest request,
      HttpServletResponse response, UserDetails user);

  protected void onLoginFail(HttpServletRequest request,
      HttpServletResponse response) {
  }

  protected void onLogout(HttpServletRequest request,
      HttpServletResponse response) {
  }

  public void afterPropertiesSet() throws Exception {
    Assert.hasLength(key);
    Assert.hasLength(parameter);
    Assert.hasLength(cookieName);
    Assert.notNull(userDetailsService);
  }

  protected String getCookieName() {
    return cookieName;
  }

  public void setCookieName(String cookieName) {
    this.cookieName = cookieName;
  }

  public boolean isAlwaysRemember() {
    return alwaysRemember;
  }

  public void setAlwaysRemember(boolean alwaysRemember) {
    this.alwaysRemember = alwaysRemember;
  }

  public String getParameter() {
    return parameter;
  }

  public void setParameter(String parameter) {
    this.parameter = parameter;
  }

  public UserDetailsService getUserDetailsService() {
    return userDetailsService;
  }

  public void setUserDetailsService(UserDetailsService userDetailsService) {
    this.userDetailsService = userDetailsService;
  }

  public String getKey() {
    return key;
  }

  public void setKey(String key) {
    this.key = key;
  }

  protected int getTokenValiditySeconds() {
    return tokenValiditySeconds;
  }

  public void setTokenValiditySeconds(int tokenValiditySeconds) {
    this.tokenValiditySeconds = tokenValiditySeconds;
  }

  public boolean isAlwaysRememberCookie() {
    return alwaysRememberCookie;
  }

  public void setAlwaysRememberCookie(boolean alwaysRememberCookie) {
    this.alwaysRememberCookie = alwaysRememberCookie;
  }
}
TOP

Related Classes of com.jeecms.common.security.rememberme.AbstractRememberMeServices

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.