Sfoglia il codice sorgente

Polish HPKP

* Javadoc polish
* Whitespace cleanup

Issue gh-3706
Rob Winch 9 anni fa
parent
commit
db81977a1a

+ 0 - 1
config/src/main/java/org/springframework/security/config/SecurityNamespaceHandler.java

@@ -166,7 +166,6 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
 		loadParsers();
 	}
 
-	@SuppressWarnings("deprecation")
 	private void loadParsers() {
 		// Parsers
 		parsers.put(Elements.LDAP_PROVIDER, new LdapProviderBeanDefinitionParser());

+ 5 - 5
config/src/main/java/org/springframework/security/config/http/HeadersBeanDefinitionParser.java

@@ -218,11 +218,11 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
 						hash = "sha256";
 					}
 
-                    Node pinValueNode = pinElement.getFirstChild();
-                    if (pinValueNode == null) {
-                        context.getReaderContext().warning("Missing value for pin entry.", hpkpElement);
-                        continue;
-                    }
+					Node pinValueNode = pinElement.getFirstChild();
+					if (pinValueNode == null) {
+						context.getReaderContext().warning("Missing value for pin entry.", hpkpElement);
+						continue;
+					}
 
 					String fingerprint = pinElement.getFirstChild().getTextContent();
 

+ 14 - 14
config/src/test/groovy/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerTests.groovy

@@ -35,12 +35,12 @@ class HeadersConfigurerTests extends BaseSpringSpec {
 			springSecurityFilterChain.doFilter(request,response,chain)
 		then:
 			responseHeaders == ['X-Content-Type-Options':'nosniff',
-						 'X-Frame-Options':'DENY',
-						 'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains',
-						 'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
-						 'Expires' : '0',
-						 'Pragma':'no-cache',
-						 'X-XSS-Protection' : '1; mode=block']
+						'X-Frame-Options':'DENY',
+						'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains',
+						'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
+						'Expires' : '0',
+						'Pragma':'no-cache',
+						'X-XSS-Protection' : '1; mode=block']
 	}
 
 	@EnableWebSecurity
@@ -123,8 +123,8 @@ class HeadersConfigurerTests extends BaseSpringSpec {
 			springSecurityFilterChain.doFilter(request,response,chain)
 		then:
 			responseHeaders == ['Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
-						 'Expires' : '0',
-						 'Pragma':'no-cache']
+						'Expires' : '0',
+						'Pragma':'no-cache']
 	}
 
 	@EnableWebSecurity
@@ -168,12 +168,12 @@ class HeadersConfigurerTests extends BaseSpringSpec {
 			springSecurityFilterChain.doFilter(request,response,chain)
 		then:
 			responseHeaders == ['X-Content-Type-Options':'nosniff',
-						 'X-Frame-Options':'SAMEORIGIN',
-						 'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains',
-						 'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
-						 'Expires' : '0',
-						 'Pragma':'no-cache',
-						 'X-XSS-Protection' : '1; mode=block']
+						'X-Frame-Options':'SAMEORIGIN',
+						'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains',
+						'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
+						'Expires' : '0',
+						'Pragma':'no-cache',
+						'X-XSS-Protection' : '1; mode=block']
 	}
 
 	@EnableWebSecurity

+ 171 - 171
config/src/test/groovy/org/springframework/security/config/http/HttpHeadersConfigTests.groovy

@@ -30,12 +30,12 @@ import org.springframework.security.web.util.matcher.AnyRequestMatcher
  */
 class HttpHeadersConfigTests extends AbstractHttpConfigTests {
 	def defaultHeaders = ['X-Content-Type-Options':'nosniff',
-								 'X-Frame-Options':'DENY',
-								 'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains',
-								 'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
-								 'Expires' : '0',
-								 'Pragma':'no-cache',
-								 'X-XSS-Protection' : '1; mode=block']
+								'X-Frame-Options':'DENY',
+								'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains',
+								'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
+								'Expires' : '0',
+								'Pragma':'no-cache',
+								'X-XSS-Protection' : '1; mode=block']
 	def 'headers disabled'() {
 		setup:
 			httpAutoConfig {
@@ -294,7 +294,7 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
 			MockHttpServletResponse response = new MockHttpServletResponse()
 			hf.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
 		then:
-			 assertHeaders(response, ['abc':'def'])
+			assertHeaders(response, ['abc':'def'])
 	}
 
 	def 'http headers header no name produces error'() {
@@ -404,8 +404,8 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
 			springSecurityFilterChain.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
 		then:
 			assertHeaders(response, ['Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
-									 'Expires' : '0',
-									 'Pragma':'no-cache'])
+									'Expires' : '0',
+									'Pragma':'no-cache'])
 	}
 
 	def 'http headers hsts'() {
@@ -458,35 +458,35 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
 			assertHeaders(response, ['Strict-Transport-Security': 'max-age=1'])
 	}
 
