| /* |
| * Copyright 2011 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. You may obtain a copy of |
| * the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package com.google.gwt.user.server.rpc; |
| |
| import com.google.gwt.user.client.rpc.RpcToken; |
| import com.google.gwt.user.client.rpc.RpcTokenException; |
| import com.google.gwt.user.client.rpc.XsrfToken; |
| import com.google.gwt.user.server.Util; |
| import com.google.gwt.util.tools.Utility; |
| |
| import java.lang.reflect.Method; |
| |
| import javax.servlet.ServletException; |
| import javax.servlet.http.Cookie; |
| |
| /** |
| * EXPERIMENTAL and subject to change. Do not use this in production code. |
| * <p> |
| * The servlet base class for RPC service implementations using default XSRF |
| * protection tied to authentication session cookie. |
| * </p> |
| * |
| * <p> |
| * XSRF token validation is performed by generating MD5 hash of the session |
| * cookie and comparing supplied {@link XsrfToken} with the generated hash. |
| * Session cookie name is specified by the {@value |
| * com.google.gwt.user.server.rpc.XsrfTokenServiceServlet#COOKIE_NAME_PARAM} |
| * context parameter in {@code web.xml}. |
| * </p> |
| * |
| * <p> |
| * {@link com.google.gwt.user.client.rpc.XsrfTokenService} can be used by |
| * clients to obtain {@link XsrfToken}s that will pass validation performed by |
| * this class. |
| * </p> |
| * |
| * @see XsrfTokenServiceServlet |
| * @see AbstractXsrfProtectedServiceServlet |
| */ |
| public class XsrfProtectedServiceServlet |
| extends AbstractXsrfProtectedServiceServlet { |
| |
| // @VisibleForTesting |
| String sessionCookieName = null; |
| |
| public XsrfProtectedServiceServlet() { |
| this(null); |
| } |
| |
| public XsrfProtectedServiceServlet(String sessionCookieName) { |
| this.sessionCookieName = sessionCookieName; |
| } |
| |
| public XsrfProtectedServiceServlet(Object delegate) { |
| this(delegate, null); |
| } |
| |
| public XsrfProtectedServiceServlet(Object delegate, |
| String sessionCookieName) { |
| super(delegate); |
| this.sessionCookieName = sessionCookieName; |
| } |
| |
| @Override |
| public void init() throws ServletException { |
| super.init(); |
| // do not overwrite if value is supplied in constructor |
| if (sessionCookieName == null) { |
| // servlet configuration precedes context configuration |
| sessionCookieName = getServletConfig().getInitParameter( |
| XsrfTokenServiceServlet.COOKIE_NAME_PARAM); |
| if (sessionCookieName == null) { |
| sessionCookieName = getServletContext().getInitParameter( |
| XsrfTokenServiceServlet.COOKIE_NAME_PARAM); |
| } |
| if (sessionCookieName == null) { |
| throw new IllegalStateException( |
| XsrfTokenServiceServlet.COOKIE_NAME_NOT_SET_ERROR_MSG); |
| } |
| } |
| } |
| |
| /** |
| * Validates {@link XsrfToken} included with {@link RPCRequest} against XSRF |
| * cookie. |
| */ |
| @Override |
| protected void validateXsrfToken(RpcToken token, Method method) |
| throws RpcTokenException { |
| if (token == null) { |
| throw new RpcTokenException("XSRF token missing"); |
| } |
| Cookie sessionCookie = Util.getCookie(getThreadLocalRequest(), |
| sessionCookieName, false); |
| if (sessionCookie == null || sessionCookie.getValue() == null || |
| sessionCookie.getValue().length() == 0) { |
| throw new RpcTokenException("Session cookie is missing or empty! " + |
| "Unable to verify XSRF cookie"); |
| } |
| |
| String expectedToken = Utility.toHexString( |
| Utility.getMd5Digest(sessionCookie.getValue().getBytes())); |
| XsrfToken xsrfToken = (XsrfToken) token; |
| |
| if (!expectedToken.equals(xsrfToken.getToken())) { |
| throw new RpcTokenException("Invalid XSRF token"); |
| } |
| } |
| } |