//# 0 errors, 77 messages
//#
/*
    //#securitytokenvalidator.java:1:1: class: net.sourceforge.pebble.web.security.SecurityTokenValidator
 * Copyright (c) 2003-2005, Simon Brown
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   - Neither the name of Pebble nor the names of its contributors may
 *     be used to endorse or promote products derived from this software
 *     without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
package net.sourceforge.pebble.web.security;

import net.sourceforge.pebble.web.action.Action;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.security.SecureRandom;

/**
 * Checks requests for a security token
 *
 * @author James Roper
 */
public class SecurityTokenValidator {
    //#securitytokenvalidator.java:46: method: void net.sourceforge.pebble.web.security.SecurityTokenValidator.net.sourceforge.pebble.web.security.SecurityTokenValidator()
    //#securitytokenvalidator.java:46: end of method: void net.sourceforge.pebble.web.security.SecurityTokenValidator.net.sourceforge.pebble.web.security.SecurityTokenValidator()

  /**
   * the security token name
   */
  public static final String PEBBLE_SECURITY_TOKEN_PARAMETER = "pebbleSecurityToken";

  /**
   * the header for bypassing security token checks
   */
  private static final String PEBBLE_SECURITY_TOKEN_HEADER = "X-Pebble-Token";

  /**
   * the value the header should be for not checking
   */
  private static final String PEBBLE_SECURITY_TOKEN_HEADER_NOCHECK = "nocheck";

  /**
   * For generating secure tokens
   */
  private static final SecureRandom random = new SecureRandom();
    //#securitytokenvalidator.java:66: method: net.sourceforge.pebble.web.security.SecurityTokenValidator.net.sourceforge.pebble.web.security.SecurityTokenValidator__static_init
    //#output(net.sourceforge.pebble.web.security.SecurityTokenValidator__static_init): __Descendant_Table[net/sourceforge/pebble/web/security/SecurityTokenValidator]
    //#output(net.sourceforge.pebble.web.security.SecurityTokenValidator__static_init): __Dispatch_Table.ensureSecurityTokenExists(Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)Ljava/lang/String;
    //#output(net.sourceforge.pebble.web.security.SecurityTokenValidator__static_init): __Dispatch_Table.shouldValidate(Lnet/sourceforge/pebble/web/action/Action;Ljavax/servlet/http/HttpServletRequest;)Z
    //#output(net.sourceforge.pebble.web.security.SecurityTokenValidator__static_init): __Dispatch_Table.validateSecurityToken(Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;Lnet/sourceforge/pebble/web/action/Action;)Z
    //#output(net.sourceforge.pebble.web.security.SecurityTokenValidator__static_init): new SecureRandom(SecurityTokenValidator__static_init#1) num objects
    //#output(net.sourceforge.pebble.web.security.SecurityTokenValidator__static_init): random
    //#new obj(net.sourceforge.pebble.web.security.SecurityTokenValidator__static_init): new SecureRandom(SecurityTokenValidator__static_init#1)
    //#post(net.sourceforge.pebble.web.security.SecurityTokenValidator__static_init): __Descendant_Table[net/sourceforge/pebble/web/security/SecurityTokenValidator] == &__Dispatch_Table
    //#post(net.sourceforge.pebble.web.security.SecurityTokenValidator__static_init): __Dispatch_Table.ensureSecurityTokenExists(Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)Ljava/lang/String; == &ensureSecurityTokenExists
    //#post(net.sourceforge.pebble.web.security.SecurityTokenValidator__static_init): __Dispatch_Table.shouldValidate(Lnet/sourceforge/pebble/web/action/Action;Ljavax/servlet/http/HttpServletRequest;)Z == &shouldValidate
    //#post(net.sourceforge.pebble.web.security.SecurityTokenValidator__static_init): __Dispatch_Table.validateSecurityToken(Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;Lnet/sourceforge/pebble/web/action/Action;)Z == &validateSecurityToken
    //#post(net.sourceforge.pebble.web.security.SecurityTokenValidator__static_init): random == &new SecureRandom(SecurityTokenValidator__static_init#1)
    //#post(net.sourceforge.pebble.web.security.SecurityTokenValidator__static_init): new SecureRandom(SecurityTokenValidator__static_init#1) num objects == 1
    //#securitytokenvalidator.java:66: end of method: net.sourceforge.pebble.web.security.SecurityTokenValidator.net.sourceforge.pebble.web.security.SecurityTokenValidator__static_init

