Skip to content

Commit

Permalink
[SHIBUI-1044]
Browse files Browse the repository at this point in the history
refactor
cleanup
  • Loading branch information
jj committed Dec 12, 2018
1 parent 5bfa4a8 commit ec99101
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 85 deletions.
3 changes: 3 additions & 0 deletions backend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ dependencies {

//JSON schema validator
compile 'org.sharegov:mjson:1.4.1'

// CSV file support
compile 'com.opencsv:opencsv:4.4'
}

def generatedSrcDir = new File(buildDir, 'generated/src/main/java')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package edu.internet2.tier.shibboleth.admin.ui.service

import com.opencsv.CSVReader
import edu.internet2.tier.shibboleth.admin.ui.configuration.ShibUIConfiguration
import edu.internet2.tier.shibboleth.admin.ui.security.model.Role
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 groovy.util.logging.Slf4j
import org.springframework.boot.context.event.ApplicationStartedEvent
import org.springframework.context.event.EventListener
import org.springframework.stereotype.Component

import javax.transaction.Transactional

@Component
@Slf4j
class UserBootstrap {
private final ShibUIConfiguration shibUIConfiguration
private final UserRepository userRepository
private final RoleRepository roleRepository

UserBootstrap(ShibUIConfiguration shibUIConfiguration, UserRepository userRepository, RoleRepository roleRepository) {
this.shibUIConfiguration = shibUIConfiguration
this.userRepository = userRepository
this.roleRepository = roleRepository
}

@Transactional
@EventListener
void bootstrapUsersAndRoles(ApplicationStartedEvent e) {
if (shibUIConfiguration.userBootstrapResource.isPresent()) {
log.info("configuring users from ${shibUIConfiguration.userBootstrapResource.get().URI}")
new CSVReader(new InputStreamReader(shibUIConfiguration.userBootstrapResource.get().inputStream)).each { it ->
def (username, password, firstName, lastName, roleName) = it
def role = roleRepository.findByName(roleName).orElse(roleRepository.save(new Role(name: roleName)))
def user = userRepository.findByUsername(username).orElse(new User(username: username)).with {
it.password = password
it.firstName = firstName
it.lastName = lastName
it.roles.add(role)
it
}
userRepository.save(user)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
package edu.internet2.tier.shibboleth.admin.ui;

import edu.internet2.tier.shibboleth.admin.ui.configuration.auto.WebSecurityConfig;
import edu.internet2.tier.shibboleth.admin.ui.configuration.auto.WebSecurityConfig.SupportedRoles;
import edu.internet2.tier.shibboleth.admin.ui.repository.MetadataResolverRepository;
import edu.internet2.tier.shibboleth.admin.ui.security.model.Role;
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.MetadataResolverService;
import edu.internet2.tier.shibboleth.admin.ui.service.UsersCsvParserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -25,16 +18,9 @@
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;

@SpringBootApplication
@ComponentScan(excludeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = "edu.internet2.tier.shibboleth.admin.ui.configuration.auto.*"))
@EntityScan(basePackages = {"edu.internet2.tier.shibboleth.admin.ui.domain", "edu.internet2.tier.shibboleth.admin.ui.security.model"})
Expand Down Expand Up @@ -87,58 +73,4 @@ public void initializeResolvers(ApplicationStartedEvent e) {
});
}
}

