This project has retired. For details please refer to its Attic page.
CsrfManager xref
View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.chemistry.opencmis.server.shared;
20  
21  import java.security.SecureRandom;
22  
23  import javax.servlet.ServletConfig;
24  import javax.servlet.ServletException;
25  import javax.servlet.http.HttpServletRequest;
26  import javax.servlet.http.HttpServletResponse;
27  import javax.servlet.http.HttpSession;
28  
29  import org.apache.chemistry.opencmis.commons.exceptions.CmisPermissionDeniedException;
30  
31  public class CsrfManager {
32  
33      public static final String CSRF_ATTR = "org.apache.chemistry.opencmis.csrftoken";
34  
35      private static final String CSRF_HEADER = "csrfHeader";
36      private static final String CSRF_PARAMETER = "csrfParameter";
37      private static final String FETCH_VALUE = "fetch";
38  
39      private static char[][] hexArrays = new char[][] { "0123456789ABCDEF".toCharArray(), //
40              "0123456789abcdef".toCharArray(), //
41              "ABCDEFGHIJKLMNOP".toCharArray(), //
42              "abcdefghijklmnop".toCharArray() };
43  
44      private String csrfHeader;
45      private String csrfParameter;
46  
47      private SecureRandom random = new SecureRandom();
48  
49      public CsrfManager(String csrfHeader, String csrfParameter) {
50          if (csrfHeader != null) {
51              this.csrfHeader = csrfHeader.trim();
52              if (this.csrfHeader.length() == 0) {
53                  throw new IllegalArgumentException("Invalid CSRF header!");
54              }
55              if (csrfParameter != null) {
56                  this.csrfParameter = csrfParameter.trim();
57                  if (this.csrfParameter.length() == 0) {
58                      throw new IllegalArgumentException("Invalid CSRF parameter!");
59                  }
60              }
61          }
62      }
63  
64      public CsrfManager(ServletConfig config) throws ServletException {
65          csrfHeader = config.getInitParameter(CSRF_HEADER);
66          if (csrfHeader != null) {
67              this.csrfHeader = csrfHeader.trim();
68              if (this.csrfHeader.length() == 0) {
69                  throw new ServletException("Invalid CSRF header!");
70              }
71  
72              // get parameter
73              csrfParameter = config.getInitParameter(CSRF_PARAMETER);
74              if (csrfParameter != null) {
75                  this.csrfParameter = csrfParameter.trim();
76                  if (this.csrfParameter.length() == 0) {
77                      throw new ServletException("Invalid CSRF parameter!");
78                  }
79              }
80          }
81      }
82  
83      public void check(HttpServletRequest req, HttpServletResponse resp, boolean isRepositoryInfoRequest,
84              boolean isContentRequest) {
85          if (csrfHeader == null) {
86              // no CSRF protection
87              return;
88          }
89  
90          HttpSession httpSession = req.getSession(true);
91          String token = (String) httpSession.getAttribute(CSRF_ATTR);
92          String headerValue = req.getHeader(csrfHeader);
93  
94          // check parameter if the header is not set and this is a content
95          // request
96          if (headerValue == null || headerValue.isEmpty()) {
97              if (isContentRequest && csrfParameter != null) {
98                  String paramValue = req.getParameter(csrfParameter);
99                  if (paramValue != null && paramValue.equals(token)) {
100                     return;
101                 }
102             }
103 
104             throw new CmisPermissionDeniedException("Invalid CSRF token!");
105         }
106 
107         // check if a new token is requested
108         if (isRepositoryInfoRequest && FETCH_VALUE.equals(headerValue) && token == null) {
109             token = generateNewToken();
110             httpSession.setAttribute(CSRF_ATTR, token);
111             resp.addHeader(csrfHeader, token);
112             return;
113         }
114 
115         // check if there is a token
116         if (token == null) {
117             throw new CmisPermissionDeniedException("Invalid CSRF token!");
118         }
119 
120         // finally, check the token
121         if (!token.equals(headerValue)) {
122             throw new CmisPermissionDeniedException("Invalid CSRF token!");
123         }
124     }
125 
126     private String generateNewToken() {
127         byte[] tokenBytes = new byte[16];
128         random.nextBytes(tokenBytes);
129 
130         int ary = random.nextInt(hexArrays.length);
131 
132         char[] token = new char[tokenBytes.length * 2];
133         for (int i = 0; i < tokenBytes.length; i++) {
134             int v = tokenBytes[i] & 0xFF;
135             token[i * 2] = hexArrays[ary][v >>> 4];
136             token[i * 2 + 1] = hexArrays[ary][v & 0x0F];
137         }
138 
139         return new String(token);
140     }
141 }