-    def 'http headers hpkp no pins'() {
-        setup:
-            httpAutoConfig {
-                'headers'('defaults-disabled':true) {
-                    'hpkp'()
-                }
-            }
-        when:
-            createAppContext()
-        then:
-            XmlBeanDefinitionStoreException expected = thrown()
-            expected.message.contains 'The content of element \'hpkp\' is not complete'
-    }
-
-    def 'http headers hpkp no pin'() {
-        setup:
-            httpAutoConfig {
-                'headers'('defaults-disabled':true) {
-                    'hpkp'() {
-                        'pins'()
-                    }
-                }
-            }
-        when:
-            createAppContext()
-        then:
-            XmlBeanDefinitionStoreException expected = thrown()
-            expected.message.contains 'The content of element \'pins\' is not complete'
-    }
+		def 'http headers hpkp no pins'() {
+				setup:
+						httpAutoConfig {
+								'headers'('defaults-disabled':true) {
+										'hpkp'()
+								}
+						}
+				when:
+						createAppContext()
+				then:
+						XmlBeanDefinitionStoreException expected = thrown()
+						expected.message.contains 'The content of element \'hpkp\' is not complete'
+		}
+
+		def 'http headers hpkp no pin'() {
+				setup:
+						httpAutoConfig {
+								'headers'('defaults-disabled':true) {
+										'hpkp'() {
+												'pins'()
+										}
+								}
+						}
+				when:
+						createAppContext()
+				then:
+						XmlBeanDefinitionStoreException expected = thrown()
+						expected.message.contains 'The content of element \'pins\' is not complete'
+		}
 
 	def 'http headers hpkp'() {
 		setup:
@@ -508,125 +508,125 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
 			assertHeaders(response, ['Public-Key-Pins-Report-Only': 'max-age=5184000 ; pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="'])
 	}
 