  /**
   * Validate the security token for this request, if necessary, setting up the security token cookie if it doesn't
   * exist
   *
   * @param request The request to validate
   * @param response The response
   * @param action The action to validate
   * @return true if the request can proceed, false if not
   */
  public boolean validateSecurityToken(HttpServletRequest request, HttpServletResponse response, Action action) {
    // First, ensure that there is a security token, for future requests
    String token = ensureSecurityTokenExists(request, response);
    //#securitytokenvalidator.java:79: method: bool net.sourceforge.pebble.web.security.SecurityTokenValidator.validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)
    //#securitytokenvalidator.java:79: Warning: method not available
    //#    -- call on String ensureSecurityTokenExists(HttpServletRequest, HttpServletResponse)
    //#    severity: INFORMATIONAL
    //#    class: net.sourceforge.pebble.web.security.SecurityTokenValidator
    //#    method: bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)
    //#    unanalyzed callee: String ensureSecurityTokenExists(HttpServletRequest, HttpServletResponse)
    //#input(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): action
    //#input(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): net/sourceforge/pebble/web/action/UtilitiesAction$UtilitiesCondition.__Dispatch_Table.shouldValidate(Ljavax/servlet/http/HttpServletRequest;)Z
    //#input(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): net/sourceforge/pebble/web/security/NullSecurityTokenValidatorCondition.__Dispatch_Table.shouldValidate(Ljavax/servlet/http/HttpServletRequest;)Z
    //#input(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): net/sourceforge/pebble/web/security/RequireSecurityToken.__Descendant_Table[net/sourceforge/pebble/web/security/RequireSecurityToken]
    //#input(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): net/sourceforge/pebble/web/security/RequireSecurityToken.__Descendant_Table[others]
    //#input(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): net/sourceforge/pebble/web/security/RequireSecurityToken.__Dispatch_Table.value()Ljava/lang/Class;
    //#input(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): net/sourceforge/pebble/web/security/SecurityTokenValidatorCondition.__Descendant_Table[net/sourceforge/pebble/web/action/UtilitiesAction$UtilitiesCondition]
    //#input(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): net/sourceforge/pebble/web/security/SecurityTokenValidatorCondition.__Descendant_Table[net/sourceforge/pebble/web/security/NullSecurityTokenValidatorCondition]
    //#input(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): net/sourceforge/pebble/web/security/SecurityTokenValidatorCondition.__Descendant_Table[net/sourceforge/pebble/web/security/SecurityTokenValidatorCondition]
    //#input(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): net/sourceforge/pebble/web/security/SecurityTokenValidatorCondition.__Descendant_Table[others]
    //#input(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): net/sourceforge/pebble/web/security/SecurityTokenValidatorCondition.__Dispatch_Table.shouldValidate(Ljavax/servlet/http/HttpServletRequest;)Z
    //#input(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): request
    //#input(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): response
    //#input(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): this
    //#output(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): return_value
    //#pre[1] (bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): action != null
    //#pre[2] (bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): (soft) request != null
    //#presumption(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): ensureSecurityTokenExists(...)@79 != null
    //#post(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): init'ed(return_value)
    //#unanalyzed(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): Effects-of-calling:java.lang.Object:getClass
    //#unanalyzed(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): Effects-of-calling:java.lang.Class:getAnnotation
    //#unanalyzed(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): Effects-of-calling:value
    //#unanalyzed(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): Effects-of-calling:java.lang.Class:newInstance
    //#unanalyzed(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): Effects-of-calling:javax.servlet.http.HttpServletRequest:getParameter
    //#unanalyzed(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): Effects-of-calling:shouldValidate
    //#unanalyzed(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): Effects-of-calling:java.lang.RuntimeException
    //#test_vector(bool validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)): java.lang.String:equals(...)@83: {0}, {1}
    if (shouldValidate(action, request)) {
      // Check for the header is there... XSRF attacks can't set custom headers, so if this header is there,
      // it must be safe
      if (PEBBLE_SECURITY_TOKEN_HEADER_NOCHECK.equals(request.getHeader(PEBBLE_SECURITY_TOKEN_HEADER))) {
        return true;
      }
      // We must validate the token
      String requestToken = request.getParameter(PEBBLE_SECURITY_TOKEN_PARAMETER);
      // Compare token to cookie
      return token.equals(requestToken);
    } else {
      return true;
    //#securitytokenvalidator.java:91: end of method: bool net.sourceforge.pebble.web.security.SecurityTokenValidator.validateSecurityToken(HttpServletRequest, HttpServletResponse, Action)
    }
  }

