001/** 002 * Copyright 2005-2016 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.krad.util; 017 018import org.apache.commons.lang.StringUtils; 019import org.apache.log4j.Logger; 020 021import javax.servlet.http.HttpServletRequest; 022import javax.servlet.http.HttpServletResponse; 023import javax.ws.rs.HttpMethod; 024import java.util.UUID; 025 026/** 027 * Simple utility class that will validate the given request to determine if it has any required CSRF information, 028 * setting appropriate response errors if not. 029 * 030 * @author Eric Westfall 031 */ 032public class CsrfValidator { 033 034 private static final Logger LOG = Logger.getLogger(CsrfValidator.class); 035 036 public static final String CSRF_PARAMETER = "csrfToken"; 037 public static final String CSRF_SESSION_TOKEN = "csrfSessionToken"; 038 039 /** 040 * Applies CSRF protection for any HTTP method other than GET, HEAD, or OPTIONS. 041 * 042 * @param request the http request to check 043 * @param response the http response associated with the given request 044 * 045 * @return true if the request validated successfully, false otherwise. If false is returned, calling code should 046 * act immediately to terminate any additional work performed on the response. 047 */ 048 public static boolean validateCsrf(HttpServletRequest request, HttpServletResponse response) { 049 if (HttpMethod.GET.equals(request.getMethod()) || 050 HttpMethod.HEAD.equals(request.getMethod()) || 051 HttpMethod.OPTIONS.equals(request.getMethod())) { 052 // if it's a GET and there's not already a CSRF token, then we need to generate and place a CSRF token 053 placeSessionToken(request); 054 } else { 055 String givenCsrf = getRequestToken(request); 056 String actualCsrf = getSessionToken(request); 057 if (actualCsrf == null) { 058 LOG.error("CSRF check failed because no CSRF token has been established on the session"); 059 response.setStatus(HttpServletResponse.SC_FORBIDDEN); 060 return false; 061 } else if (!StringUtils.equals(givenCsrf, actualCsrf)) { 062 LOG.error("CSRF check failed, actual value was: " + actualCsrf + ", given value was: " + givenCsrf + ", requested URL was: " + request.getRequestURL()); 063 response.setStatus(HttpServletResponse.SC_FORBIDDEN); 064 return false; 065 } 066 } 067 return true; 068 } 069 070 071 /** 072 * Retrieve the CSRF token that is associated with the session for the given request, or null if the session has none. 073 * 074 * @param request the request to check the session for the CSRF token 075 * @return the CSRF token on the request's session, or null if the session has none 076 */ 077 public static String getSessionToken(HttpServletRequest request) { 078 return (String)request.getSession().getAttribute(CSRF_SESSION_TOKEN); 079 } 080 081 /** 082 * Retrieve the CSRF token parameter that is on the given request, or null if the request has none. 083 * 084 * @param request the request to check for the CSRF token parameter 085 * @return the CSRF token parameter on the request, or null if the request has none 086 */ 087 public static String getRequestToken(HttpServletRequest request) { 088 return request.getParameter(CSRF_PARAMETER); 089 } 090 091 /** 092 * If the session associated with the given request has no CSRF token, this method will generate that token and 093 * add it as an attribute on the session. If the session already has a CSRF token, this method will do nothing. 094 * 095 * @param request the request with the session on which to place the session token if needed 096 */ 097 public static void placeSessionToken(HttpServletRequest request) { 098 if (getSessionToken(request) == null) { 099 request.getSession().setAttribute(CSRF_SESSION_TOKEN, UUID.randomUUID().toString()); 100 } 101 } 102 103}