diff --git a/config/src/test/groovy/org/springframework/security/config/doc/Attribute.groovy b/config/src/test/groovy/org/springframework/security/config/doc/Attribute.groovy
deleted file mode 100644
index a419d45bf7..0000000000
--- a/config/src/test/groovy/org/springframework/security/config/doc/Attribute.groovy
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2002-2011 the original author or authors.
- *
- * 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 org.springframework.security.config.doc
-
-/**
- * Represents a Spring Security XSD Attribute. It is created when parsing the current xsd to compare to the documented appendix.
- *
- * @author Rob Winch
- * @see SpringSecurityXsdParser
- * @see XsdDocumentedSpec
- */
-class Attribute {
- def name
- def desc
- def elmt
-
- def getId() {
- return "${elmt.id}-${name}".toString()
- }
-}
diff --git a/config/src/test/groovy/org/springframework/security/config/doc/Element.groovy b/config/src/test/groovy/org/springframework/security/config/doc/Element.groovy
deleted file mode 100644
index b7d877f809..0000000000
--- a/config/src/test/groovy/org/springframework/security/config/doc/Element.groovy
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright 2002-2011 the original author or authors.
- *
- * 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 org.springframework.security.config.doc
-
-/**
-* Represents a Spring Security XSD Element. It is created when parsing the current xsd to compare to the documented appendix.
-*
-* @author Rob Winch
-* @see SpringSecurityXsdParser
-* @see XsdDocumentedSpec
-*/
-class Element {
- def name
- def desc
- def attrs
- /**
- * Contains the elements that extend this element (i.e. any-user-service contains ldap-user-service)
- */
- def subGrps = []
- def childElmts = [:]
- def parentElmts = [:]
-
- def getId() {
- return "nsa-${name}".toString()
- }
-
- /**
- * Gets all the ids related to this Element including attributes, parent elements, and child elements.
- *
- *
- * The expected ids to be found are documented below.
- *
- * - Elements - any xml element will have the nsa-<element>. For example the http element will have the id
- * nsa-http
- * - Parent Section - Any element with a parent other than beans will have a section named
- * nsa-<element>-parents. For example, authentication-provider would have a section id of
- * nsa-authentication-provider-parents. The section would then contain a list of links pointing to the
- * documentation for each parent element.
- * - Attributes Section - Any element with attributes will have a section with the id
- * nsa-<element>-attributes. For example the http element would require a section with the id
- * http-attributes.
- * - Attribute - Each attribute of an element would have an id of nsa-<element>-<attributeName>. For
- * example the attribute create-session for the http attribute would have the id http-create-session.
- * - Child Section - Any element with a child element will have a section named nsa-<element>-children.
- * For example, authentication-provider would have a section id of nsa-authentication-provider-children. The
- * section would then contain a list of links pointing to the documentation for each child element.
- *
- * @return
- */
- def getIds() {
- def ids = [id]
- childElmts.values()*.ids.each { ids.addAll it }
- attrs*.id.each { ids.add it }
- if(childElmts) {
- ids.add id+'-children'
- }
- if(attrs) {
- ids.add id+'-attributes'
- }
- if(parentElmts) {
- ids.add id+'-parents'
- }
- ids
- }
-
- def getAllChildElmts() {
- def result = [:]
- childElmts.values()*.subGrps*.each { elmt -> result.put(elmt.name,elmt) }
- result + childElmts
- }
-
- def getAllParentElmts() {
- def result = [:]
- parentElmts.values()*.subGrps*.each { elmt -> result.put(elmt.name,elmt) }
- result + parentElmts
- }
-}
diff --git a/config/src/test/groovy/org/springframework/security/config/doc/SpringSecurityXsdParser.groovy b/config/src/test/groovy/org/springframework/security/config/doc/SpringSecurityXsdParser.groovy
deleted file mode 100644
index cb25182675..0000000000
--- a/config/src/test/groovy/org/springframework/security/config/doc/SpringSecurityXsdParser.groovy
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright 2002-2011 the original author or authors.
- *
- * 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 org.springframework.security.config.doc
-
-import groovy.xml.Namespace
-
-/**
- * Parses the Spring Security Xsd Document
- *
- * @author Rob Winch
- */
-class SpringSecurityXsdParser {
- private def rootElement
-
- private def xs = new Namespace("http://www.w3.org/2001/XMLSchema", 'xs')
- private def attrElmts = [] as Set
- private def elementNameToElement = [:] as Map
-
- /**
- * Returns a map of the element name to the {@link Element}.
- * @return
- */
- Map parse() {
- elements(rootElement)
- elementNameToElement
- }
-
- /**
- * Creates a Map of the name to an Element object of all the children of element.
- *
- * @param element
- * @return
- */
- private def elements(element) {
- def elementNameToElement = [:] as Map
- element.children().each { c->
- if(c.name() == 'element') {
- def e = elmt(c)
- elementNameToElement.put(e.name,e)
- } else {
- elementNameToElement.putAll(elements(c))
- }
- }
- elementNameToElement
- }
-
- /**
- * Any children that are attribute will be returned as an Attribute object.
- * @param element
- * @return a collection of Attribute objects that are children of element.
- */
- private def attrs(element) {
- def r = []
- element.children().each { c->
- if(c.name() == 'attribute') {
- r.add(attr(c))
- }else if(c.name() == 'element') {
- }else {
- r.addAll(attrs(c))
- }
- }
- r
- }
-
- /**
- * Any children will be searched for an attributeGroup, each of it's children will be returned as an Attribute
- * @param element
- * @return
- */
- private def attrgrps(element) {
- def r = []
- element.children().each { c->
- if(c.name() == 'element') {
- }else if (c.name() == 'attributeGroup') {
- if(c.attributes().get('name')) {
- r.addAll(attrgrp(c))
- } else {
- def n = c.attributes().get('ref').split(':')[1]
- def attrGrp = findNode(element,n)
- r.addAll(attrgrp(attrGrp))
- }
- } else {
- r.addAll(attrgrps(c))
- }
- }
- r
- }
-
- private def findNode(c,name) {
- def root = c
- while(root.name() != 'schema') {
- root = root.parent()
- }
- def result = root.breadthFirst().find { child-> name == child.@name?.text() }
- assert result?.@name?.text() == name
- result
- }
-
- /**
- * Processes an individual attributeGroup by obtaining all the attributes and then looking for more attributeGroup elements and prcessing them.
- * @param e
- * @return all the attributes for a specific attributeGroup and any child attributeGroups
- */
- private def attrgrp(e) {
- def attrs = attrs(e)
- attrs.addAll(attrgrps(e))
- attrs
- }
-
- /**
- * Obtains the description for a specific element
- * @param element
- * @return
- */
- private def desc(element) {
- return element['annotation']['documentation']
- }
-
- /**
- * Given an element creates an attribute from it.
- * @param n
- * @return
- */
- private def attr(n) {
- new Attribute(desc: desc(n), name: n.@name.text())
- }
-
- /**
- * Given an element creates an Element out of it by collecting all its attributes and child elements.
- *
- * @param n
- * @return
- */
- private def elmt(n) {
- def name = n.@ref.text()
- if(name) {
- name = name.split(':')[1]
- n = findNode(n,name)
- } else {
- name = n.@name.text()
- }
- if(elementNameToElement.containsKey(name)) {
- return elementNameToElement.get(name)
- }
- attrElmts.add(name)
- def e = new Element()
- e.name = n.@name.text()
- e.desc = desc(n)
- e.childElmts = elements(n)
- e.attrs = attrs(n)
- e.attrs.addAll(attrgrps(n))
- e.attrs*.elmt = e
- e.childElmts.values()*.each { it.parentElmts.put(e.name,e) }
-
- def subGrpName = n.@substitutionGroup.text()
- if(subGrpName) {
- def subGrp = elmt(findNode(n,subGrpName.split(":")[1]))
- subGrp.subGrps.add(e)
- }
-
- elementNameToElement.put(name,e)
- e
- }
-}
diff --git a/config/src/test/groovy/org/springframework/security/config/doc/XsdDocumentedTests.groovy b/config/src/test/groovy/org/springframework/security/config/doc/XsdDocumentedTests.groovy
deleted file mode 100644
index eea0757a1c..0000000000
--- a/config/src/test/groovy/org/springframework/security/config/doc/XsdDocumentedTests.groovy
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Copyright 2011-2016 the original author or authors.
- *
- * 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 org.springframework.security.config.doc
-
-import groovy.util.slurpersupport.GPathResult
-import spock.lang.*
-
-import org.springframework.security.config.http.SecurityFilters
-
-/**
- * Tests to ensure that the xsd is properly documented.
- *
- * @author Rob Winch
- */
-class XsdDocumentedTests extends Specification {
-
- def ignoredIds = [
- 'nsa-any-user-service',
- 'nsa-any-user-service-parents',
- 'nsa-authentication',
- 'nsa-websocket-security',
- 'nsa-ldap',
- 'nsa-method-security',
- 'nsa-web'
- ]
- @Shared def reference = new File('../docs/manual/src/docs/asciidoc/_includes/appendix/namespace.adoc')
-
- @Shared File schema31xDocument = new File('src/main/resources/org/springframework/security/config/spring-security-3.1.xsd')
- @Shared File schemaDocument = new File('src/main/resources/org/springframework/security/config/spring-security-5.0.xsd')
- @Shared Map elementNameToElement
- @Shared GPathResult schemaRootElement
-
- def setupSpec() {
- schemaRootElement = new XmlSlurper().parse(schemaDocument)
- elementNameToElement = new SpringSecurityXsdParser(rootElement: schemaRootElement).parse()
- }
-
- def cleanupSpec() {
- reference = null
- schema31xDocument = null
- schemaDocument = null
- elementNameToElement = null
- schemaRootElement = null
- }
-
- def 'SEC-2139: named-security-filter are all defined and ordered properly'() {
- setup:
- def expectedFilters = (EnumSet.allOf(SecurityFilters) as List).sort { it.order }
- when:
- def nsf = schemaRootElement.simpleType.find { it.@name == 'named-security-filter' }
- def nsfValues = nsf.children().children().collect { c ->
- Enum.valueOf(SecurityFilters, c.@value.toString())
- }
- then:
- expectedFilters == nsfValues
- }
-
- def 'SEC-2139: 3.1.x named-security-filter are all defined and ordered properly'() {
- setup:
- def expectedFilters = [
- "FIRST",
- "CHANNEL_FILTER",
- "SECURITY_CONTEXT_FILTER",
- "CONCURRENT_SESSION_FILTER",
- "LOGOUT_FILTER",
- "X509_FILTER",
- "PRE_AUTH_FILTER",
- "CAS_FILTER",
- "FORM_LOGIN_FILTER",
- "OPENID_FILTER",
- "LOGIN_PAGE_FILTER",
- "DIGEST_AUTH_FILTER",
- "BASIC_AUTH_FILTER",
- "REQUEST_CACHE_FILTER",
- "SERVLET_API_SUPPORT_FILTER",
- "JAAS_API_SUPPORT_FILTER",
- "REMEMBER_ME_FILTER",
- "ANONYMOUS_FILTER",
- "SESSION_MANAGEMENT_FILTER",
- "EXCEPTION_TRANSLATION_FILTER",
- "FILTER_SECURITY_INTERCEPTOR",
- "SWITCH_USER_FILTER",
- "LAST"
- ].collect {
- Enum.valueOf(SecurityFilters, it)
- }
- def schema31xRootElement = new XmlSlurper().parse(schema31xDocument)
- when:
- def nsf = schema31xRootElement.simpleType.find { it.@name == 'named-security-filter' }
- def nsfValues = nsf.children().children().collect { c ->
- Enum.valueOf(SecurityFilters, c.@value.toString())
- }
- then:
- expectedFilters == nsfValues
- }
-
- /**
- * This will check to ensure that the expected number of xsd documents are found to ensure that we are validating
- * against the current xsd document. If this test fails, all that is needed is to update the schemaDocument
- * and the expected size for this test.
- * @return
- */
- def 'the latest schema is being validated'() {
- when: 'all the schemas are found'
- def schemas = schemaDocument.getParentFile().list().findAll { it.endsWith('.xsd') }
- then: 'the count is equal to 12, if not then schemaDocument needs updated'
- schemas.size() == 12
- }
-
- /**
- * This uses a naming convention for the ids of the appendix to ensure that the entire appendix is documented.
- * The naming convention for the ids is documented in {@link Element#getIds()}.
- * @return
- */
- def 'the entire schema is included in the appendix documentation'() {
- setup: 'get all the documented ids and the expected ids'
- def documentedIds = []
- reference.eachLine { line ->
- if(line.matches("\\[\\[(nsa-.*)\\]\\]")) {
- documentedIds.add(line.substring(2,line.length() - 2))
- }
- }
- when: 'the schema is compared to the appendix documentation'
- def expectedIds = [] as Set
- elementNameToElement*.value*.ids*.each { expectedIds.addAll it }
- documentedIds.removeAll ignoredIds
- expectedIds.removeAll ignoredIds
- def undocumentedIds = (expectedIds - documentedIds)
- def shouldNotBeDocumented = (documentedIds - expectedIds)
- then: 'all the elements and attributes are documented'
- shouldNotBeDocumented.empty
- undocumentedIds.empty
- }
-
- /**
- * This test ensures that any element that has children or parents contains a section that has links pointing to that
- * documentation.
- * @return
- */
- def 'validate parents and children are linked in the appendix documentation'() {
- when: "get all the links for each element's children and parents"
- def docAttrNameToChildren = [:]
- def docAttrNameToParents = [:]
-
- def currentDocAttrNameToElmt
- def docAttrName
-
- reference.eachLine { line ->
- if(line.matches('^\\[\\[.*\\]\\]$')) {
- def id = line.substring(2,line.length() - 2)
- if(id.endsWith("-children")) {
- docAttrName = id.substring(0,id.length() - 9)
- currentDocAttrNameToElmt = docAttrNameToChildren
- } else if(id.endsWith("-parents")) {
- docAttrName = id.substring(0,id.length() - 8)
- currentDocAttrNameToElmt = docAttrNameToParents
- } else if(docAttrName && !id.startsWith(docAttrName)) {
- currentDocAttrNameToElmt = null
- docAttrName = null
- }
- }
-
- if(docAttrName) {
- def expression = '^\\* <<(nsa-.*),.*>>$'
- if(line.matches(expression)) {
- String elmtId = line.replaceAll(expression, '$1')
- currentDocAttrNameToElmt.get(docAttrName, []).add(elmtId)
- }
- }
- }
-
- def schemaAttrNameToParents = [:]
- def schemaAttrNameToChildren = [:]
- elementNameToElement.each { entry ->
- def key = 'nsa-'+entry.key
- if(ignoredIds.contains(key)) {
- return
- }
- def parentIds = entry.value.allParentElmts.values()*.id.findAll { !ignoredIds.contains(it) }.sort()
- if(parentIds) {
- schemaAttrNameToParents.put(key,parentIds)
- }
- def childIds = entry.value.allChildElmts.values()*.id.findAll { !ignoredIds.contains(it) }.sort()
- if(childIds) {
- schemaAttrNameToChildren.put(key,childIds)
- }
- }
- then: "the expected parents and children are all documented"
- schemaAttrNameToChildren.sort() == docAttrNameToChildren.sort()
- schemaAttrNameToParents.sort() == docAttrNameToParents.sort()
- }
-
- /**
- * This test checks each xsd element and ensures there is documentation for it.
- * @return
- */
- def 'entire xsd is documented'() {
- when: "validate that the entire xsd contains documentation"
- def notDocElmtIds = elementNameToElement.values().findAll {
- !it.desc.text() && !ignoredIds.contains(it.id)
- }*.id.sort().join("\n")
- def notDocAttrIds = elementNameToElement.values()*.attrs.flatten().findAll {
- !it.desc.text() && !ignoredIds.contains(it.id)
- }*.id.sort().join("\n")
- then: "all the elements and attributes have some documentation"
- !notDocElmtIds
- !notDocAttrIds
- }
-}
diff --git a/config/src/test/java/org/springframework/security/config/doc/Attribute.java b/config/src/test/java/org/springframework/security/config/doc/Attribute.java
new file mode 100644
index 0000000000..57b1b90deb
--- /dev/null
+++ b/config/src/test/java/org/springframework/security/config/doc/Attribute.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2002-2018 the original author or authors.
+ *
+ * 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 org.springframework.security.config.doc;
+
+/**
+ * Represents a Spring Security XSD Attribute. It is created when parsing the current xsd to compare to the documented appendix.
+ *
+ * @author Rob Winch
+ * @author Josh Cummings
+ *
+ * @see SpringSecurityXsdParser
+ * @see XsdDocumentedTests
+ */
+public class Attribute {
+ private String name;
+
+ private String desc;
+
+ private Element elmt;
+
+ public Attribute(String desc, String name) {
+ this.desc = desc;
+ this.name = name;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDesc() {
+ return this.desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+
+ public Element getElmt() {
+ return this.elmt;
+ }
+
+ public void setElmt(Element elmt) {
+ this.elmt = elmt;
+ }
+
+ public String getId() {
+ return String.format("%s-%s", this.elmt.getId(), this.name);
+ }
+}
diff --git a/config/src/test/java/org/springframework/security/config/doc/Element.java b/config/src/test/java/org/springframework/security/config/doc/Element.java
new file mode 100644
index 0000000000..fcb2fc2adf
--- /dev/null
+++ b/config/src/test/java/org/springframework/security/config/doc/Element.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2002-2018 the original author or authors.
+ *
+ * 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 org.springframework.security.config.doc;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Represents a Spring Security XSD Element. It is created when parsing
+ * the current xsd to compare to the documented appendix.
+ *
+ * @author Rob Winch
+ * @author Josh Cummings
+ *
+ * @see SpringSecurityXsdParser
+ * @see XsdDocumentedTests
+*/
+public class Element {
+ private String name;
+ private String desc;
+ private Collection attrs = new ArrayList<>();
+
+ /**
+ * Contains the elements that extend this element (i.e. any-user-service contains ldap-user-service)
+ */
+ private Collection subGrps = new ArrayList<>();
+ private Map childElmts = new HashMap<>();
+ private Map parentElmts = new HashMap<>();
+
+ public String getId() {
+ return String.format("nsa-%s", this.name);
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getDesc() {
+ return this.desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+
+ public Collection getAttrs() {
+ return this.attrs;
+ }
+
+ public void setAttrs(Collection attrs) {
+ this.attrs = attrs;
+ }
+
+ public Collection getSubGrps() {
+ return this.subGrps;
+ }
+
+ public void setSubGrps(Collection subGrps) {
+ this.subGrps = subGrps;
+ }
+
+ public Map getChildElmts() {
+ return this.childElmts;
+ }
+
+ public void setChildElmts(Map childElmts) {
+ this.childElmts = childElmts;
+ }
+
+ public Map getParentElmts() {
+ return this.parentElmts;
+ }
+
+ public void setParentElmts(Map parentElmts) {
+ this.parentElmts = parentElmts;
+ }
+
+ /**
+ * Gets all the ids related to this Element including attributes, parent elements, and child elements.
+ *
+ *
+ * The expected ids to be found are documented below.
+ *
+ * - Elements - any xml element will have the nsa-<element>. For example the http element will have the id
+ * nsa-http
+ * - Parent Section - Any element with a parent other than beans will have a section named
+ * nsa-<element>-parents. For example, authentication-provider would have a section id of
+ * nsa-authentication-provider-parents. The section would then contain a list of links pointing to the
+ * documentation for each parent element.
+ * - Attributes Section - Any element with attributes will have a section with the id
+ * nsa-<element>-attributes. For example the http element would require a section with the id
+ * http-attributes.
+ * - Attribute - Each attribute of an element would have an id of nsa-<element>-<attributeName>. For
+ * example the attribute create-session for the http attribute would have the id http-create-session.
+ * - Child Section - Any element with a child element will have a section named nsa-<element>-children.
+ * For example, authentication-provider would have a section id of nsa-authentication-provider-children. The
+ * section would then contain a list of links pointing to the documentation for each child element.
+ *
+ * @return
+ */
+ public Collection getIds() {
+ Collection ids = new ArrayList<>();
+ ids.add(getId());
+
+ this.childElmts.values()
+ .forEach(elmt -> ids.add(elmt.getId()));
+
+ this.attrs.forEach(attr -> ids.add(attr.getId()));
+
+ if ( !this.childElmts.isEmpty() ) {
+ ids.add(getId() + "-children");
+ }
+
+ if ( !this.attrs.isEmpty() ) {
+ ids.add(getId() + "-attributes");
+ }
+
+ if ( !this.parentElmts.isEmpty() ) {
+ ids.add(getId() + "-parents");
+ }
+
+ return ids;
+ }
+
+ public Map getAllChildElmts() {
+ Map result = new HashMap<>();
+
+ this.childElmts.values()
+ .forEach(elmt ->
+ elmt.subGrps.forEach(
+ subElmt -> result.put(subElmt.name, subElmt)));
+
+ result.putAll(this.childElmts);
+
+ return result;
+ }
+
+ public Map getAllParentElmts() {
+ Map result = new HashMap<>();
+
+ this.parentElmts.values()
+ .forEach(elmt ->
+ elmt.subGrps.forEach(
+ subElmt -> result.put(subElmt.name, subElmt)));
+
+ result.putAll(this.parentElmts);
+
+ return result;
+ }
+}
diff --git a/config/src/test/java/org/springframework/security/config/doc/NicerNode.java b/config/src/test/java/org/springframework/security/config/doc/NicerNode.java
new file mode 100644
index 0000000000..da6883e95d
--- /dev/null
+++ b/config/src/test/java/org/springframework/security/config/doc/NicerNode.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2002-2018 the original author or authors.
+ *
+ * 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 org.springframework.security.config.doc;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import java.util.Optional;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+/**
+ * @author Josh Cummings
+ */
+public class NicerNode {
+ private final Node node;
+
+ public NicerNode(Node node) {
+ this.node = node;
+ }
+
+ public String simpleName() {
+ String[] parts = this.node.getNodeName().split(":");
+ return parts[parts.length-1];
+ }
+
+ public String text() {
+ return this.node.getTextContent();
+ }
+
+ public Stream children() {
+ NodeList children = this.node.getChildNodes();
+
+ return IntStream.range(0, children.getLength())
+ .mapToObj(children::item)
+ .map(NicerNode::new);
+ }
+
+ public Optional child(String name) {
+ return this.children()
+ .filter(child -> name.equals(child.simpleName()))
+ .findFirst();
+ }
+
+ public Optional parent() {
+ return Optional.ofNullable(this.node.getParentNode())
+ .map(parent -> new NicerNode(parent));
+ }
+
+ public String attribute(String name) {
+ return Optional.ofNullable(this.node.getAttributes())
+ .map(attrs -> attrs.getNamedItem(name))
+ .map(attr -> attr.getTextContent())
+ .orElse(null);
+ }
+
+ public Node node() {
+ return this.node;
+ }
+}
diff --git a/config/src/test/java/org/springframework/security/config/doc/NicerXmlParser.java b/config/src/test/java/org/springframework/security/config/doc/NicerXmlParser.java
new file mode 100644
index 0000000000..eece67afc9
--- /dev/null
+++ b/config/src/test/java/org/springframework/security/config/doc/NicerXmlParser.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2002-2018 the original author or authors.
+ *
+ * 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 org.springframework.security.config.doc;
+
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * @author Josh Cummings
+ */
+public class NicerXmlParser implements AutoCloseable {
+ private InputStream xml;
+
+ public NicerXmlParser(InputStream xml) {
+ this.xml = xml;
+ }
+
+ public NicerNode parse() {
+ try {
+ DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
+
+ return new NicerNode(dBuilder.parse(this.xml));
+ } catch ( IOException | ParserConfigurationException | SAXException e ) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ this.xml.close();
+ }
+}
diff --git a/config/src/test/java/org/springframework/security/config/doc/NicerXmlSupport.java b/config/src/test/java/org/springframework/security/config/doc/NicerXmlSupport.java
new file mode 100644
index 0000000000..af05fe188c
--- /dev/null
+++ b/config/src/test/java/org/springframework/security/config/doc/NicerXmlSupport.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2002-2018 the original author or authors.
+ *
+ * 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 org.springframework.security.config.doc;
+
+import org.springframework.core.io.ClassPathResource;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * Support for ensuring preparing the givens in {@link XsdDocumentedTests}
+ *
+ * @author Josh Cummings
+ */
+public class NicerXmlSupport {
+ private NicerXmlParser parser;
+
+ public NicerNode parse(String location) throws IOException {
+ ClassPathResource resource = new ClassPathResource(location);
+ this.parser = new NicerXmlParser(resource.getInputStream());
+
+ return this.parser.parse();
+ }
+
+ public Map elementsByElementName(String location) throws IOException {
+ NicerNode node = parse(location);
+ return new SpringSecurityXsdParser(node).parse();
+ }
+
+ public void close() throws IOException {
+ if ( this.parser != null ) {
+ this.parser.close();
+ }
+ }
+}
diff --git a/config/src/test/java/org/springframework/security/config/doc/SpringSecurityXsdParser.java b/config/src/test/java/org/springframework/security/config/doc/SpringSecurityXsdParser.java
new file mode 100644
index 0000000000..0e3dd667de
--- /dev/null
+++ b/config/src/test/java/org/springframework/security/config/doc/SpringSecurityXsdParser.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2002-2018 the original author or authors.
+ *
+ * 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 org.springframework.security.config.doc;
+
+import org.springframework.util.StringUtils;
+
+import java.util.*;
+import java.util.stream.Stream;
+
+/**
+ * Parses the Spring Security Xsd Document
+ *
+ * @author Rob Winch
+ * @author Josh Cummings
+ */
+public class SpringSecurityXsdParser {
+ private NicerNode rootElement;
+
+ private Set attrElmts = new LinkedHashSet<>();
+ private Map elementNameToElement = new HashMap<>();
+
+ public SpringSecurityXsdParser(NicerNode rootElement) {
+ this.rootElement = rootElement;
+ }
+
+ /**
+ * Returns a map of the element name to the {@link Element}.
+ *
+ * @return
+ */
+ public Map parse() {
+ elements(this.rootElement);
+ return this.elementNameToElement;
+ }
+
+ /**
+ * Creates a Map of the name to an Element object of all the children of element.
+ *
+ * @param node
+ * @return
+ */
+ private Map elements(NicerNode node) {
+ Map elementNameToElement = new HashMap<>();
+
+ node.children().forEach(child -> {
+ if ("element".equals(child.simpleName())) {
+ Element e = elmt(child);
+ elementNameToElement.put(e.getName(), e);
+ } else {
+ elementNameToElement.putAll(elements(child));
+ }
+ });
+
+ return elementNameToElement;
+ }
+
+ /**
+ * Any children that are attribute will be returned as an Attribute object.
+ *
+ * @param element
+ * @return a collection of Attribute objects that are children of element.
+ */
+ private Collection attrs(NicerNode element) {
+ Collection attrs = new ArrayList<>();
+ element.children().forEach(c -> {
+ String name = c.simpleName();
+ if ("attribute".equals(name)) {
+ attrs.add(attr(c));
+ } else if ("element".equals(name)) {
+ } else {
+ attrs.addAll(attrs(c));
+ }
+ });
+
+ return attrs;
+ }
+
+ /**
+ * Any children will be searched for an attributeGroup, each of its children will be returned as an Attribute
+ *
+ * @param element
+ * @return
+ */
+ private Collection attrgrps(NicerNode element) {
+ Collection attrgrp = new ArrayList<>();
+
+ element.children().forEach(c -> {
+ if ("element".equals(c.simpleName())) {
+
+ } else if ("attributeGroup".equals(c.simpleName())) {
+ if (c.attribute("name") != null) {
+ attrgrp.addAll(attrgrp(c));
+ } else {
+ String name = c.attribute("ref").split(":")[1];
+ NicerNode attrGrp = findNode(element, name);
+ attrgrp.addAll(attrgrp(attrGrp));
+ }
+ } else {
+ attrgrp.addAll(attrgrps(c));
+ }
+ });
+
+ return attrgrp;
+ }
+
+ private NicerNode findNode(NicerNode c, String name) {
+ NicerNode root = c;
+ while (!"schema".equals(root.simpleName())) {
+ root = root.parent().get();
+ }
+
+ return expand(root)
+ .filter(node -> name.equals(node.attribute("name")))
+ .findFirst().orElseThrow(IllegalArgumentException::new);
+ }
+
+ private Stream expand(NicerNode root) {
+ return Stream.concat(
+ Stream.of(root),
+ root.children().flatMap(this::expand));
+ }
+
+ /**
+ * Processes an individual attributeGroup by obtaining all the attributes and then looking for more attributeGroup elements and prcessing them.
+ *
+ * @param e
+ * @return all the attributes for a specific attributeGroup and any child attributeGroups
+ */
+ private Collection attrgrp(NicerNode e) {
+ Collection attrs = attrs(e);
+ attrs.addAll(attrgrps(e));
+ return attrs;
+ }
+
+ /**
+ * Obtains the description for a specific element
+ *
+ * @param element
+ * @return
+ */
+ private String desc(NicerNode element) {
+ return element.child("annotation")
+ .flatMap(annotation -> annotation.child("documentation"))
+ .map(documentation -> documentation.text())
+ .orElse(null);
+ }
+
+ /**
+ * Given an element creates an attribute from it.
+ *
+ * @param n
+ * @return
+ */
+ private Attribute attr(NicerNode n) {
+ return new Attribute(desc(n), n.attribute("name"));
+ }
+
+ /**
+ * Given an element creates an Element out of it by collecting all its attributes and child elements.
+ *
+ * @param n
+ * @return
+ */
+ private Element elmt(NicerNode n) {
+ String name = n.attribute("ref");
+ if (StringUtils.isEmpty(name)) {
+ name = n.attribute("name");
+ } else {
+ name = name.split(":")[1];
+ n = findNode(n, name);
+ }
+
+ if (this.elementNameToElement.containsKey(name)) {
+ return this.elementNameToElement.get(name);
+ }
+ this.attrElmts.add(name);
+
+ Element e = new Element();
+ e.setName(n.attribute("name"));
+ e.setDesc(desc(n));
+ e.setChildElmts(elements(n));
+ e.setAttrs(attrs(n));
+ e.getAttrs().addAll(attrgrps(n));
+ e.getAttrs().forEach(attr -> attr.setElmt(e));
+ e.getChildElmts().values().forEach(element ->
+ element.getParentElmts().put(e.getName(), e));
+
+ String subGrpName = n.attribute("substitutionGroup");
+ if (!StringUtils.isEmpty(subGrpName)) {
+ Element subGrp = elmt(findNode(n, subGrpName.split(":")[1]));
+ subGrp.getSubGrps().add(e);
+ }
+
+ this.elementNameToElement.put(name, e);
+
+ return e;
+ }
+}
diff --git a/config/src/test/java/org/springframework/security/config/doc/XsdDocumentedTests.java b/config/src/test/java/org/springframework/security/config/doc/XsdDocumentedTests.java
new file mode 100644
index 0000000000..8f711c94f8
--- /dev/null
+++ b/config/src/test/java/org/springframework/security/config/doc/XsdDocumentedTests.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright 2002-2018 the original author or authors.
+ *
+ * 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 org.springframework.security.config.doc;
+
+import org.apache.commons.lang.StringUtils;
+import org.junit.After;
+import org.junit.Test;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.security.config.http.SecurityFiltersAssertions;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests to ensure that the xsd is properly documented.
+ *
+ * @author Rob Winch
+ * @author Josh Cummings
+ */
+public class XsdDocumentedTests {
+
+ Collection ignoredIds = Arrays.asList(
+ "nsa-any-user-service",
+ "nsa-any-user-service-parents",
+ "nsa-authentication",
+ "nsa-websocket-security",
+ "nsa-ldap",
+ "nsa-method-security",
+ "nsa-web");
+
+ String referenceLocation = "../docs/manual/src/docs/asciidoc/_includes/appendix/namespace.adoc";
+
+ String schema31xDocumentLocation = "org/springframework/security/config/spring-security-3.1.xsd";
+ String schemaDocumentLocation = "org/springframework/security/config/spring-security-5.0.xsd";
+
+ NicerXmlSupport xml = new NicerXmlSupport();
+
+ @After
+ public void close() throws IOException {
+ this.xml.close();
+ }
+
+ @Test
+ public void parseWhenLatestXsdThenAllNamedSecurityFiltersAreDefinedAndOrderedProperly()
+ throws IOException {
+ NicerNode root = this.xml.parse(this.schemaDocumentLocation);
+
+ List nodes =
+ root.child("schema")
+ .map(NicerNode::children)
+ .orElse(Stream.empty())
+ .filter(node ->
+ "simpleType".equals(node.simpleName()) &&
+ "named-security-filter".equals(node.attribute("name")))
+ .flatMap(NicerNode::children)
+ .flatMap(NicerNode::children)
+ .map(node -> node.attribute("value"))
+ .filter(StringUtils::isNotEmpty)
+ .collect(Collectors.toList());
+
+ SecurityFiltersAssertions.assertEquals(nodes);
+ }
+
+ @Test
+ public void parseWhen31XsdThenAllNamedSecurityFiltersAreDefinedAndOrderedProperly()
+ throws IOException {
+
+ List expected = Arrays.asList(
+ "FIRST",
+ "CHANNEL_FILTER",
+ "SECURITY_CONTEXT_FILTER",
+ "CONCURRENT_SESSION_FILTER",
+ "LOGOUT_FILTER",
+ "X509_FILTER",
+ "PRE_AUTH_FILTER",
+ "CAS_FILTER",
+ "FORM_LOGIN_FILTER",
+ "OPENID_FILTER",
+ "LOGIN_PAGE_FILTER",
+ "DIGEST_AUTH_FILTER",
+ "BASIC_AUTH_FILTER",
+ "REQUEST_CACHE_FILTER",
+ "SERVLET_API_SUPPORT_FILTER",
+ "JAAS_API_SUPPORT_FILTER",
+ "REMEMBER_ME_FILTER",
+ "ANONYMOUS_FILTER",
+ "SESSION_MANAGEMENT_FILTER",
+ "EXCEPTION_TRANSLATION_FILTER",
+ "FILTER_SECURITY_INTERCEPTOR",
+ "SWITCH_USER_FILTER",
+ "LAST"
+ );
+
+ NicerNode root = this.xml.parse(this.schema31xDocumentLocation);
+
+ List nodes =
+ root.child("schema")
+ .map(NicerNode::children)
+ .orElse(Stream.empty())
+ .filter(node ->
+ "simpleType".equals(node.simpleName()) &&
+ "named-security-filter".equals(node.attribute("name")))
+ .flatMap(NicerNode::children)
+ .flatMap(NicerNode::children)
+ .map(node -> node.attribute("value"))
+ .filter(StringUtils::isNotEmpty)
+ .collect(Collectors.toList());
+
+ assertThat(nodes).isEqualTo(expected);
+ }
+
+ /**
+ * This will check to ensure that the expected number of xsd documents are found to ensure that we are validating
+ * against the current xsd document. If this test fails, all that is needed is to update the schemaDocument
+ * and the expected size for this test.
+ * @return
+ */
+ @Test
+ public void sizeWhenReadingFilesystemThenIsCorrectNumberOfSchemaFiles()
+ throws IOException {
+
+ ClassPathResource resource = new ClassPathResource(this.schemaDocumentLocation);
+
+ String[] schemas = resource.getFile().getParentFile().list((dir, name) -> name.endsWith(".xsd"));
+
+ assertThat(schemas.length).isEqualTo(12)
+ .withFailMessage("the count is equal to 12, if not then schemaDocument needs updating");
+ }
+
+ /**
+ * This uses a naming convention for the ids of the appendix to ensure that the entire appendix is documented.
+ * The naming convention for the ids is documented in {@link Element#getIds()}.
+ * @return
+ */
+ @Test
+ public void countReferencesWhenReviewingDocumentationThenEntireSchemaIsIncluded()
+ throws IOException {
+
+ Map elementsByElementName =
+ this.xml.elementsByElementName(this.schemaDocumentLocation);
+
+ List documentIds =
+ Files.lines(Paths.get(this.referenceLocation))
+ .filter(line -> line.matches("\\[\\[(nsa-.*)\\]\\]"))
+ .map(line -> line.substring(2, line.length() - 2))
+ .collect(Collectors.toList());
+
+ Set expectedIds =
+ elementsByElementName.values().stream()
+ .flatMap(element -> element.getIds().stream())
+ .collect(Collectors.toSet());
+
+ documentIds.removeAll(this.ignoredIds);
+ expectedIds.removeAll(this.ignoredIds);
+
+ assertThat(documentIds).containsAll(expectedIds);
+ assertThat(expectedIds).containsAll(documentIds);
+ }
+
+ /**
+ * This test ensures that any element that has children or parents contains a section that has links pointing to that
+ * documentation.
+ * @return
+ */
+ @Test
+ public void countLinksWhenReviewingDocumentationThenParentsAndChildrenAreCorrectlyLinked()
+ throws IOException {
+
+ Map> docAttrNameToChildren = new HashMap<>();
+ Map> docAttrNameToParents = new HashMap<>();
+
+ String docAttrName = null;
+ Map> currentDocAttrNameToElmt = null;
+
+ List lines = Files.readAllLines(Paths.get(this.referenceLocation));
+ for ( String line : lines ) {
+ if(line.matches("^\\[\\[.*\\]\\]$")) {
+ String id = line.substring(2, line.length() - 2);
+
+ if(id.endsWith("-children")) {
+ docAttrName = id.substring(0, id.length() - 9);
+ currentDocAttrNameToElmt = docAttrNameToChildren;
+ } else if(id.endsWith("-parents")) {
+ docAttrName = id.substring(0, id.length() - 8);
+ currentDocAttrNameToElmt = docAttrNameToParents;
+ } else if(docAttrName != null && !id.startsWith(docAttrName)) {
+ currentDocAttrNameToElmt = null;
+ docAttrName = null;
+ }
+ }
+
+ if(docAttrName != null && currentDocAttrNameToElmt != null) {
+ String expression = "^\\* <<(nsa-.*),.*>>$";
+ if(line.matches(expression)) {
+ String elmtId = line.replaceAll(expression, "$1");
+ currentDocAttrNameToElmt
+ .computeIfAbsent(docAttrName, key -> new ArrayList<>())
+ .add(elmtId);
+ }
+ }
+ }
+
+ Map elementNameToElement = this.xml.elementsByElementName(this.schemaDocumentLocation);
+
+ Map> schemaAttrNameToChildren = new HashMap<>();
+ Map> schemaAttrNameToParents = new HashMap<>();
+
+ elementNameToElement.entrySet().stream()
+ .forEach(entry -> {
+ String key = "nsa-" + entry.getKey();
+ if (this.ignoredIds.contains(key) ) {
+ return;
+ }
+
+ List parentIds =
+ entry.getValue().getAllParentElmts().values().stream()
+ .filter(element -> !this.ignoredIds.contains(element.getId()))
+ .map(element -> element.getId())
+ .sorted()
+ .collect(Collectors.toList());
+ if ( !parentIds.isEmpty() ) {
+ schemaAttrNameToParents.put(key, parentIds);
+ }
+
+ List childIds =
+ entry.getValue().getAllChildElmts().values().stream()
+ .filter(element -> !this.ignoredIds.contains(element.getId()))
+ .map(element -> element.getId())
+ .sorted()
+ .collect(Collectors.toList());
+ if ( !childIds.isEmpty() ) {
+ schemaAttrNameToChildren.put(key, childIds);
+ }
+ });
+
+ assertThat(docAttrNameToChildren).isEqualTo(schemaAttrNameToChildren);
+ assertThat(docAttrNameToParents).isEqualTo(schemaAttrNameToParents);
+ }
+
+
+ /**
+ * This test checks each xsd element and ensures there is documentation for it.
+ * @return
+ */
+ @Test
+ public void countWhenReviewingDocumentationThenAllElementsDocumented()
+ throws IOException {
+
+ Map elementNameToElement =
+ this.xml.elementsByElementName(this.schemaDocumentLocation);
+
+ String notDocElmtIds =
+ elementNameToElement.values().stream()
+ .filter(element ->
+ StringUtils.isEmpty(element.getDesc()) &&
+ !this.ignoredIds.contains(element.getId()))
+ .map(element -> element.getId())
+ .sorted()
+ .collect(Collectors.joining("\n"));
+
+ String notDocAttrIds =
+ elementNameToElement.values().stream()
+ .flatMap(element -> element.getAttrs().stream())
+ .filter(element ->
+ StringUtils.isEmpty(element.getDesc()) &&
+ !this.ignoredIds.contains(element.getId()))
+ .map(element -> element.getId())
+ .sorted()
+ .collect(Collectors.joining("\n"));
+
+ assertThat(notDocElmtIds).isEmpty();
+ assertThat(notDocAttrIds).isEmpty();
+ }
+}
diff --git a/config/src/test/java/org/springframework/security/config/http/SecurityFiltersAssertions.java b/config/src/test/java/org/springframework/security/config/http/SecurityFiltersAssertions.java
new file mode 100644
index 0000000000..1d0effd36a
--- /dev/null
+++ b/config/src/test/java/org/springframework/security/config/http/SecurityFiltersAssertions.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2002-2018 the original author or authors.
+ *
+ * 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 org.springframework.security.config.http;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Assertions for tests that rely on confirming behavior of the package-private SecurityFilters enum
+ *
+ * @author Josh Cummings
+ */
+public class SecurityFiltersAssertions {
+ private static Collection ordered = Arrays.asList(SecurityFilters.values());
+
+ public static void assertEquals(List filters) {
+ List expected = ordered.stream()
+ .map(SecurityFilters::name)
+ .collect(Collectors.toList());
+
+ assertThat(filters).isEqualTo(expected);
+ }
+}