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 f8f5f6a55..ac3f159c2 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 @@ -16,6 +16,7 @@ import org.pac4j.saml.client.SAML2Client; import org.pac4j.saml.config.SAML2Configuration; import org.pac4j.saml.credentials.authenticator.SAML2Authenticator; +import org.springframework.boot.autoconfigure.AutoConfigureOrder; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -24,6 +25,8 @@ import edu.internet2.tier.shibboleth.admin.ui.security.repository.UserRepository; +import lombok.extern.slf4j.Slf4j; + /** * Configuration setup here following readme from - https://github.com/pac4j/spring-security-pac4j/tree/5.0.x * NOTE: matchers are now done as part of the config and have been moved over from the WebSecurity.java class of this package @@ -31,6 +34,7 @@ */ @Configuration @ConditionalOnProperty(name = "shibui.pac4j-enabled", havingValue = "true") +@Slf4j public class Pac4jConfiguration { public final static String PAC4J_CLIENT_NAME = "shibUIAuthClient"; @@ -42,15 +46,17 @@ public SAML2ModelAuthorizationGenerator saml2ModelAuthorizationGenerator(UserRep return new SAML2ModelAuthorizationGenerator(userRepository); } - @Bean + @Bean(name = "pac4j-config") public Config config(final Pac4jConfigurationProperties pac4jConfigProps, - final SAML2ModelAuthorizationGenerator saml2ModelAuthorizationGenerator) { - + final SAML2ModelAuthorizationGenerator saml2ModelAuthorizationGenerator) { + log.info("**** Configuring PAC4J "); + final Config config = new Config(); final Clients clients = new Clients(pac4jConfigProps.getCallbackUrl()); // Configure the client switch (pac4jConfigProps.getTypeOfAuth()) { case "SAML2": { + log.info("**** Configuring PAC4J SAML2"); final SAML2Configuration saml2Config = new SAML2Configuration(); saml2Config.setKeystorePath(pac4jConfigProps.getKeystorePath()); saml2Config.setKeystorePassword(pac4jConfigProps.getKeystorePassword()); @@ -76,6 +82,7 @@ public Config config(final Pac4jConfigurationProperties pac4jConfigProps, clients.setClients(saml2Client); } case "HEADER": { + log.info("**** Configuring PAC4J Header Client"); HeaderClient headerClient = new HeaderClient(pac4jConfigProps.getAuthenticationHeader(), new Authenticator() { @Override @@ -99,13 +106,13 @@ public void validate(Credentials credentials, WebContext context, SessionStore s clients.setClients(headerClient); } } - final Config config = new Config(clients); // configure the matcher for bypassing auth checks PathMatcher pm = new PathMatcher(); pm.setExcludedPaths(Lists.newArrayList("/favicon.ico", "/unsecured/**/*", "/error", "/login", "/")); config.addMatcher("exclude-paths-matcher", pm); + config.setClients(clients); return config; } } diff --git a/pac4j-module/src/main/java/net/unicon/shibui/pac4j/Pac4jConfigurationProperties.java b/pac4j-module/src/main/java/net/unicon/shibui/pac4j/Pac4jConfigurationProperties.java index 57e38d91b..8a44baf47 100644 --- a/pac4j-module/src/main/java/net/unicon/shibui/pac4j/Pac4jConfigurationProperties.java +++ b/pac4j-module/src/main/java/net/unicon/shibui/pac4j/Pac4jConfigurationProperties.java @@ -1,172 +1,47 @@ package net.unicon.shibui.pac4j; +import javax.servlet.Filter; + +import org.pac4j.springframework.security.web.CallbackFilter; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.stereotype.Component; +import lombok.Getter; +import lombok.Setter; + @Component @ConfigurationProperties(prefix = "shibui.pac4j") @EnableConfigurationProperties @ConditionalOnProperty(name = "shibui.pac4j-enabled", havingValue = "true") +@Getter +@Setter public class Pac4jConfigurationProperties { - final static String DEFAULT_AUTH_HEADER = "REMOTE_USER"; - private String keystorePath = "/tmp/samlKeystore.jks"; - private String keystorePassword = "changeit"; - private String privateKeyPassword = "changeit"; + final static String DEFAULT_AUTH_HEADER = "REMOTE_USER"; + private String authenticationHeader = DEFAULT_AUTH_HEADER; + private String callbackUrl; + private boolean forceServiceProviderMetadataGeneration = false; private String identityProviderMetadataPath = "/tmp/idp-metadata.xml"; + private String keystorePassword = "changeit"; + private String keystorePath = "/tmp/samlKeystore.jks"; private int maximumAuthenticationLifetime = 3600; + private String privateKeyPassword = "changeit"; + private SAML2ProfileMapping saml2ProfileMapping; private String serviceProviderEntityId = "https://unicon.net/shibui"; private String serviceProviderMetadataPath = "/tmp/sp-metadata.xml"; - private boolean forceServiceProviderMetadataGeneration = false; - private String callbackUrl; - private boolean wantAssertionsSigned = true; - private SAML2ProfileMapping saml2ProfileMapping; private String typeOfAuth = "SAML2"; - private String authenticationHeader = DEFAULT_AUTH_HEADER; + private boolean wantAssertionsSigned = true; + + @Getter + @Setter public static class SAML2ProfileMapping { - private String username; private String email; private String firstName; private String lastName; - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - } - - public String getKeystorePath() { - return keystorePath; - } - - public void setKeystorePath(String keystorePath) { - this.keystorePath = keystorePath; - } - - public String getKeystorePassword() { - return keystorePassword; - } - - public void setKeystorePassword(String keystorePassword) { - this.keystorePassword = keystorePassword; - } - - public String getPrivateKeyPassword() { - return privateKeyPassword; - } - - public void setPrivateKeyPassword(String privateKeyPassword) { - this.privateKeyPassword = privateKeyPassword; - } - - public String getIdentityProviderMetadataPath() { - return identityProviderMetadataPath; - } - - public void setIdentityProviderMetadataPath(String identityProviderMetadataPath) { - this.identityProviderMetadataPath = identityProviderMetadataPath; - } - - public int getMaximumAuthenticationLifetime() { - return maximumAuthenticationLifetime; - } - - public void setMaximumAuthenticationLifetime(int maximumAuthenticationLifetime) { - this.maximumAuthenticationLifetime = maximumAuthenticationLifetime; - } - - public String getServiceProviderEntityId() { - return serviceProviderEntityId; - } - - public void setServiceProviderEntityId(String serviceProviderEntityId) { - this.serviceProviderEntityId = serviceProviderEntityId; - } - - public String getServiceProviderMetadataPath() { - return serviceProviderMetadataPath; - } - - public void setServiceProviderMetadataPath(String serviceProviderMetadataPath) { - this.serviceProviderMetadataPath = serviceProviderMetadataPath; - } - - public boolean isForceServiceProviderMetadataGeneration() { - return forceServiceProviderMetadataGeneration; - } - - public void setForceServiceProviderMetadataGeneration(boolean forceServiceProviderMetadataGeneration) { - this.forceServiceProviderMetadataGeneration = forceServiceProviderMetadataGeneration; - } - - public String getCallbackUrl() { - return callbackUrl; - } - - public void setCallbackUrl(String callbackUrl) { - this.callbackUrl = callbackUrl; - } - - public boolean isWantAssertionsSigned() { - return wantAssertionsSigned; - } - - public void setWantAssertionsSigned(boolean wantAssertionsSigned) { - this.wantAssertionsSigned = wantAssertionsSigned; - } - - public SAML2ProfileMapping getSaml2ProfileMapping() { - return saml2ProfileMapping; - } - - public void setSaml2ProfileMapping(SAML2ProfileMapping saml2ProfileMapping) { - this.saml2ProfileMapping = saml2ProfileMapping; - } - - public String getTypeOfAuth() { - return typeOfAuth; - } - - public void setTypeOfAuth(String typeOfAuth) { - this.typeOfAuth = typeOfAuth; - } - - public String getAuthenticationHeader() { - return authenticationHeader; - } - - public void setAuthenticationHeader(String authenticationHeader) { - this.authenticationHeader = authenticationHeader; - } + private String username; + } } 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 fc8532196..d42206e3f 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 @@ -26,14 +26,13 @@ import java.util.Optional; +import javax.servlet.Filter; + @Configuration @AutoConfigureOrder(-1) @ConditionalOnProperty(name = "shibui.pac4j-enabled", havingValue = "true") @AutoConfigureAfter(EmailConfiguration.class) -public class WebSecurity { - @Value("${shibui.logout-url:/dashboard}") - private static String logoutUrl; - +public class WebSecurity { @Bean("webSecurityConfig") public WebSecurityConfigurerAdapter webSecurityConfigurerAdapter(final Config config, UserRepository userRepository, RoleRepository roleRepository, Optional emailService, @@ -61,26 +60,29 @@ public Pac4jWebSecurityConfigurerAdapter(final Config config, UserRepository use @Override protected void configure(HttpSecurity http) throws Exception { - final SecurityFilter securityFilterForHeader = new SecurityFilter(this.config, Pac4jConfiguration.PAC4J_CLIENT_NAME); - securityFilterForHeader.setMatchers("exclude-paths-matcher"); - - final CallbackFilter callbackFilter = new CallbackFilter(this.config); - - http.antMatcher("/**").addFilterBefore(callbackFilter, BasicAuthenticationFilter.class) - .addFilterBefore(securityFilterForHeader, BasicAuthenticationFilter.class) - .addFilterAfter(new AddNewUserFilter(pac4jConfigurationProperties, userRepository, roleRepository, - emailService), SecurityFilter.class); + http.antMatcher("/**"); + http.addFilterBefore(getFilter(config, pac4jConfigurationProperties.getTypeOfAuth()), BasicAuthenticationFilter.class); + http.addFilterAfter(new AddNewUserFilter(pac4jConfigurationProperties, userRepository, roleRepository, emailService), SecurityFilter.class); http.authorizeRequests().anyRequest().fullyAuthenticated(); - - http.exceptionHandling().accessDeniedHandler((request, response, accessDeniedException) -> response.sendRedirect("/unsecured/error.html")) - .and().formLogin().and().httpBasic().and() - .logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl(StringUtils.isAllEmpty(logoutUrl) ? "/dashboard" : logoutUrl); - + http.exceptionHandling().accessDeniedHandler((request, response, accessDeniedException) -> response.sendRedirect("/unsecured/error.html")); http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.ALWAYS); http.csrf().disable(); http.headers().frameOptions().disable(); } + private Filter getFilter(Config config2, String typeOfAuth) { + switch (typeOfAuth) { + case "SAML2": + return new CallbackFilter(this.config); + case "HEADER": + final SecurityFilter securityFilterForHeader = new SecurityFilter(this.config, + Pac4jConfiguration.PAC4J_CLIENT_NAME); + securityFilterForHeader.setMatchers("exclude-paths-matcher"); + return securityFilterForHeader; + } + return null; // This will cause a runtime error + } + @Override public void configure(org.springframework.security.config.annotation.web.builders.WebSecurity web) throws Exception { super.configure(web);