Skip to content

Commit

Permalink
[SHIBUI-1029]
Browse files Browse the repository at this point in the history
Updated tests with support for new custom user mappings.
  • Loading branch information
Bill Smith committed Jan 25, 2019
1 parent 0d35c92 commit 127bfcf
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
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.lang3.RandomStringUtils;
import org.pac4j.saml.profile.SAML2Profile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
Expand All @@ -22,6 +24,7 @@
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Optional;

Expand Down Expand Up @@ -54,31 +57,35 @@ public AddNewUserFilter(CustomPropertiesConfiguration customPropertiesConfigurat
public void init(FilterConfig filterConfig) throws ServletException {
}

private User buildAndPersistNewUserFromProfile(Map<String, Object> attributes) {
private User buildAndPersistNewUserFromProfile(SAML2Profile profile) {
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;
user.setUsername(getAttributeFromProfile(profile, "username"));
user.setPassword(BCrypt.hashpw(RandomStringUtils.randomAlphanumeric(20), BCrypt.gensalt()));
user.setFirstName(getAttributeFromProfile(profile, "firstName"));
user.setLastName(getAttributeFromProfile(profile, "lastName"));
user.setEmailAddress(getAttributeFromProfile(profile, "email"));
User persistedUser = userRepository.save(user);
if (logger.isDebugEnabled()) {
logger.debug("Persisted new user:\n" + user);
}
return persistedUser;
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
SAML2Profile profile = (SAML2Profile) authentication.getPrincipal();
if (profile != null) {
String username = (String) profile.getAttribute(saml2ProfileMapping.get("username"));
String username = getAttributeFromProfile(profile, "username");
if (username != null) {
Optional<User> persistedUser = userRepository.findByUsername(username);
User user;
if (!persistedUser.isPresent()) {
user = buildAndPersistNewUserFromProfile(profile.getAttributes());
user = buildAndPersistNewUserFromProfile(profile);
try {
emailService.sendNewUserMail(username);
} catch (MessagingException e) {
Expand All @@ -100,6 +107,18 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
public void destroy() {
}

private String getAttributeFromProfile(SAML2Profile profile, String stringKey) {
String mappingKey = saml2ProfileMapping.get(stringKey);
List<String> attributeList = (List<String>) profile.getAttribute(mappingKey);
String attribute = null;
if (attributeList.size() > 0) {
if (attributeList.size() != 1) {
logger.warn(String.format("More than one attribute was found for key [%s]", stringKey));
}
attribute = attributeList.get(0);
}
return attribute;
}
private byte[] getJsonResponseBytes(ErrorResponse eErrorResponse) throws IOException {
String errorResponseJson = new ObjectMapper().writeValueAsString(eErrorResponse);
return errorResponseJson.getBytes();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
package net.unicon.shibui.pac4j;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
* @author Bill Smith (wsmith@unicon.net)
*/
@Component
@ConfigurationProperties(prefix="custom")
@EnableConfigurationProperties
public class CustomPropertiesConfiguration {

private Map<String, String> saml2ProfileMapping;
Expand Down
4 changes: 2 additions & 2 deletions pac4j-module/src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
custom:
saml2ProfileMapping:
username: urn:oid:0.9.2342.19200300.100.1.3
firstname: givenName
lastname: sn
firstName: givenName
lastName: sn
email: mail
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import edu.internet2.tier.shibboleth.admin.ui.security.model.User
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.pac4j.saml.profile.SAML2Profile
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.context.annotation.ComponentScan
import org.springframework.security.core.Authentication
import org.springframework.security.core.context.SecurityContext
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.test.context.ContextConfiguration
import spock.lang.Specification
import spock.lang.Subject

Expand All @@ -22,9 +22,8 @@ import javax.servlet.http.HttpServletResponse
/**
* @author Bill Smith (wsmith@unicon.net)
*/
@SpringBootTest
@ComponentScan("net.unicon.shibui.pac4j")
@ContextConfiguration(classes=[CustomPropertiesConfiguration])
@SpringBootTest(classes = [CustomPropertiesConfiguration])
@EnableConfigurationProperties([CustomPropertiesConfiguration])
class AddNewUserFilterTests extends Specification {

UserRepository userRepository = Mock()
Expand All @@ -37,20 +36,31 @@ class AddNewUserFilterTests extends Specification {

SecurityContext securityContext = Mock()
Authentication authentication = Mock()
SAML2Profile saml2Profile = Mock()

@Autowired
CustomPropertiesConfiguration customPropertiesConfiguration

Map<String, String> userAttributeMapping

@Subject
AddNewUserFilter addNewUserFilter = new AddNewUserFilter(customPropertiesConfiguration, userRepository, roleRepository, emailService)
AddNewUserFilter addNewUserFilter

def setup() {
SecurityContextHolder.setContext(securityContext)
securityContext.getAuthentication() >> authentication
authentication.getPrincipal() >> saml2Profile

addNewUserFilter = new AddNewUserFilter(customPropertiesConfiguration, userRepository, roleRepository, emailService)
userAttributeMapping = customPropertiesConfiguration.saml2ProfileMapping
}

def "new users are redirected"() {
given:
authentication.getName() >> 'newUser'
saml2Profile.getAttribute(userAttributeMapping.get('username')) >> ['newUser']
saml2Profile.getAttribute(userAttributeMapping.get('firstName')) >> ['New']
saml2Profile.getAttribute(userAttributeMapping.get('lastName')) >> ['User']
saml2Profile.getAttribute(userAttributeMapping.get('email')) >> ['newuser@institution.edu']
userRepository.findByUsername('newUser') >> Optional.empty()
roleRepository.findByName('ROLE_NONE') >> Optional.of(new Role('ROLE_NONE'))

Expand All @@ -59,14 +69,14 @@ class AddNewUserFilterTests extends Specification {

then:
1 * roleRepository.save(_)
1 * userRepository.save(_)
1 * userRepository.save(_ as User) >> { User user -> user }
1 * emailService.sendNewUserMail('newUser')
1 * response.sendRedirect("/static.html")
}

def "existing users are not redirected"() {
given:
authentication.getName() >> 'existingUser'
saml2Profile.getAttribute(userAttributeMapping.get('username')) >> ['existingUser']
userRepository.findByUsername('existingUser') >> Optional.of(new User().with {
it.username = 'existingUser'
it.roles = [new Role('ROLE_USER')]
Expand Down

0 comments on commit 127bfcf

Please sign in to comment.