├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── pom.xml
└── src
├── main
└── java
│ └── com
│ └── allanditzel
│ └── springframework
│ └── security
│ └── web
│ └── csrf
│ └── CsrfTokenResponseHeaderBindingFilter.java
└── test
└── java
└── com
└── allanditzel
└── springframework
└── security
└── web
└── csrf
└── CsrfTokenResponseHeaderBindingFilterTest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled source #
2 | ###################
3 | *.com
4 | *.class
5 | *.dll
6 | *.exe
7 | *.o
8 | *.so
9 |
10 | # Packages #
11 | ############
12 | # it's better to unpack these files and commit the raw source
13 | # git has its own built in compression methods
14 | *.7z
15 | *.dmg
16 | *.gz
17 | *.iso
18 | *.jar
19 | *.rar
20 | *.tar
21 | *.zip
22 |
23 | # Logs and databases #
24 | ######################
25 | *.log
26 |
27 | # OS generated files #
28 | ######################
29 | .DS_Store
30 | .DS_Store?
31 | ._*
32 | .Spotlight-V100
33 | .Trashes
34 | ehthumbs.db
35 | Thumbs.db
36 |
37 | # IDE Files #
38 | #############
39 | *.iml
40 | .idea/
41 |
42 | # Maven Files #
43 | ###############
44 | target/
45 | target-grunt/
46 | src/main/webapp/static/node_modules/
47 |
48 | # Git Files #
49 | #############
50 | *.orig
51 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | jdk:
3 | - oraclejdk8
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2014 Allan Ditzel
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
15 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://travis-ci.org/aditzel/spring-security-csrf-filter)
2 | #Spring Security CSRF Token Filter
3 |
4 | The idea behind this filter is to be able to use Spring Security to build a Single Page Application with whatever
5 | front end technology you would like such as Ember, Angular, Backbone, etc.
6 |
7 | By default, Spring Security assumes that you are going to be rendering all your pages on the server, so you are
8 | expected to use their expression language to print out the CSRF tokens to make it available to your UI layer. This
9 | filter is meant to allow you to automatically expose the CSRF token data from Spring on all HTTP response headers.
10 |
11 | #Installation:
12 |
13 | This can be installed via Maven:
14 |
15 | ````
16 |
17 | com.allanditzel
18 | spring-security-csrf-token-filter
19 | 1.1
20 |
21 | ````
22 |
23 | #Usage:
24 |
25 | If you are using JavaConfig you just have to add it to a configure block for HttpSecurity:
26 |
27 | ```Java
28 | protected void configure(HttpSecurity http) throws Exception {
29 | CsrfTokenResponseHeaderBindingFilter csrfTokenFilter = new CsrfTokenResponseHeaderBindingFilter();
30 | http.addFilterAfter(csrfTokenFilter, CsrfFilter.class);
31 | }
32 | ```
33 |
34 | #Credits:
35 | Credit goes to the authors of the great discussion on stackoverflow.com:
36 |
37 | http://stackoverflow.com/questions/20862299/with-spring-security-3-2-0-release-how-can-i-get-the-csrf-token-in-a-page-that
38 |
39 | #License:
40 | Apache 2.0
41 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 | 4.0.0
19 |
20 | com.allanditzel
21 | spring-security-csrf-token-filter
22 | 1.2-SNAPSHOT
23 | jar
24 |
25 | Spring Security CSRF Token Filter
26 | https://github.com/aditzel/spring-security-csrf-filter
27 | A Spring Security Filter that binds the existing CSRF token values to response headers.
28 |
29 |
30 |
31 | aditzel
32 | Allan Ditzel
33 | allan@allanditzel.com
34 | https://github.com/aditzel
35 |
36 |
37 |
38 |
39 |
40 | The Apache Software License, Version 2.0
41 | http://www.apache.org/licenses/LICENSE-2.0.txt
42 | repo
43 |
44 |
45 |
46 |
47 | https://github.com/aditzel/spring-security-csrf-filter/issues
48 | GitHub Issues
49 |
50 |
51 |
52 | https://github.com/aditzel/spring-security-csrf-filter
53 | scm:git:git://github.com/aditzel/spring-security-csrf-filter.git
54 | scm:git:git@github.com:aditzel/spring-security-csrf-filter.git
55 | HEAD
56 |
57 |
58 |
59 |
60 | ossrh
61 | https://oss.sonatype.org/content/repositories/snapshots/
62 |
63 |
64 |
65 |
66 | UTF-8
67 | 4.11
68 | 1.9.5
69 | 3.2.0.RELEASE
70 | 3.1.0
71 | 1.7.7
72 | 2.1.1
73 | 2.9.1
74 | 1.5
75 | 1.6
76 | 2.5
77 |
78 |
79 |
80 |
81 |
82 | javax.servlet
83 | javax.servlet-api
84 | ${servlet.version}
85 | provided
86 |
87 |
88 | junit
89 | junit
90 | ${junit.version}
91 | test
92 |
93 |
94 | org.mockito
95 | mockito-all
96 | ${mockito.version}
97 | test
98 |
99 |
100 | org.springframework.security
101 | spring-security-web
102 | ${spring.security.version}
103 | provided
104 |
105 |
106 | org.springframework.security
107 | spring-security-config
108 | ${spring.security.version}
109 | provided
110 |
111 |
112 | org.slf4j
113 | slf4j-api
114 | ${slf4j.version}
115 | test
116 |
117 |
118 | org.slf4j
119 | slf4j-simple
120 | ${slf4j.version}
121 | test
122 |
123 |
124 | org.slf4j
125 | jcl-over-slf4j
126 | ${slf4j.version}
127 | test
128 |
129 |
130 |
131 |
132 |
133 |
134 | javax.servlet
135 | javax.servlet-api
136 |
137 |
138 | junit
139 | junit
140 |
141 |
142 | org.mockito
143 | mockito-all
144 |
145 |
146 | org.springframework.security
147 | spring-security-web
148 |
149 |
150 | org.springframework.security
151 | spring-security-config
152 |
153 |
154 | org.slf4j
155 | slf4j-api
156 |
157 |
158 | org.slf4j
159 | slf4j-simple
160 |
161 |
162 | org.slf4j
163 | jcl-over-slf4j
164 |
165 |
166 |
167 |
168 |
169 |
170 | org.apache.maven.plugins
171 | maven-source-plugin
172 | ${maven-source-plugin.version}
173 |
174 |
175 | attach-sources
176 |
177 | jar-no-fork
178 |
179 |
180 |
181 |
182 |
183 | org.apache.maven.plugins
184 | maven-javadoc-plugin
185 | ${maven-javadoc-plugin.version}
186 |
187 |
188 | attach-javadocs
189 |
190 | jar
191 |
192 |
193 |
194 |
195 |
196 | org.sonatype.plugins
197 | nexus-staging-maven-plugin
198 | ${nexus-staging-maven-plugin.version}
199 | true
200 |
201 | ossrh
202 | https://oss.sonatype.org/
203 |
204 |
205 |
206 | org.apache.maven.plugins
207 | maven-release-plugin
208 | ${maven-release-plugin.version}
209 |
210 | true
211 | false
212 | release-sign-artifacts
213 | deploy
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 | release-sign-artifacts
222 |
223 |
224 | performRelease
225 | true
226 |
227 |
228 |
229 |
230 |
231 | org.apache.maven.plugins
232 | maven-gpg-plugin
233 | ${maven-gpg-plugin.version}
234 |
235 |
236 | sign-artifacts
237 | verify
238 |
239 | sign
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
--------------------------------------------------------------------------------
/src/main/java/com/allanditzel/springframework/security/web/csrf/CsrfTokenResponseHeaderBindingFilter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Allan Ditzel
3 | *
4 | * Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
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 |
17 | package com.allanditzel.springframework.security.web.csrf;
18 |
19 | import org.springframework.security.web.csrf.CsrfToken;
20 | import org.springframework.web.filter.OncePerRequestFilter;
21 |
22 | import javax.servlet.ServletException;
23 | import javax.servlet.http.HttpServletRequest;
24 | import javax.servlet.http.HttpServletResponse;
25 | import java.io.IOException;
26 |
27 | /**
28 | * Binds a {@link org.springframework.security.web.csrf.CsrfToken} to the {@link HttpServletResponse}
29 | * headers if the Spring {@link org.springframework.security.web.csrf.CsrfFilter} has placed one in the {@link HttpServletRequest}.
30 | *
31 | * Based on the work found in: Stack Overflow
32 | *
33 | * @author Allan Ditzel
34 | * @since 1.0
35 | */
36 | public class CsrfTokenResponseHeaderBindingFilter extends OncePerRequestFilter {
37 | protected static final String REQUEST_ATTRIBUTE_NAME = "_csrf";
38 | protected static final String RESPONSE_HEADER_NAME = "X-CSRF-HEADER";
39 | protected static final String RESPONSE_PARAM_NAME = "X-CSRF-PARAM";
40 | protected static final String RESPONSE_TOKEN_NAME = "X-CSRF-TOKEN";
41 |
42 | @Override
43 | protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, javax.servlet.FilterChain filterChain) throws ServletException, IOException {
44 | CsrfToken token = (CsrfToken) request.getAttribute(REQUEST_ATTRIBUTE_NAME);
45 |
46 | if (token != null) {
47 | response.setHeader(RESPONSE_HEADER_NAME, token.getHeaderName());
48 | response.setHeader(RESPONSE_PARAM_NAME, token.getParameterName());
49 | response.setHeader(RESPONSE_TOKEN_NAME , token.getToken());
50 | }
51 |
52 | filterChain.doFilter(request, response);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/test/java/com/allanditzel/springframework/security/web/csrf/CsrfTokenResponseHeaderBindingFilterTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2014 Allan Ditzel
3 | *
4 | * Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
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 |
17 | package com.allanditzel.springframework.security.web.csrf;
18 |
19 | import org.junit.Before;
20 | import org.junit.Test;
21 | import org.junit.runner.RunWith;
22 | import org.mockito.Mock;
23 | import org.mockito.runners.MockitoJUnitRunner;
24 | import org.springframework.security.web.csrf.CsrfToken;
25 |
26 | import javax.servlet.FilterChain;
27 | import javax.servlet.ServletException;
28 | import javax.servlet.http.HttpServletRequest;
29 | import javax.servlet.http.HttpServletResponse;
30 | import javax.servlet.http.HttpSession;
31 |
32 | import java.io.IOException;
33 |
34 | import static org.mockito.Mockito.verify;
35 | import static org.mockito.Mockito.verifyNoMoreInteractions;
36 | import static org.mockito.Mockito.when;
37 |
38 | /**
39 | * Test for {@link CsrfTokenResponseHeaderBindingFilter}.
40 | *
41 | * @author Allan Ditzel
42 | * @since 1.0
43 | */
44 | @RunWith(MockitoJUnitRunner.class)
45 | public class CsrfTokenResponseHeaderBindingFilterTest {
46 | private CsrfTokenResponseHeaderBindingFilter filter;
47 |
48 | @Mock
49 | HttpServletRequest request;
50 |
51 | @Mock
52 | HttpServletResponse response;
53 |
54 | @Mock
55 | FilterChain filterChain;
56 |
57 | @Mock
58 | HttpSession session;
59 |
60 | @Mock
61 | CsrfToken token;
62 |
63 | @Before
64 | public void setUp() {
65 | filter = new CsrfTokenResponseHeaderBindingFilter();
66 | }
67 |
68 | @Test
69 | public void shouldContinueProcessingFilterChainIfTokenNotPresentInRequest() throws ServletException, IOException {
70 | when(request.getAttribute(CsrfTokenResponseHeaderBindingFilter.REQUEST_ATTRIBUTE_NAME)).thenReturn(null);
71 |
72 | filter.doFilterInternal(request, response, filterChain);
73 |
74 | verify(request).getAttribute(CsrfTokenResponseHeaderBindingFilter.REQUEST_ATTRIBUTE_NAME);
75 | verify(filterChain).doFilter(request, response);
76 | verifyNoMoreInteractions(request, response, filterChain);
77 | }
78 |
79 | @Test
80 | public void shouldBindCsrfValuesToResponseHeadersWhenTokenIsPresentInRequest() throws ServletException, IOException {
81 | String headerName = "headerName";
82 | String paramName = "paramName";
83 | String tokenValue = "token";
84 |
85 | when(request.getAttribute(CsrfTokenResponseHeaderBindingFilter.REQUEST_ATTRIBUTE_NAME)).thenReturn(token);
86 | when(token.getHeaderName()).thenReturn(headerName);
87 | when(token.getParameterName()).thenReturn(paramName);
88 | when(token.getToken()).thenReturn(tokenValue);
89 |
90 | filter.doFilterInternal(request, response, filterChain);
91 |
92 | verify(request).getAttribute(CsrfTokenResponseHeaderBindingFilter.REQUEST_ATTRIBUTE_NAME);
93 | verify(token).getHeaderName();
94 | verify(token).getParameterName();
95 | verify(token).getToken();
96 | verify(response).setHeader(CsrfTokenResponseHeaderBindingFilter.RESPONSE_HEADER_NAME, headerName);
97 | verify(response).setHeader(CsrfTokenResponseHeaderBindingFilter.RESPONSE_PARAM_NAME, paramName);
98 | verify(response).setHeader(CsrfTokenResponseHeaderBindingFilter.RESPONSE_TOKEN_NAME, tokenValue);
99 | verify(filterChain).doFilter(request, response);
100 | verifyNoMoreInteractions(token, request, response, filterChain);
101 | }
102 | }
--------------------------------------------------------------------------------