Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/feature/SHIBUI-1062' into featur…
Browse files Browse the repository at this point in the history
…e/SHIBUI-1062
  • Loading branch information
Bill Smith committed Jan 25, 2019
2 parents ae1df15 + aaaf521 commit 26258f6
Show file tree
Hide file tree
Showing 21 changed files with 1,063 additions and 397 deletions.
4 changes: 4 additions & 0 deletions backend/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ configurations {

processResources.dependsOn(':ui:npm_run_buildProd')

jar {
enabled = true
}

//Integration of the frontend and backend into the build to have all of the UI resources available in the app's executable war
bootWar.dependsOn(':ui:npm_run_buildProd')
bootWar.baseName = 'shibui'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,15 @@ class UserBootstrap {
if (shibUIConfiguration.userBootstrapResource) {
log.info("configuring users from ${shibUIConfiguration.userBootstrapResource.URI}")
new CSVReader(new InputStreamReader(shibUIConfiguration.userBootstrapResource.inputStream)).each { it ->
def (username, password, firstName, lastName, roleName) = it
def (username, password, firstName, lastName, roleName, email) = it
def role = roleRepository.findByName(roleName).orElse(new Role(name: roleName))
roleRepository.saveAndFlush(role)
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.emailAddress = email
it
}
userRepository.saveAndFlush(user)
Expand Down
2 changes: 1 addition & 1 deletion backend/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ shibui.nameid-filter-ui-schema-location=classpath:nameid-filter.schema.json
# shibui.metadataProviders.taskRunRate=30000

# Email configuration (local mailhog)
spring.mail.host=localhost
spring.mail.host=mailhog
spring.mail.port=1025
spring.mail.username=username
spring.mail.password=password
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,15 +117,16 @@
"refreshDelayFactor": {
"title": "label.refresh-delay-factor",
"description": "tooltip.refresh-delay-factor",
"type": "number",
"type": "string",
"widget": {
"id": "number",
"step": 0.01
},
"placeholder": "label.real-number",
"minimum": 0.01,
"maximum": 0.99,
"default": null
"minimum": 0,
"maximum": 1,
"default": null,
"pattern": "^([0]*(\\.[0-9]+)?|[0]*\\.[0-9]*[1-9][0-9]*)$"
},
"minCacheDuration": {
"title": "label.min-cache-duration",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,15 +128,16 @@
"refreshDelayFactor": {
"title": "label.refresh-delay-factor",
"description": "tooltip.refresh-delay-factor",
"type": "number",
"type": "string",
"widget": {
"id": "number",
"step": 0.01
},
"placeholder": "label.real-number",
"minimum": 0,
"maximum": 0.99,
"default": null
"maximum": 1,
"default": null,
"pattern": "^([0]*(\\.[0-9]+)?|[0]*\\.[0-9]*[1-9][0-9]*)$"
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions backend/src/main/resources/i18n/messages_en.properties
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,9 @@ message.required-for-regex=Required for Regex
message.file-doesnt-exist=The requested file to be processed does not exist on the server.
message.database-constraint=There was a database constraint problem processing the request. Check the request to ensure that fields that must be unique are truly unique.

message.user-request-received-title=User request received
message.user-request-received-body=Your request has been received and is being reviewed. You will be notified with access status.

tooltip.entity-id=Entity ID
tooltip.service-provider-name=Service Provider Name (Dashboard Display Only)
tooltip.force-authn=Disallows use (or reuse) of authentication results and login flows that don\u0027t provide a real-time proof of user presence in the login process
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,16 @@
"refreshDelayFactor": {
"title": "label.refresh-delay-factor",
"description": "tooltip.refresh-delay-factor",
"type": "number",
"type": "string",
"widget": {
"id": "number",
"step": 0.01
},
"placeholder": "label.real-number",
"minimum": 0,
"maximum": 0.99,
"default": null
"maximum": 1,
"default": null,
"pattern": "^([0]*(\\.[0-9]+)?|[0]*\\.[0-9]*[1-9][0-9]*)$"
},
"minCacheDuration": {
"title": "label.min-cache-duration",
Expand Down
4 changes: 2 additions & 2 deletions backend/src/test/resources/conf/1044.csv
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
"user1","password1","firstName1","lastName1","ROLE_ADMIN"
"user2","password2","firstName2","lastName2","ROLE_USER"
"user1","password1","firstName1","lastName1","ROLE_ADMIN","user1@example.org"
"user2","password2","firstName2","lastName2","ROLE_USER","user2@example.org"
13 changes: 6 additions & 7 deletions pac4j-module/build.gradle
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
plugins {
id 'java'
id 'groovy'
id 'com.palantir.docker' version '0.20.1'
id 'jacoco'
id 'io.franzbecker.gradle-lombok' version '1.13'
id 'org.springframework.boot' version '2.0.0.RELEASE' apply false
id 'io.spring.dependency-management' version '1.0.6.RELEASE'
}
Expand All @@ -18,11 +17,6 @@ repositories {
}
}

lombok {
version = "1.16.20"
sha256 = "c5178b18caaa1a15e17b99ba5e4023d2de2ebc18b58cde0f5a04ca4b31c10e6d"
}

dependencyManagement {
imports {
mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES
Expand All @@ -39,6 +33,11 @@ dependencies {
exclude group: 'org.opensaml'
}

testCompile project(':backend')
testCompile "org.springframework.boot:spring-boot-starter-test"
testCompile "org.spockframework:spock-core:1.1-groovy-2.4"
testCompile "org.spockframework:spock-spring:1.1-groovy-2.4"

annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"

docker project(':backend')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package net.unicon.shibui.pac4j;

import com.fasterxml.jackson.databind.ObjectMapper;
import edu.internet2.tier.shibboleth.admin.ui.controller.ErrorResponse;
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.EmailService;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.http.entity.ContentType;
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;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Optional;

/**
* @author Bill Smith (wsmith@unicon.net)
*/
public class AddNewUserFilter implements Filter {

private static final Logger logger = LoggerFactory.getLogger(AddNewUserFilter.class);

private static final String ROLE_NONE = "ROLE_NONE";

private UserRepository userRepository;
private RoleRepository roleRepository;
private EmailService emailService;

public AddNewUserFilter(UserRepository userRepository, RoleRepository roleRepository, EmailService emailService) {
this.userRepository = userRepository;
this.roleRepository = roleRepository;
this.emailService = emailService;
}

@Override
public void init(FilterConfig filterConfig) throws ServletException {
}

@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();
if (username != null) {
Optional<User> 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);
try {
emailService.sendNewUserMail(username);
} catch (MessagingException e) {
logger.warn(String.format("Unable to send new user email for user [%s]", username), e);
}
} else {
user = persistedUser.get();
}
if (user.getRole().equals(ROLE_NONE)) {
((HttpServletResponse) response).sendRedirect("/static.html");
} else {
chain.doFilter(request, response); // else, user is in the system already, carry on
}
}
}
}

@Override
public void destroy() {
}

private byte[] getJsonResponseBytes(ErrorResponse eErrorResponse) throws IOException {
String errorResponseJson = new ObjectMapper().writeValueAsString(eErrorResponse);
return errorResponseJson.getBytes();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package net.unicon.shibui.pac4j;

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.core.config.Config;
import org.pac4j.springframework.security.web.CallbackFilter;
import org.pac4j.springframework.security.web.SecurityFilter;
Expand All @@ -17,8 +20,8 @@
@AutoConfigureOrder(-1)
public class WebSecurity {
@Bean("webSecurityConfig")
public WebSecurityConfigurerAdapter webSecurityConfigurerAdapter(final Config config) {
return new Pac4jWebSecurityConfigurerAdapter(config);
public WebSecurityConfigurerAdapter webSecurityConfigurerAdapter(final Config config, UserRepository userRepository, RoleRepository roleRepository, EmailService emailService) {
return new Pac4jWebSecurityConfigurerAdapter(config, userRepository, roleRepository, emailService);
}

@Configuration
Expand All @@ -30,28 +33,51 @@ protected void configure(HttpSecurity http) throws Exception {
}
}

@Configuration
@Order(1)
public static class StaticSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/static.html").authorizeRequests().antMatchers("/static.html").permitAll();
}
}

@Configuration
@Order(2)
public static class ErrorSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/error").authorizeRequests().antMatchers("/error").permitAll();
}
}

@Order(100)
public static class Pac4jWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
private final Config config;
private UserRepository userRepository;
private RoleRepository roleRepository;
private EmailService emailService;

public Pac4jWebSecurityConfigurerAdapter(final Config config) {
public Pac4jWebSecurityConfigurerAdapter(final Config config, UserRepository userRepository, RoleRepository roleRepository, EmailService emailService) {
this.config = config;
this.userRepository = userRepository;
this.roleRepository = roleRepository;
this.emailService = emailService;
}

@Override
protected void configure(HttpSecurity http) throws Exception {
final SecurityFilter securityFilter = new SecurityFilter(this.config, "Saml2Client");

final CallbackFilter callbackFilter = new CallbackFilter(this.config);
// http.regexMatcher("/callback").addFilterBefore(callbackFilter, BasicAuthenticationFilter.class);
http.antMatcher("/**").addFilterBefore(callbackFilter, BasicAuthenticationFilter.class);
http.antMatcher("/**").addFilterBefore(callbackFilter, BasicAuthenticationFilter.class)
.addFilterBefore(securityFilter, BasicAuthenticationFilter.class)
.addFilterAfter(new AddNewUserFilter(userRepository, roleRepository, emailService), SecurityFilter.class);

http.authorizeRequests().anyRequest().fullyAuthenticated();

http.addFilterBefore(securityFilter, BasicAuthenticationFilter.class);
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.ALWAYS);

// http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());

http.csrf().disable();
http.headers().frameOptions().disable();
}
Expand Down
4 changes: 2 additions & 2 deletions pac4j-module/src/test/docker/conf/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ shibui:
keystorePath: "/conf/samlKeystore.jks"
keystorePassword: "changeit"
privateKeyPassword: "changeit"
serviceProviderEntityId: "https://unicon.net/shibui"
serviceProviderEntityId: "https://unicon.net/test/shibui"
serviceProviderMetadataPath: "/conf/sp-metadata.xml"
identityProviderMetadataPath: "/conf/idp-metadata.xml"
forceServiceProviderMetadataGeneration: true
Expand All @@ -19,4 +19,4 @@ shibui:
logging:
level:
org.pac4j: "TRACE"
org.opensaml: "INFO"
org.opensaml: "INFO"
Loading

0 comments on commit 26258f6

Please sign in to comment.