@Component
public static class UsersBootstrapStartupListener {

@Autowired
UsersCsvParserService usersCsvParserService;

@Autowired
UserRepository userRepository;

@Autowired
RoleRepository roleRepository;

private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();

@Transactional
@EventListener
public void bootstrapUsersAndRoles(ApplicationStartedEvent e) {
bootstrapRoles();
List<User> users = usersCsvParserService.parseUsersFromCsv();
for (User user : users) {
User toBePersistedUser;
Optional<User> existingUser = userRepository.findByUsername(user.getUsername());
if (existingUser.isPresent()) {
toBePersistedUser = existingUser.get();
} else {
toBePersistedUser = new User();
toBePersistedUser.setUsername(user.getUsername());
}
toBePersistedUser.setFirstName(user.getFirstName());
toBePersistedUser.setLastName(user.getLastName());
toBePersistedUser.setPassword(ENCODER.encode(user.getPassword()));
Set<Role> toBePersistedRoles = new HashSet<>();
for (Role role : user.getRoles()) {
Optional<Role> existingRole = roleRepository.findByName(role.getName());
if (existingRole.isPresent()) {
toBePersistedRoles.add(existingRole.get());
}
}
toBePersistedUser.setRoles(toBePersistedRoles);
userRepository.save(toBePersistedUser);
}
}

private void bootstrapRoles() {
for (SupportedRoles role : SupportedRoles.values()) {
if (!roleRepository.findByName(role.name()).isPresent()) {
Role toBePersistedRole = new Role();
toBePersistedRole.setName(role.name());
roleRepository.save(toBePersistedRole);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import edu.internet2.tier.shibboleth.admin.ui.service.JPAMetadataResolverServiceImpl;
import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolverService;
import edu.internet2.tier.shibboleth.admin.ui.service.MetadataResolversPositionOrderContainerService;
import edu.internet2.tier.shibboleth.admin.ui.service.UsersCsvParserService;
import edu.internet2.tier.shibboleth.admin.util.AttributeUtility;
import edu.internet2.tier.shibboleth.admin.util.LuceneUtility;
import edu.internet2.tier.shibboleth.admin.util.ModelRepresentationConversions;
Expand Down Expand Up @@ -195,9 +194,4 @@ public Module stringTrimModule() {
public ModelRepresentationConversions modelRepresentationConversions() {
return new ModelRepresentationConversions(customPropertiesConfiguration());
}

@Bean
public UsersCsvParserService usersCsvParserService() {
return new UsersCsvParserService();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package edu.internet2.tier.shibboleth.admin.ui.configuration;

import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;

import java.util.List;
import java.util.Optional;

@Configuration
@ConfigurationProperties(prefix = "shibui")
@Getter
@Setter
public class ShibUIConfiguration {
/**
* A list of namespaces that should be excluded from incoming metadata. This is used to prevent third party metadata
* sources from using attributes that they might not have the rights to use.
*/
private List<String> protectedAttributeNamespaces;

/**
* A Resource containing a CSV of users to bootstrap into the system. Currently, this must be in format
*
* username,password,firstName,lastName,role
*
* Note that the password must be encrypted in the file using the system configured password encryption (by default,
* bcrypt)
*/
private Optional<Resource> userBootstrapResource;
}
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,5 @@ public void configure(WebSecurity web) throws Exception {
}
};
}

public enum SupportedRoles {
ROLE_ADMIN,
ROLE_USER
}
}

6 changes: 0 additions & 6 deletions backend/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,3 @@ shibui.entity-attributes-filters-ui-schema-location=classpath:entity-attributes-
# Set the following property to periodically write out metadata providers configuration. There is no default value; the following is just an example
# shibui.metadataProviders.target=file:/opt/shibboleth-idp/conf/shibui-metadata-providers.xml
# shibui.metadataProviders.taskRunRate=30000

# CSV ile to bootstrap users from
# Entries should be of the form:
# username,password,firstName,lastName[,role1,role2,...,roleN}
# Note that the only roles currently supported are ROLE_ADMIN and ROLE_USER
bootstrap.users.csv.filename=bootstrap-users.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package edu.internet2.tier.shibboleth.admin.ui.service

import edu.internet2.tier.shibboleth.admin.ui.configuration.CoreShibUiConfiguration
import edu.internet2.tier.shibboleth.admin.ui.configuration.InternationalizationConfiguration
import edu.internet2.tier.shibboleth.admin.ui.configuration.SearchConfiguration
import edu.internet2.tier.shibboleth.admin.ui.configuration.ShibUIConfiguration
import edu.internet2.tier.shibboleth.admin.ui.configuration.TestConfiguration
import edu.internet2.tier.shibboleth.admin.ui.security.repository.RoleRepository
import edu.internet2.tier.shibboleth.admin.ui.security.repository.UserRepository
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.autoconfigure.domain.EntityScan
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
import org.springframework.core.io.ClassPathResource
import org.springframework.data.jpa.repository.config.EnableJpaRepositories
import org.springframework.test.annotation.DirtiesContext
import org.springframework.test.context.ContextConfiguration
import spock.lang.Specification

@DataJpaTest
@ContextConfiguration(classes=[CoreShibUiConfiguration, SearchConfiguration, TestConfiguration, InternationalizationConfiguration, ShibUIConfiguration])
@EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"])
@EntityScan(["edu.internet2.tier.shibboleth.admin.ui", "edu.internet2.tier.shibboleth.admin.ui.security.model"])
@DirtiesContext(methodMode = DirtiesContext.MethodMode.AFTER_METHOD)
class UserBootstrapTests extends Specification {
@Autowired
ShibUIConfiguration shibUIConfiguration

@Autowired
UserRepository userRepository

@Autowired
RoleRepository roleRepository

def "simple test"() {
setup:
shibUIConfiguration.userBootstrapResource = Optional.of(new ClassPathResource('/conf/1044.csv'))
def userBootstrap = new UserBootstrap(shibUIConfiguration, userRepository, roleRepository)

when:
userBootstrap.bootstrapUsersAndRoles(null)

then:
noExceptionThrown()
assert userRepository.findAll().size() == 2
assert roleRepository.findAll().size() == 2
}
}
2 changes: 2 additions & 0 deletions backend/src/test/resources/conf/1044.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"user1","password1","firstName1","lastName1","ROLE_ADMIN"
"user2","password2","firstName2","lastName2","ROLE_USER"

0 comments on commit ec99101

Please sign in to comment.