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 }