  private boolean shouldValidate(Action action, HttpServletRequest request)
  {
    RequireSecurityToken annotation = action.getClass().getAnnotation(RequireSecurityToken.class);
    //#securitytokenvalidator.java:97: method: bool net.sourceforge.pebble.web.security.SecurityTokenValidator.shouldValidate(Action, HttpServletRequest)
    //#input(bool shouldValidate(Action, HttpServletRequest)): action
    //#input(bool shouldValidate(Action, HttpServletRequest)): net/sourceforge/pebble/web/action/UtilitiesAction$UtilitiesCondition.__Dispatch_Table.shouldValidate(Ljavax/servlet/http/HttpServletRequest;)Z
    //#input(bool shouldValidate(Action, HttpServletRequest)): net/sourceforge/pebble/web/security/NullSecurityTokenValidatorCondition.__Dispatch_Table.shouldValidate(Ljavax/servlet/http/HttpServletRequest;)Z
    //#input(bool shouldValidate(Action, HttpServletRequest)): net/sourceforge/pebble/web/security/RequireSecurityToken.__Descendant_Table[net/sourceforge/pebble/web/security/RequireSecurityToken]
    //#input(bool shouldValidate(Action, HttpServletRequest)): net/sourceforge/pebble/web/security/RequireSecurityToken.__Descendant_Table[others]
    //#input(bool shouldValidate(Action, HttpServletRequest)): net/sourceforge/pebble/web/security/RequireSecurityToken.__Dispatch_Table.value()Ljava/lang/Class;
    //#input(bool shouldValidate(Action, HttpServletRequest)): net/sourceforge/pebble/web/security/SecurityTokenValidatorCondition.__Descendant_Table[net/sourceforge/pebble/web/action/UtilitiesAction$UtilitiesCondition]
    //#input(bool shouldValidate(Action, HttpServletRequest)): net/sourceforge/pebble/web/security/SecurityTokenValidatorCondition.__Descendant_Table[net/sourceforge/pebble/web/security/NullSecurityTokenValidatorCondition]
    //#input(bool shouldValidate(Action, HttpServletRequest)): net/sourceforge/pebble/web/security/SecurityTokenValidatorCondition.__Descendant_Table[net/sourceforge/pebble/web/security/SecurityTokenValidatorCondition]
    //#input(bool shouldValidate(Action, HttpServletRequest)): net/sourceforge/pebble/web/security/SecurityTokenValidatorCondition.__Descendant_Table[others]
    //#input(bool shouldValidate(Action, HttpServletRequest)): net/sourceforge/pebble/web/security/SecurityTokenValidatorCondition.__Dispatch_Table.shouldValidate(Ljavax/servlet/http/HttpServletRequest;)Z
    //#input(bool shouldValidate(Action, HttpServletRequest)): request
    //#output(bool shouldValidate(Action, HttpServletRequest)): return_value
    //#pre[1] (bool shouldValidate(Action, HttpServletRequest)): action != null
    //#presumption(bool shouldValidate(Action, HttpServletRequest)): java.lang.Class:getAnnotation(...).__Tag@97 == net/sourceforge/pebble/web/security/RequireSecurityToken
    //#presumption(bool shouldValidate(Action, HttpServletRequest)): java.lang.Class:newInstance(...).__Tag@104 in {net/sourceforge/pebble/web/action/UtilitiesAction$UtilitiesCondition, net/sourceforge/pebble/web/security/NullSecurityTokenValidatorCondition, net/sourceforge/pebble/web/security/SecurityTokenValidatorCondition}
    //#presumption(bool shouldValidate(Action, HttpServletRequest)): java.lang.Object:getClass(...)@97 != null
    //#post(bool shouldValidate(Action, HttpServletRequest)): init'ed(return_value)
    //#unanalyzed(bool shouldValidate(Action, HttpServletRequest)): Effects-of-calling:javax.servlet.http.HttpServletRequest:getParameter
    //#test_vector(bool shouldValidate(Action, HttpServletRequest)): java.lang.Class:getAnnotation(...)@97: Addr_Set{null}, Inverse{null}
    //#test_vector(bool shouldValidate(Action, HttpServletRequest)): value(...)@100: Addr_Set{null}, Addr_Set{&net/sourceforge/pebble/web/security/NullSecurityTokenValidatorCondition.__Class_Obj}, Inverse{null,&net/sourceforge/pebble/web/security/NullSecurityTokenValidatorCondition.__Class_Obj}
    if (annotation != null) {
      // Check for a condition
      Class<? extends SecurityTokenValidatorCondition> condition = annotation.value();
    //#securitytokenvalidator.java:100: Warning: method not available
    //#    -- call on Class value()
    //#    severity: INFORMATIONAL
    //#    class: net.sourceforge.pebble.web.security.SecurityTokenValidator
    //#    method: bool shouldValidate(Action, HttpServletRequest)
    //#    unanalyzed callee: Class value()
      if (condition != null && condition != NullSecurityTokenValidatorCondition.class) {
        // Instantiate condition
        try {
          return condition.newInstance().shouldValidate(request);
    //#securitytokenvalidator.java:104: Warning: method not available
    //#    -- call on bool shouldValidate(HttpServletRequest)
    //#    severity: INFORMATIONAL
    //#    class: net.sourceforge.pebble.web.security.SecurityTokenValidator
    //#    method: bool shouldValidate(Action, HttpServletRequest)
    //#    unanalyzed callee: bool shouldValidate(HttpServletRequest)
        } catch (IllegalAccessException iae) {
          throw new RuntimeException("Could not instantiate " + condition);
        } catch (InstantiationException ie) {
          throw new RuntimeException("Could not instantiate " + condition);
        }
      }
      // Otherwise, with no condition we should return validate
      return true;
    } else {
      // We have no annotation, don't validate
      return false;
    //#securitytokenvalidator.java:115: end of method: bool net.sourceforge.pebble.web.security.SecurityTokenValidator.shouldValidate(Action, HttpServletRequest)
    }
  }

