From 29d948d8a0a5f65d52d199178c913a30da3794ba Mon Sep 17 00:00:00 2001 From: Bill Smith Date: Thu, 24 Jan 2019 17:52:24 -0700 Subject: [PATCH] [SHIBUI-1029] Custom user attributes mapping WIP. Need to deal with some casting issues. --- .../unicon/shibui/pac4j/AddNewUserFilter.java | 41 ++++++++++++------- .../pac4j/CustomPropertiesConfiguration.java | 26 ++++++++++++ .../net/unicon/shibui/pac4j/WebSecurity.java | 10 +++-- .../main/resources/META-INF/spring.factories | 3 +- .../src/main/resources/application.yml | 6 +++ 5 files changed, 67 insertions(+), 19 deletions(-) create mode 100644 pac4j-module/src/main/java/net/unicon/shibui/pac4j/CustomPropertiesConfiguration.java create mode 100644 pac4j-module/src/main/resources/application.yml diff --git a/pac4j-module/src/main/java/net/unicon/shibui/pac4j/AddNewUserFilter.java b/pac4j-module/src/main/java/net/unicon/shibui/pac4j/AddNewUserFilter.java index 5c5bf6e12..d30acf5bd 100644 --- a/pac4j-module/src/main/java/net/unicon/shibui/pac4j/AddNewUserFilter.java +++ b/pac4j-module/src/main/java/net/unicon/shibui/pac4j/AddNewUserFilter.java @@ -7,14 +7,11 @@ import edu.internet2.tier.shibboleth.admin.ui.security.repository.RoleRepository; import edu.internet2.tier.shibboleth.admin.ui.security.repository.UserRepository; import edu.internet2.tier.shibboleth.admin.ui.service.EmailService; -import org.apache.commons.lang.RandomStringUtils; -import org.apache.http.entity.ContentType; +import org.pac4j.saml.profile.SAML2Profile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.http.HttpStatus; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.crypto.bcrypt.BCrypt; import javax.mail.MessagingException; import javax.servlet.Filter; @@ -25,6 +22,7 @@ import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import java.util.Map; import java.util.Optional; /** @@ -40,32 +38,47 @@ public class AddNewUserFilter implements Filter { private RoleRepository roleRepository; private EmailService emailService; - public AddNewUserFilter(UserRepository userRepository, RoleRepository roleRepository, EmailService emailService) { + private CustomPropertiesConfiguration customPropertiesConfiguration; + + private Map saml2ProfileMapping; + + public AddNewUserFilter(CustomPropertiesConfiguration customPropertiesConfiguration, UserRepository userRepository, RoleRepository roleRepository, EmailService emailService) { this.userRepository = userRepository; this.roleRepository = roleRepository; this.emailService = emailService; + this.customPropertiesConfiguration = customPropertiesConfiguration; + saml2ProfileMapping = this.customPropertiesConfiguration.getSaml2ProfileMapping(); } @Override public void init(FilterConfig filterConfig) throws ServletException { } + private User buildAndPersistNewUserFromProfile(Map attributes) { + Role noRole = roleRepository.findByName(ROLE_NONE).orElse(new Role(ROLE_NONE)); + roleRepository.save(noRole); + + User user = new User(); + user.getRoles().add(noRole); + user.setUsername((String) attributes.get(saml2ProfileMapping.get("username"))); + user.setFirstName((String) attributes.get(saml2ProfileMapping.get("firstName"))); + user.setLastName((String) attributes.get(saml2ProfileMapping.get("lastName"))); + user.setEmailAddress((String) attributes.get(saml2ProfileMapping.get("email"))); + userRepository.save(user); + return user; + } + @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - if (authentication != null) { - String username = authentication.getName(); + SAML2Profile profile = (SAML2Profile) authentication.getPrincipal(); + if (profile != null) { + String username = (String) profile.getAttribute(saml2ProfileMapping.get("username")); if (username != null) { Optional persistedUser = userRepository.findByUsername(username); User user; if (!persistedUser.isPresent()) { - user = new User(); - user.setUsername(username); - user.setPassword(BCrypt.hashpw(RandomStringUtils.randomAlphanumeric(20), BCrypt.gensalt())); - Role noRole = roleRepository.findByName(ROLE_NONE).orElse(new Role(ROLE_NONE)); - roleRepository.save(noRole); - user.getRoles().add(noRole); - userRepository.save(user); + user = buildAndPersistNewUserFromProfile(profile.getAttributes()); try { emailService.sendNewUserMail(username); } catch (MessagingException e) { diff --git a/pac4j-module/src/main/java/net/unicon/shibui/pac4j/CustomPropertiesConfiguration.java b/pac4j-module/src/main/java/net/unicon/shibui/pac4j/CustomPropertiesConfiguration.java new file mode 100644 index 000000000..9d0f745b6 --- /dev/null +++ b/pac4j-module/src/main/java/net/unicon/shibui/pac4j/CustomPropertiesConfiguration.java @@ -0,0 +1,26 @@ +package net.unicon.shibui.pac4j; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Bill Smith (wsmith@unicon.net) + */ +@Component +@ConfigurationProperties(prefix="custom") +public class CustomPropertiesConfiguration { + + private Map saml2ProfileMapping; + + public Map getSaml2ProfileMapping() { + return saml2ProfileMapping; + } + + public void setSaml2ProfileMapping(Map saml2ProfileMapping) { + this.saml2ProfileMapping = saml2ProfileMapping; + } +} 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 e0e156eec..421dffe63 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 @@ -20,8 +20,8 @@ @AutoConfigureOrder(-1) public class WebSecurity { @Bean("webSecurityConfig") - public WebSecurityConfigurerAdapter webSecurityConfigurerAdapter(final Config config, UserRepository userRepository, RoleRepository roleRepository, EmailService emailService) { - return new Pac4jWebSecurityConfigurerAdapter(config, userRepository, roleRepository, emailService); + public WebSecurityConfigurerAdapter webSecurityConfigurerAdapter(final Config config, UserRepository userRepository, RoleRepository roleRepository, EmailService emailService, CustomPropertiesConfiguration customPropertiesConfiguration) { + return new Pac4jWebSecurityConfigurerAdapter(config, userRepository, roleRepository, emailService, customPropertiesConfiguration); } @Configuration @@ -57,12 +57,14 @@ public static class Pac4jWebSecurityConfigurerAdapter extends WebSecurityConfigu private UserRepository userRepository; private RoleRepository roleRepository; private EmailService emailService; + private CustomPropertiesConfiguration customPropertiesConfiguration; - public Pac4jWebSecurityConfigurerAdapter(final Config config, UserRepository userRepository, RoleRepository roleRepository, EmailService emailService) { + public Pac4jWebSecurityConfigurerAdapter(final Config config, UserRepository userRepository, RoleRepository roleRepository, EmailService emailService, CustomPropertiesConfiguration customPropertiesConfiguration) { this.config = config; this.userRepository = userRepository; this.roleRepository = roleRepository; this.emailService = emailService; + this.customPropertiesConfiguration = customPropertiesConfiguration; } @Override @@ -72,7 +74,7 @@ protected void configure(HttpSecurity http) throws Exception { final CallbackFilter callbackFilter = new CallbackFilter(this.config); http.antMatcher("/**").addFilterBefore(callbackFilter, BasicAuthenticationFilter.class) .addFilterBefore(securityFilter, BasicAuthenticationFilter.class) - .addFilterAfter(new AddNewUserFilter(userRepository, roleRepository, emailService), SecurityFilter.class); + .addFilterAfter(new AddNewUserFilter(customPropertiesConfiguration, userRepository, roleRepository, emailService), SecurityFilter.class); http.authorizeRequests().anyRequest().fullyAuthenticated(); diff --git a/pac4j-module/src/main/resources/META-INF/spring.factories b/pac4j-module/src/main/resources/META-INF/spring.factories index 90f792d84..f46ede845 100644 --- a/pac4j-module/src/main/resources/META-INF/spring.factories +++ b/pac4j-module/src/main/resources/META-INF/spring.factories @@ -1,4 +1,5 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ net.unicon.shibui.pac4j.Pac4jConfiguration,\ net.unicon.shibui.pac4j.WebSecurity,\ - net.unicon.shibui.pac4j.Pac4jConfigurationProperties \ No newline at end of file + net.unicon.shibui.pac4j.Pac4jConfigurationProperties,\ + net.unicon.shibui.pac4j.CustomPropertiesConfiguration \ No newline at end of file diff --git a/pac4j-module/src/main/resources/application.yml b/pac4j-module/src/main/resources/application.yml new file mode 100644 index 000000000..7ffeb8bf9 --- /dev/null +++ b/pac4j-module/src/main/resources/application.yml @@ -0,0 +1,6 @@ +custom: + saml2ProfileMapping: + username: urn:oid:0.9.2342.19200300.100.1.3 + firstname: givenName + lastname: sn + email: mail \ No newline at end of file