diff --git a/backend/Dockerfile b/backend/Dockerfile index cec9c4c44..2bce3ec96 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -3,7 +3,8 @@ FROM gcr.io/distroless/java ARG JAR_FILE COPY ${JAR_FILE} app.jar +COPY loader.properties loader.properties EXPOSE 8080 -CMD ["app.jar"] \ No newline at end of file +ENTRYPOINT ["/usr/bin/java", "-jar", "app.jar"] \ No newline at end of file diff --git a/backend/build.gradle b/backend/build.gradle index 167bd3994..be652ccd5 100644 --- a/backend/build.gradle +++ b/backend/build.gradle @@ -34,16 +34,36 @@ processResources.dependsOn(':ui:npm_run_buildProd') bootWar.dependsOn(':ui:npm_run_buildProd') bootWar.baseName = 'shibui' bootWar { - manifest { - attributes("Manifest-Version" : "1.0", "Implementation-Version" : "${project.version}") - } - from(tasks.findByPath(':ui:npm_run_buildProd').outputs) { + manifest { + attributes( + "Manifest-Version" : "1.0", + "Implementation-Version" : "${project.version}" + ) + } + from(tasks.findByPath(':ui:npm_run_buildProd').outputs) { // into '/' into '/public' } archiveName = "${baseName}.war" } +bootJar.dependsOn ':ui:npm_run_buildProd' +bootJar.baseName = 'shibui' +bootJar { + manifest { + attributes( + "Manifest-Version" : "1.0", + "Implementation-Version" : "${project.version}", + 'Main-Class': 'org.springframework.boot.loader.PropertiesLauncher' + ) + } + from(tasks.findByPath(':ui:npm_run_buildProd').outputs) { + // into '/' + into '/public' + } + archiveName = "${baseName}.jar" +} + springBoot { mainClassName = 'edu.internet2.tier.shibboleth.admin.ui.ShibbolethUiApplication' buildInfo() @@ -209,12 +229,13 @@ jacocoTestReport { } } -tasks.docker.dependsOn tasks.build +tasks.docker.dependsOn tasks.bootJar docker { name 'unicon/shibui' tags 'latest' pull true noCache true - files tasks.bootWar.outputs - buildArgs(['JAR_FILE': 'shibui.war']) + files tasks.bootJar.outputs + files 'src/main/docker-files/loader.properties' + buildArgs(['JAR_FILE': 'shibui.jar']) } \ No newline at end of file diff --git a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/WebSecurityConfig.java b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/WebSecurityConfig.java index 4ef76087f..186021597 100644 --- a/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/WebSecurityConfig.java +++ b/backend/src/main/java/edu/internet2/tier/shibboleth/admin/ui/configuration/WebSecurityConfig.java @@ -1,6 +1,8 @@ package edu.internet2.tier.shibboleth.admin.ui.configuration; import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Profile; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; @@ -36,6 +38,7 @@ public HttpFirewall allowUrlEncodedSlashHttpFirewall() { @Bean @Profile("default") + @ConditionalOnMissingBean(value = {WebSecurityConfigurerAdapter.class}) public WebSecurityConfigurerAdapter defaultAuth() { return new WebSecurityConfigurerAdapter() { diff --git a/pac4j-module/Dockerfile b/pac4j-module/Dockerfile index e69de29bb..6c78f991e 100644 --- a/pac4j-module/Dockerfile +++ b/pac4j-module/Dockerfile @@ -0,0 +1,3 @@ +FROM unicon/shibui + +COPY *.jar /libs/ \ No newline at end of file diff --git a/pac4j-module/build.gradle b/pac4j-module/build.gradle index d783ad01f..36817e334 100644 --- a/pac4j-module/build.gradle +++ b/pac4j-module/build.gradle @@ -1,17 +1,17 @@ plugins { id 'java' - id 'org.springframework.boot' version '2.0.0.RELEASE' id 'com.palantir.docker' version '0.20.1' id 'jacoco' id 'io.franzbecker.gradle-lombok' version '1.13' + id 'org.springframework.boot' version '2.0.0.RELEASE' apply false + id 'io.spring.dependency-management' version '1.0.6.RELEASE' } -apply plugin: 'io.spring.dependency-management' - sourceCompatibility = 1.8 targetCompatibility = 1.8 repositories { + mavenLocal() jcenter() maven { url 'https://build.shibboleth.net/nexus/content/groups/public' @@ -24,14 +24,31 @@ lombok { sha256 = "c5178b18caaa1a15e17b99ba5e4023d2de2ebc18b58cde0f5a04ca4b31c10e6d" } +dependencyManagement { + imports { + mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES + } +} + dependencies { compileOnly project(':backend') - compile "org.pac4j:spring-security-pac4j:3.0.0" - compile "org.pac4j:pac4j-saml:2.2.1", { + compile "org.pac4j:spring-security-pac4j:4.0.0" + compile "org.pac4j:pac4j-saml:3.2.0-SNAPSHOT", { // opensaml libraries are provided exclude group: 'org.opensaml' } annotationProcessor "org.springframework.boot:spring-boot-configuration-processor" -} \ No newline at end of file + + docker project(':backend') +} + +docker { + name 'unicon/shibui-pac4j' + tags 'latest-pac4j' + files configurations.runtime, tasks.jar.outputs + noCache true +} + +tasks.docker.dependsOn(tasks.jar, ':backend:docker') \ No newline at end of file diff --git a/pac4j-module/src/main/java/net/unicon/shibui/pac4j/Pac4jConfiguration.java b/pac4j-module/src/main/java/net/unicon/shibui/pac4j/Pac4jConfiguration.java index 193ccaac2..1c28b1ee1 100644 --- a/pac4j-module/src/main/java/net/unicon/shibui/pac4j/Pac4jConfiguration.java +++ b/pac4j-module/src/main/java/net/unicon/shibui/pac4j/Pac4jConfiguration.java @@ -4,6 +4,7 @@ import org.pac4j.core.config.Config; import org.pac4j.saml.client.SAML2Client; import org.pac4j.saml.client.SAML2ClientConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/pac4j-module/src/main/java/net/unicon/shibui/pac4j/WebSecurity.java b/pac4j-module/src/main/java/net/unicon/shibui/pac4j/WebSecurity.java index 80a755431..28bfa1f58 100644 --- a/pac4j-module/src/main/java/net/unicon/shibui/pac4j/WebSecurity.java +++ b/pac4j-module/src/main/java/net/unicon/shibui/pac4j/WebSecurity.java @@ -1,14 +1,46 @@ package net.unicon.shibui.pac4j; +import org.pac4j.core.config.Config; +import org.pac4j.springframework.security.web.CallbackFilter; +import org.pac4j.springframework.security.web.SecurityFilter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; +import org.springframework.security.web.csrf.CookieCsrfTokenRepository; @Configuration -@EnableWebSecurity public class WebSecurity { @Configuration + @Order(1) public static class Pac4jSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter { + private static final Logger logger = LoggerFactory.getLogger(Pac4jSecurityConfigurationAdapter.class); + private final Config config; + + public Pac4jSecurityConfigurationAdapter(Config config) { + logger.info("configuring pac4j authentication"); + this.config = config; + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + final SecurityFilter securityFilter = new SecurityFilter(this.config, "Saml2Client"); + + final CallbackFilter callbackFilter = new CallbackFilter(this.config); + http.antMatcher("/**").addFilterBefore(callbackFilter, BasicAuthenticationFilter.class); + http.authorizeRequests().anyRequest().fullyAuthenticated(); + + http.addFilterBefore(securityFilter, BasicAuthenticationFilter.class); + http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.ALWAYS); + + http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()); + } } } diff --git a/pac4j-module/src/main/resources/META-INF/spring.factories b/pac4j-module/src/main/resources/META-INF/spring.factories index a24bba892..9a6e6cbf2 100644 --- a/pac4j-module/src/main/resources/META-INF/spring.factories +++ b/pac4j-module/src/main/resources/META-INF/spring.factories @@ -1 +1 @@ -org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer = net.unicon.shibui.pac4j.WebSecurity.Pac4jSecurityConfigurationAdapter \ No newline at end of file +org.springframework.boot.autoconfigure.EnableAutoConfiguration=net.unicon.shibui.pac4j.Pac4jConfiguration,net.unicon.shibui.pac4j.WebSecurity,net.unicon.shibui.pac4j.WebSecurity.Pac4jSecurityConfigurationAdapter,net.unicon.shibui.pac4j.Pac4jConfigurationProperties \ No newline at end of file diff --git a/pac4j-module/src/test/docker/conf/application.yml b/pac4j-module/src/test/docker/conf/application.yml new file mode 100644 index 000000000..6bd9b0946 --- /dev/null +++ b/pac4j-module/src/test/docker/conf/application.yml @@ -0,0 +1,9 @@ +shibui: + pac4j: + keystorePath: "/conf/samlKeystore.jks" + keystorePassword: "changeit" + privateKeyPassword: "changeit" + serviceProviderEntityId: "https://unicon.net/shibui" + serviceProviderMetadataPath: "/conf/sp-metadata.xml" + forceServiceProviderMetadataGeneration: true + callbackUrl: "http://localhost:8080/callback \ No newline at end of file diff --git a/pac4j-module/src/test/docker/conf/idp-metadata.xml b/pac4j-module/src/test/docker/conf/idp-metadata.xml new file mode 100644 index 000000000..eddc5010c --- /dev/null +++ b/pac4j-module/src/test/docker/conf/idp-metadata.xml @@ -0,0 +1,30 @@ + + + + + + + MIIDdDCCAlygAwIBAgIGAVWm+BpSMA0GCSqGSIb3DQEBCwUAMHsxFDASBgNVBAoTC0dvb2dsZSBJ +bmMuMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MQ8wDQYDVQQDEwZHb29nbGUxGDAWBgNVBAsTD0dv +b2dsZSBGb3IgV29yazELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWEwHhcNMTYwNzAx +MTQ1ODQ0WhcNMjEwNjMwMTQ1ODQ0WjB7MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEWMBQGA1UEBxMN +TW91bnRhaW4gVmlldzEPMA0GA1UEAxMGR29vZ2xlMRgwFgYDVQQLEw9Hb29nbGUgRm9yIFdvcmsx +CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAirwyeCS6SZpnYxprfXhpTNXwVfQC+J9OvBlJp8/7ngA627yER1bvfUkBMQxo0CXe +H6HX6Vw1DgalZJeEGDZSErlAY7lWkXkHdsejlMoYayQSZz2b/EfeRetwxh3Ek0hMDScOgDlsdfAn +AiZ4//n3IlypCi4ZMnLPs308FYunvp+R0Wd8Yqj8ctKhiYs6fCSHksDd+JKPe2FC1Zqw9GCGhi32 +DBNRTHfE3tX3rTRs1pT0qbrQmpPfeBYfX00astGa3Dq/XWVO62IlqM7nVjglIPdi0tCIx+5RVZrY +uvULMipA+131TMxTpcGjUFxNwzPdogdpNhtL8+erfhG26C6b8wIDAQABMA0GCSqGSIb3DQEBCwUA +A4IBAQCIOe/bW+mdE9PuarSz60HPGe9ROibyEOTyAWGxvSFfqoNFzaH3oOiEHMNG+ZkHHGtGEeWc +KYQ72V1OKO4aNqy2XaT3onOkd2oh4N8Q5pWrgMRkAB2HvBhBcQeO6yojVamTd43Kbtc+Hly3o+Or +XXOR9cgfxX/0Dbb+xwzTcwcMoJ1CPd3T4zxByKMHNflWrgrmZ9DmDOya4Aqs+xvrvPJB2VHaXoJ6 +r/N+xtG8zO8wNRuxQxNUvtcFKKX2sZAqQRASGi1z8Y1FhU6rWBdBRtaiASAIgkNwOmS603Mm08Yr +0Yq7x6h3XlG8HO0bAOto6pr6q85pLqqv7v7/x7mfdjV3 + + + + urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress + + + + diff --git a/pac4j-module/src/test/docker/docker-compose.yml b/pac4j-module/src/test/docker/docker-compose.yml new file mode 100644 index 000000000..73861c077 --- /dev/null +++ b/pac4j-module/src/test/docker/docker-compose.yml @@ -0,0 +1,17 @@ +version: "3.7" + +services: + shibui: + image: unicon/shibui-pac4j + command: "--shibui.pac4j.callbackUrl=http://localhost:8080/callback" + ports: + - 8080:8080 + - 5005:5005 + volumes: + - ./conf:/conf + - ./conf/application.yml:/application.yml + networks: + - front +networks: + front: + driver: bridge \ No newline at end of file