View Javadoc
1   /**
2    * Copyright 2005-2016 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.util;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.apache.log4j.Logger;
20  
21  import javax.servlet.http.HttpServletRequest;
22  import javax.servlet.http.HttpServletResponse;
23  import javax.ws.rs.HttpMethod;
24  import java.util.UUID;
25  
26  /**
27   * Simple utility class that will validate the given request to determine if it has any required CSRF information,
28   * setting appropriate response errors if not.
29   *
30   * @author Eric Westfall
31   */
32  public class CsrfValidator {
33  
34      private static final Logger LOG = Logger.getLogger(CsrfValidator.class);
35  
36      public static final String CSRF_PARAMETER = "csrfToken";
37      public static final String CSRF_SESSION_TOKEN = "csrfSessionToken";
38  
39      /**
40       * Applies CSRF protection for any HTTP method other than GET, HEAD, or OPTIONS.
41       *
42       * @param request the http request to check
43       * @param response the http response associated with the given request
44       *
45       * @return true if the request validated successfully, false otherwise. If false is returned, calling code should
46       * act immediately to terminate any additional work performed on the response.
47       */
48      public static boolean validateCsrf(HttpServletRequest request, HttpServletResponse response) {
49          if (HttpMethod.GET.equals(request.getMethod()) ||
50                  HttpMethod.HEAD.equals(request.getMethod()) ||
51                  HttpMethod.OPTIONS.equals(request.getMethod())) {
52              // if it's a GET and there's not already a CSRF token, then we need to generate and place a CSRF token
53              placeSessionToken(request);
54          } else {
55              String givenCsrf = getRequestToken(request);
56              String actualCsrf = getSessionToken(request);
57              if (actualCsrf == null) {
58                  LOG.error("CSRF check failed because no CSRF token has been established on the session");
59                  response.setStatus(HttpServletResponse.SC_FORBIDDEN);
60                  return false;
61              } else if (!StringUtils.equals(givenCsrf, actualCsrf)) {
62                  LOG.error("CSRF check failed, actual value was: " + actualCsrf + ", given value was: " + givenCsrf + ", requested URL was: " + request.getRequestURL());
63                  response.setStatus(HttpServletResponse.SC_FORBIDDEN);
64                  return false;
65              }
66          }
67          return true;
68      }
69  
70  
71      /**
72       * Retrieve the CSRF token that is associated with the session for the given request, or null if the session has none.
73       *
74       * @param request the request to check the session for the CSRF token
75       * @return the CSRF token on the request's session, or null if the session has none
76       */
77      public static String getSessionToken(HttpServletRequest request) {
78          return (String)request.getSession().getAttribute(CSRF_SESSION_TOKEN);
79      }
80  
81      /**
82       * Retrieve the CSRF token parameter that is on the given request, or null if the request has none.
83       *
84       * @param request the request to check for the CSRF token parameter
85       * @return the CSRF token parameter on the request, or null if the request has none
86       */
87      public static String getRequestToken(HttpServletRequest request) {
88          return request.getParameter(CSRF_PARAMETER);
89      }
90  
91      /**
92       * If the session associated with the given request has no CSRF token, this method will generate that token and
93       * add it as an attribute on the session. If the session already has a CSRF token, this method will do nothing.
94       *
95       * @param request the request with the session on which to place the session token if needed
96       */
97      private static void placeSessionToken(HttpServletRequest request) {
98          if (getSessionToken(request) == null) {
99              request.getSession().setAttribute(CSRF_SESSION_TOKEN, UUID.randomUUID().toString());
100         }
101     }
102 
103 }