@BeforeMethod
  public void setUp() throws Exception {
    _service = mock(MemcachedSessionService.class);
    _request = mock(Request.class);
    _response = mock(Response.class);

    final Context _contextContainer = mock(Context.class);
    final Host _hostContainer = mock(Host.class);
    final SessionManager _manager = mock(SessionManager.class);

    when(_service.getManager()).thenReturn(_manager);
    when(_manager.getContainer()).thenReturn(_contextContainer);
    when(_contextContainer.getParent()).thenReturn(_hostContainer);
    when(_contextContainer.getPath()).thenReturn("/");

    _sessionTrackerValve = createSessionTrackerValve();
    _nextValve = mock(Valve.class);
    _sessionTrackerValve.setNext(_nextValve);
    _sessionTrackerValve.setContainer(_hostContainer);
    _memcachedNodesManager = mock(MemcachedNodesManager.class);
    _sessionIdFormat = mock(SessionIdFormat.class);

    when(_request.getRequestURI()).thenReturn("/someRequest");
    when(_request.getMethod()).thenReturn("GET");
    when(_request.getQueryString()).thenReturn(null);
    when(_request.getContext()).thenReturn(_contextContainer);

    when(_request.getNote(eq(RequestTrackingHostValve.REQUEST_PROCESSED))).thenReturn(Boolean.TRUE);
    when(_request.getNote(eq(RequestTrackingHostValve.SESSION_ID_CHANGED)))
        .thenReturn(Boolean.FALSE);

    when(_sessionIdFormat.extractMemcachedId(anyString())).thenReturn(PRIMARY_NODE_IDENTIFIER);
    when(_service.getMemcachedNodesManager()).thenReturn(_memcachedNodesManager);
    when(_memcachedNodesManager.isNodeAvailable(PRIMARY_NODE_IDENTIFIER))
        .thenReturn(IS_PRIMARY_MEMCACHED_NODE_OPERATIONAL);
    when(_memcachedNodesManager.getSessionIdFormat()).thenReturn(_sessionIdFormat);
  }
  @Test
  public final void testChangeSessionIdForRelocatedSession() throws IOException, ServletException {

    final String sessionId = "bar";
    final String newSessionId = "newId";

    when(_request.getNote(eq(RequestTrackingHostValve.SESSION_ID_CHANGED)))
        .thenReturn(Boolean.TRUE);
    when(_request.getRequestedSessionId()).thenReturn(sessionId);

    final Cookie cookie = new Cookie(_sessionTrackerValve.getSessionCookieName(), newSessionId);
    setupGetResponseSetCookieHeadersExpectations(
        _response, new String[] {generateCookieString(cookie)});

    _sessionTrackerValve.invoke(_request, _response);

    verify(_service).backupSession(eq(newSessionId), eq(true), anyString());
  }
  /**
   * Authenticate the user making this request, based on the specified login configuration. Return
   * <code>true</code> if any specified constraint has been satisfied, or <code>false</code> if we
   * have created a response challenge already.
   *
   * @param request Request we are processing
   * @param response Response we are creating
   * @param config Login configuration describing how authentication should be performed
   * @exception IOException if an input/output error occurs
   */
  @Override
  public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config)
      throws IOException {

    // Have we already authenticated someone?
    Principal principal = request.getUserPrincipal();
    String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
    if (principal != null) {
      if (log.isDebugEnabled()) log.debug("Already authenticated '" + principal.getName() + "'");
      // Associate the session with any existing SSO session
      if (ssoId != null) associate(ssoId, request.getSessionInternal(true));
      return (true);
    }

    // Is there an SSO session against which we can try to reauthenticate?
    if (ssoId != null) {
      if (log.isDebugEnabled())
        log.debug("SSO Id " + ssoId + " set; attempting " + "reauthentication");
      /* Try to reauthenticate using data cached by SSO.  If this fails,
      either the original SSO logon was of DIGEST or SSL (which
      we can't reauthenticate ourselves because there is no
      cached username and password), or the realm denied
      the user's reauthentication for some reason.
      In either case we have to prompt the user for a logon */
      if (reauthenticateFromSSO(ssoId, request)) return true;
    }

    // Validate any credentials already included with this request
    String username = null;
    String password = null;

    MessageBytes authorization =
        request.getCoyoteRequest().getMimeHeaders().getValue("authorization");

    if (authorization != null) {
      authorization.toBytes();
      ByteChunk authorizationBC = authorization.getByteChunk();
      if (authorizationBC.startsWithIgnoreCase("basic ", 0)) {
        authorizationBC.setOffset(authorizationBC.getOffset() + 6);
        // FIXME: Add trimming
        // authorizationBC.trim();

        CharChunk authorizationCC = authorization.getCharChunk();
        Base64.decode(authorizationBC, authorizationCC);

        // Get username and password
        int colon = authorizationCC.indexOf(':');
        if (colon < 0) {
          username = authorizationCC.toString();
        } else {
          char[] buf = authorizationCC.getBuffer();
          username = new String(buf, 0, colon);
          password = new String(buf, colon + 1, authorizationCC.getEnd() - colon - 1);
        }

        authorizationBC.setOffset(authorizationBC.getOffset() - 6);
      }

      principal = context.getRealm().authenticate(username, password);
      if (principal != null) {
        register(request, response, principal, Constants.BASIC_METHOD, username, password);
        return (true);
      }
    }

    StringBuilder value = new StringBuilder(16);
    value.append("Basic realm=\"");
    if (config.getRealmName() == null) {
      value.append(REALM_NAME);
    } else {
      value.append(config.getRealmName());
    }
    value.append('\"');
    response.setHeader(AUTH_HEADER_NAME, value.toString());
    response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
    return (false);
  }
  /**
   * Authenticate the user making this request, based on the specified login configuration. Return
   * <code>true</code> if any specified constraint has been satisfied, or <code>false</code> if we
   * have created a response challenge already.
   *
   * @param request Request we are processing
   * @param response Response we are creating
   * @exception IOException if an input/output error occurs
   */
  @Override
  public boolean authenticate(Request request, HttpServletResponse response) throws IOException {

    // Have we already authenticated someone?
    Principal principal = request.getUserPrincipal();
    // String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
    if (principal != null) {
      if (log.isDebugEnabled()) {
        log.debug("Already authenticated '" + principal.getName() + "'");
      }
      // Associate the session with any existing SSO session in order
      // to get coordinated session invalidation at logout
      String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
      if (ssoId != null) {
        associate(ssoId, request.getSessionInternal(true));
      }
      return (true);
    }

    // NOTE: We don't try to reauthenticate using any existing SSO session,
    // because that will only work if the original authentication was
    // BASIC or FORM, which are less secure than the DIGEST auth-type
    // specified for this webapp
    //
    // Uncomment below to allow previous FORM or BASIC authentications
    // to authenticate users for this webapp
    // TODO make this a configurable attribute (in SingleSignOn??)
    /*
    // Is there an SSO session against which we can try to reauthenticate?
    if (ssoId != null) {
        if (log.isDebugEnabled())
            log.debug("SSO Id " + ssoId + " set; attempting " +
                      "reauthentication");
        // Try to reauthenticate using data cached by SSO.  If this fails,
        // either the original SSO logon was of DIGEST or SSL (which
        // we can't reauthenticate ourselves because there is no
        // cached username and password), or the realm denied
        // the user's reauthentication for some reason.
        // In either case we have to prompt the user for a logon
        if (reauthenticateFromSSO(ssoId, request))
            return true;
    }
    */

    // Validate any credentials already included with this request
    String authorization = request.getHeader("authorization");
    DigestInfo digestInfo =
        new DigestInfo(getOpaque(), getNonceValidity(), getKey(), nonces, isValidateUri());
    if (authorization != null) {
      if (digestInfo.parse(request, authorization)) {
        if (digestInfo.validate(request)) {
          principal = digestInfo.authenticate(context.getRealm());
        }

        if (principal != null && !digestInfo.isNonceStale()) {
          register(
              request,
              response,
              principal,
              HttpServletRequest.DIGEST_AUTH,
              digestInfo.getUsername(),
              null);
          return true;
        }
      }
    }

    // Send an "unauthorized" response and an appropriate challenge

    // Next, generate a nonce token (that is a token which is supposed
    // to be unique).
    String nonce = generateNonce(request);

    setAuthenticateHeader(request, response, nonce, principal != null && digestInfo.isNonceStale());
    response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
    return false;
  }