Skip to content

Commit

Permalink
SHIBUI-1748
Browse files Browse the repository at this point in the history
Finally got the configuration working
  • Loading branch information
chasegawa committed Jul 9, 2021
1 parent 57eb294 commit 401dbf9
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 169 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -24,13 +25,16 @@

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
* @see http://www.pac4j.org/docs/config.html
*/
@Configuration
@ConditionalOnProperty(name = "shibui.pac4j-enabled", havingValue = "true")
@Slf4j
public class Pac4jConfiguration {
public final static String PAC4J_CLIENT_NAME = "shibUIAuthClient";

Expand All @@ -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());
Expand All @@ -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
Expand All @@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
}

38 changes: 20 additions & 18 deletions pac4j-module/src/main/java/net/unicon/shibui/pac4j/WebSecurity.java
Original file line number Diff line number Diff line change
Expand Up @@ -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> emailService,
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 401dbf9

Please sign in to comment.