  private String ensureSecurityTokenExists(HttpServletRequest request, HttpServletResponse response) {
    String token = (String) request.getAttribute(PEBBLE_SECURITY_TOKEN_PARAMETER);
    if (token != null) {
      // We've already configured it for this request
      return token;
    }
    String contextPath = request.getContextPath();
    Cookie[] cookies = request.getCookies();
    if (cookies != null) {
      for (Cookie cookie : cookies) {
        if (PEBBLE_SECURITY_TOKEN_PARAMETER.equals(cookie.getName())) {
          if (contextPath != null && contextPath.length() > 0) {
            if (contextPath.equals(cookie.getPath())) {
              token = cookie.getValue();
              break;
            }
          } else {
            token = cookie.getValue();
            break;
          }
        }
      }
    }
    // No cookie, generate a token at least 12 characters long
    if (token == null) {
      token = "";
      while (token.length() < 12) {
        token += Long.toHexString(random.nextLong());
      }
      // Set the cookie
      Cookie cookie = new Cookie(PEBBLE_SECURITY_TOKEN_PARAMETER, token);
      // Non persistent
      cookie.setMaxAge(-1);
      cookie.setPath(contextPath);
      response.addCookie(cookie);
    }
    // Set it as a request attribute so the security token tag can find it
    request.setAttribute(PEBBLE_SECURITY_TOKEN_PARAMETER, token);
    return token;
  }
  
}
    //#securitytokenvalidator.java:: end of class: net.sourceforge.pebble.web.security.SecurityTokenValidator
