From 85e508bbb6d296b0a428b6b61e4630ced77fb2eb Mon Sep 17 00:00:00 2001 From: Bill Smith Date: Fri, 27 Apr 2018 16:30:29 +0000 Subject: [PATCH] Merged in SHIBUI-456 (pull request #63) SHIBUI-456 * [SHIBUI-456] Fix tomcat configuration for `/entities` endpoint update documentation * [SHIBUI-456] Fix tomcat configuration for `/entities` endpoint * [SHIBUI-456] Copied tests from EntityControllerTests and modified to work with WebTestClient (and a live Tomcat). --- README.md | 11 ++ .../ui/configuration/TomcatConfiguration.java | 13 ++ .../EntitiesControllerIntegrationTests.groovy | 135 +++++++++++++++--- 3 files changed, 143 insertions(+), 16 deletions(-) create mode 100644 backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/TomcatConfiguration.java diff --git a/README.md b/README.md index 4033766c8..a7f5b9994 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,17 @@ allowed with: -Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true ``` +In Apache HTTPD, you'll need something like: + +``` + + AllowEncodedSlashes NoDecode + ServerName shibui.unicon.net + ProxyPass / http://localhost:8080/ nocanon + ProxyPassReverse / http://localhost:8080/ + +``` + ### Running as an executable `java -jar shibui.war` diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/TomcatConfiguration.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/TomcatConfiguration.java new file mode 100644 index 000000000..e3c2d019c --- /dev/null +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/TomcatConfiguration.java @@ -0,0 +1,13 @@ +package edu.internet2.tier.shibboleth.admin.ui.configuration; + +import org.springframework.boot.web.server.WebServerFactoryCustomizer; +import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; +import org.springframework.stereotype.Component; + +@Component +public class TomcatConfiguration implements WebServerFactoryCustomizer { + @Override + public void customize(ConfigurableServletWebServerFactory factory) { + System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true"); + } +} diff --git a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntitiesControllerIntegrationTests.groovy b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntitiesControllerIntegrationTests.groovy index 62a15c646..2ed405784 100644 --- a/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntitiesControllerIntegrationTests.groovy +++ b/backend/src/test/groovy/edu/internet2/tier/shibboleth/admin/ui/controller/EntitiesControllerIntegrationTests.groovy @@ -1,22 +1,41 @@ package edu.internet2.tier.shibboleth.admin.ui.controller +import edu.internet2.tier.shibboleth.admin.ui.opensaml.OpenSamlObjects +import net.shibboleth.ext.spring.resource.ResourceHelper +import org.joda.time.DateTime +import org.opensaml.saml.metadata.resolver.ChainingMetadataResolver +import org.opensaml.saml.metadata.resolver.MetadataResolver +import org.opensaml.saml.metadata.resolver.filter.MetadataFilterChain +import org.opensaml.saml.metadata.resolver.impl.ResourceBackedMetadataResolver import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest +import org.springframework.boot.test.context.TestConfiguration +import org.springframework.context.annotation.Bean +import org.springframework.core.io.ClassPathResource import org.springframework.test.context.ActiveProfiles import org.springframework.test.web.reactive.server.WebTestClient +import org.springframework.web.util.DefaultUriBuilderFactory +import org.xmlunit.builder.DiffBuilder +import org.xmlunit.builder.Input +import org.xmlunit.diff.DefaultNodeMatcher +import org.xmlunit.diff.ElementSelectors import spock.lang.Specification /** * @author Bill Smith (wsmith@unicon.net) */ -// TODO: implement -// @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -// @ActiveProfiles("no-auth") +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ActiveProfiles("no-auth") class EntitiesControllerIntegrationTests extends Specification { @Autowired private WebTestClient webClient + def setup() { + // yeah, don't ask... this is just shenanigans + this.webClient.webClient.uriBuilderFactory.encodingMode = DefaultUriBuilderFactory.EncodingMode.NONE + } + def "GET /api/entities returns the proper json"() { given: def expectedBody = ''' @@ -55,24 +74,108 @@ class EntitiesControllerIntegrationTests extends Specification { ''' when: - def x = 1 - // TODO: implement - /* def result = this.webClient .get() .uri("/api/entities/http%3A%2F%2Ftest.scaldingspoon.org%2Ftest1") - .exchange() - */ + .exchange() // someday, I'd like to know why IntelliJ "cannot resolve symbol 'exchange'" then: - assert 1 - // TODO: implement - /* result.expectStatus().isOk() - .expectBody().consumeWith( - { response -> new String(response.getResponseBody()) == expectedBody } - ) - //.expectedBody() // some other json comparison - */ + .expectBody() + .json(expectedBody) + } + + def "GET /api/entities/test is not found"() { + when: + def result = this.webClient + .get() + .uri("/api/entities/test") + .exchange() + + then: + result.expectStatus().isNotFound() + } + + def "GET /api/entities/test XML is not found"() { + when: + def result = this.webClient + .get() + .uri("/api/entities/test") + .header('Accept', 'application/xml') + .exchange() + + then: + result.expectStatus().isNotFound() + } + + def "GET /api/entities/http%3A%2F%2Ftest.scaldingspoon.org%2Ftest1 XML returns proper XML"() { + given: + def expectedBody = ''' + + + + + internal + + + givenName + employeeNumber + + + + + urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified + + + +''' + when: + def result = this.webClient + .get() + .uri("/api/entities/http%3A%2F%2Ftest.scaldingspoon.org%2Ftest1") + .header('Accept', 'application/xml') + .exchange() + + then: + def resultBody = result.expectStatus().isOk() + //.expectHeader().contentType("application/xml;charset=ISO-8859-1") // should this really be ISO-8859-1? + // expectedBody encoding is UTF-8... + .expectHeader().contentType("application/xml;charset=UTF-8") + .expectBody(String.class) + .returnResult() + def diff = DiffBuilder.compare(Input.fromString(expectedBody)).withTest(Input.fromString(resultBody.getResponseBody())).ignoreComments().checkForSimilar().ignoreWhitespace().withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText)).build() + !diff.hasDifferences() + } + + @TestConfiguration + static class Config { + @Autowired + OpenSamlObjects openSamlObjects + + @Bean + MetadataResolver metadataResolver() { + def resource = ResourceHelper.of(new ClassPathResource("/metadata/aggregate.xml")) + def aggregate = new ResourceBackedMetadataResolver(resource){ + @Override + DateTime getLastRefresh() { + return null + } + } + + aggregate.with { + it.metadataFilter = new MetadataFilterChain() + it.id = 'testme' + it.parserPool = openSamlObjects.parserPool + it.initialize() + it + } + + return new ChainingMetadataResolver().with { + it.id = 'chain' + it.resolvers = [aggregate] + it.initialize() + it + } + } } }