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 }