-    def 'http headers hpkp with default algorithm'() {
-        setup:
-            httpAutoConfig {
-                'headers'('defaults-disabled':true) {
-                    'hpkp'() {
-                        'pins'() {
-                            'pin'('d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=')
-                        }
-                    }
-                }
-            }
-            createAppContext()
-            def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
-            MockHttpServletResponse response = new MockHttpServletResponse()
-        when:
-            springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure:true), response, new MockFilterChain())
-        then:
-            assertHeaders(response, ['Public-Key-Pins-Report-Only': 'max-age=5184000 ; pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="'])
-    }
+		def 'http headers hpkp with default algorithm'() {
+				setup:
+						httpAutoConfig {
+								'headers'('defaults-disabled':true) {
+										'hpkp'() {
+												'pins'() {
+														'pin'('d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=')
+												}
+										}
+								}
+						}
+						createAppContext()
+						def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
+						MockHttpServletResponse response = new MockHttpServletResponse()
+				when:
+						springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure:true), response, new MockFilterChain())
+				then:
+						assertHeaders(response, ['Public-Key-Pins-Report-Only': 'max-age=5184000 ; pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="'])
+		}
 
 	def 'http headers hpkp only invokes on HttpServletRequest.isSecure = true'() {
 		setup:
-            httpAutoConfig {
-                'headers'('defaults-disabled':true) {
-                    'hpkp'() {
-                        'pins'() {
-                            'pin'('algorithm':'sha256', 'E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=')
-                        }
-                    }
-                }
-            }
-            createAppContext()
-            def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
-            MockHttpServletResponse response = new MockHttpServletResponse()
-		when:
-		    springSecurityFilterChain.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
-		then:
-		    response.headerNames.empty
-	}
-
-    def 'http headers hpkp with custom max age'() {
-        setup:
-            httpAutoConfig {
-                'headers'('defaults-disabled':true) {
-                    'hpkp'('max-age-seconds':'604800') {
-                        'pins'() {
-                            'pin'('algorithm':'sha256', 'd6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=')
-                        }
-                    }
-                }
-            }
-            createAppContext()
-            def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
-            MockHttpServletResponse response = new MockHttpServletResponse()
-        when:
-            springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure:true), response, new MockFilterChain())
-        then:
-            assertHeaders(response, ['Public-Key-Pins-Report-Only': 'max-age=604800 ; pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="'])
-    }
-
-    def 'http headers hpkp@reportOnly=false'() {
-        setup:
-            httpAutoConfig {
-                'headers'('defaults-disabled':true) {
-                    'hpkp'('report-only':'false') {
-                        'pins'() {
-                            'pin'('algorithm':'sha256', 'E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=')
-                        }
-                    }
-                }
-            }
-            createAppContext()
-            def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
-            MockHttpServletResponse response = new MockHttpServletResponse()
-        when:
-            springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure: true), response, new MockFilterChain())
-        then:
-            assertHeaders(response, ['Public-Key-Pins': 'max-age=5184000 ; pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g="'])
-    }
-
-    def 'http headers hpkp@includeSubDomains=true'() {
-        setup:
-            httpAutoConfig {
-                'headers'('defaults-disabled':true) {
-                    'hpkp'('include-subdomains':'true') {
-                        'pins'() {
-                            'pin'('algorithm':'sha256', 'E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=')
-                        }
-                    }
-                }
-            }
-            createAppContext()
-            def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
-            MockHttpServletResponse response = new MockHttpServletResponse()
-        when:
-            springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure: true), response, new MockFilterChain())
-        then:
-            assertHeaders(response, ['Public-Key-Pins-Report-Only': 'max-age=5184000 ; pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" ; includeSubDomains'])
-    }
-
-    def 'http headers hpkp with report-uri'() {
-        setup:
-            httpAutoConfig {
-                'headers'('defaults-disabled':true) {
-                    'hpkp'('report-uri':'http://example.net/pkp-report') {
-                        'pins'() {
-                            'pin'('algorithm':'sha256', 'E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=')
-                        }
-                    }
-                }
-            }
-            createAppContext()
-            def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
-            MockHttpServletResponse response = new MockHttpServletResponse()
-        when:
-            springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure: true), response, new MockFilterChain())
-        then:
-            assertHeaders(response, ['Public-Key-Pins-Report-Only': 'max-age=5184000 ; pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" ; report-uri="http://example.net/pkp-report"'])
-    }
+						httpAutoConfig {
+								'headers'('defaults-disabled':true) {
+										'hpkp'() {
+												'pins'() {
+														'pin'('algorithm':'sha256', 'E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=')
+												}
+										}
+								}
+						}
+						createAppContext()
+						def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
+						MockHttpServletResponse response = new MockHttpServletResponse()
+		when:
+				springSecurityFilterChain.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
+		then:
+				response.headerNames.empty
+	}
+
+		def 'http headers hpkp with custom max age'() {
+				setup:
+						httpAutoConfig {
+								'headers'('defaults-disabled':true) {
+										'hpkp'('max-age-seconds':'604800') {
+												'pins'() {
+														'pin'('algorithm':'sha256', 'd6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=')
+												}
+										}
+								}
+						}
+						createAppContext()
+						def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
+						MockHttpServletResponse response = new MockHttpServletResponse()
+				when:
+						springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure:true), response, new MockFilterChain())
+				then:
+						assertHeaders(response, ['Public-Key-Pins-Report-Only': 'max-age=604800 ; pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="'])
+		}
+
+		def 'http headers hpkp@reportOnly=false'() {
+				setup:
+						httpAutoConfig {
+								'headers'('defaults-disabled':true) {
+										'hpkp'('report-only':'false') {
+												'pins'() {
+														'pin'('algorithm':'sha256', 'E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=')
+												}
+										}
+								}
+						}
+						createAppContext()
+						def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
+						MockHttpServletResponse response = new MockHttpServletResponse()
+				when:
+						springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure: true), response, new MockFilterChain())
+				then:
+						assertHeaders(response, ['Public-Key-Pins': 'max-age=5184000 ; pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g="'])
+		}
+
+		def 'http headers hpkp@includeSubDomains=true'() {
+				setup:
+						httpAutoConfig {
+								'headers'('defaults-disabled':true) {
+										'hpkp'('include-subdomains':'true') {
+												'pins'() {
+														'pin'('algorithm':'sha256', 'E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=')
+												}
+										}
+								}
+						}
+						createAppContext()
+						def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
+						MockHttpServletResponse response = new MockHttpServletResponse()
+				when:
+						springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure: true), response, new MockFilterChain())
+				then:
+						assertHeaders(response, ['Public-Key-Pins-Report-Only': 'max-age=5184000 ; pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" ; includeSubDomains'])
+		}
+
+		def 'http headers hpkp with report-uri'() {
+				setup:
+						httpAutoConfig {
+								'headers'('defaults-disabled':true) {
+										'hpkp'('report-uri':'http://example.net/pkp-report') {
+												'pins'() {
+														'pin'('algorithm':'sha256', 'E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=')
+												}
+										}
+								}
+						}
+						createAppContext()
+						def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
+						MockHttpServletResponse response = new MockHttpServletResponse()
+				when:
+						springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure: true), response, new MockFilterChain())
+				then:
+						assertHeaders(response, ['Public-Key-Pins-Report-Only': 'max-age=5184000 ; pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=" ; report-uri="http://example.net/pkp-report"'])
+		}
 
 	// --- disable single default header ---
 
@@ -688,23 +688,23 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
 
 	def 'http headers hpkp@disabled=true'() {
 		setup:
-            httpAutoConfig {
-                'headers'() {
-                    'hpkp'(disabled:true) {
-                        'pins'() {
-                            'pin'('algorithm':'sha256', 'E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=')
-                        }
-                    }
-                }
-            }
-            createAppContext()
-            def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
-            MockHttpServletResponse response = new MockHttpServletResponse()
-            def expectedHeaders = [:] << defaultHeaders
-		when:
-		    springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure:true), response, new MockFilterChain())
-		then:
-		    assertHeaders(response, expectedHeaders)
+						httpAutoConfig {
+								'headers'() {
+										'hpkp'(disabled:true) {
+												'pins'() {
+														'pin'('algorithm':'sha256', 'E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=')
+												}
+										}
+								}
+						}
+						createAppContext()
+						def springSecurityFilterChain = appContext.getBean(FilterChainProxy)
+						MockHttpServletResponse response = new MockHttpServletResponse()
+						def expectedHeaders = [:] << defaultHeaders
+		when:
+				springSecurityFilterChain.doFilter(new MockHttpServletRequest(secure:true), response, new MockFilterChain())
+		then:
+				assertHeaders(response, expectedHeaders)
 	}
 
 	def 'http headers frame-options@disabled=true'() {

+ 12 - 12
docs/manual/src/docs/asciidoc/index.adoc

@@ -3844,8 +3844,8 @@ Opposed to the other headers, Spring Security does not add HPKP by default. You
 			include-subdomains="true"
 			report-uri="http://example.net/pkp-report">
 			<pins>
-			    <pin algorithm="sha256">d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=</pin>
-			    <pin algorithm="sha256">E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=</pin>
+					<pin algorithm="sha256">d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=</pin>
+					<pin algorithm="sha256">E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=</pin>
 			</pins>
 		</hpkp>
 	</headers>
@@ -3860,16 +3860,16 @@ Similarly, you can enable HPKP headers with Java Configuration:
 public class WebSecurityConfig extends
 WebSecurityConfigurerAdapter {
 
-    @Override
-    protected void configure(HttpSecurity http) throws Exception {
-        http
-        // ...
-        .headers()
-            .httpPublicKeyPinning()
-                .includeSubdomains(true)
-                .reportUri("http://example.net/pkp-report")
-                .addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=", "E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=";
-    }
+		@Override
+		protected void configure(HttpSecurity http) throws Exception {
+				http
+				// ...
+				.headers()
+						.httpPublicKeyPinning()
+								.includeSubdomains(true)
+								.reportUri("http://example.net/pkp-report")
+								.addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=", "E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=";
+		}
 }
 ----
 

+ 4 - 2
web/src/main/java/org/springframework/security/web/header/writers/HpkpHeaderWriter.java

@@ -162,7 +162,7 @@ public final class HpkpHeaderWriter implements HeaderWriter {
 
 	/*
 	 * (non-Javadoc)
-	 * 
+	 *
 	 * @see org.springframework.security.web.headers.HeaderWriter#writeHeaders(javax
 	 * .servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
 	 */
@@ -199,9 +199,11 @@ public final class HpkpHeaderWriter implements HeaderWriter {
 	 *
 	 * Use
 	 *
-	 * Map<String, String> pins = new HashMap<String, String>();
+	 * <code>
+	 * Map&lt;String, String&gt; pins = new HashMap&lt;String, String&gt;();
 	 * pins.put("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=", "sha256");
 	 * pins.put("E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=", "sha256");
+	 * </code>
 	 * </p>
 	 *
 	 * @param pins the map of base64-encoded SPKI fingerprint &amp; cryptographic hash algorithm pairs.