Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/bugfix/nojira-searching-sources'…
Browse files Browse the repository at this point in the history
… into feature/SHIBUI-2052-selenium
  • Loading branch information
Bill Smith committed Sep 2, 2021
2 parents 6eff75f + 8b9f8cb commit 8005135
Show file tree
Hide file tree
Showing 15 changed files with 390 additions and 142 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,8 @@
import org.springframework.security.web.firewall.StrictHttpFirewall;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import java.util.Collections;

import javax.transaction.Transactional;
import java.util.Collections;

/**
* Web security configuration.
Expand All @@ -40,20 +39,29 @@ public class WebSecurityConfig {
@Value("${shibui.roles.authenticated}")
private String[] acceptedAuthenticationRoles;

@Value("${shibui.default-password:}")
private String defaultPassword;

@Value("${shibui.logout-url:/dashboard}")
private String logoutUrl;

@Value("${shibui.default-password:}")
private String defaultPassword;
@Autowired
private RoleRepository roleRepository;

@Value("${shibui.default-rootuser:root}")
private String rootUser;

@Autowired
private UserRepository userRepository;

@Autowired
private UserService userService;

@Autowired
private RoleRepository roleRepository;

@Bean
@Profile("!no-auth")
public AdminUserService adminUserService(UserRepository userRepository) {
return new AdminUserService(userRepository);
}

private HttpFirewall allowUrlEncodedSlashHttpFirewall() {
StrictHttpFirewall firewall = new StrictHttpFirewall();
Expand All @@ -62,8 +70,10 @@ private HttpFirewall allowUrlEncodedSlashHttpFirewall() {
return firewall;
}

private HttpFirewall defaultFirewall() {
return new DefaultHttpFirewall();
@Bean
@Profile("!no-auth")
public AuditorAware<String> defaultAuditorAware() {
return new DefaultAuditorAware();
}

@Bean
Expand Down Expand Up @@ -94,9 +104,9 @@ protected void configure(AuthenticationManagerBuilder auth) throws Exception {
PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
if (defaultPassword != null && !"".equals(defaultPassword)) {
// TODO: yeah, this isn't good, but we gotta initialize this user for now
User adminUser = userRepository.findByUsername("root").orElseGet(() ->{
User adminUser = userRepository.findByUsername(rootUser).orElseGet(() ->{
User u = new User();
u.setUsername("root");
u.setUsername(rootUser);
u.setPassword(defaultPassword);
u.setFirstName("admin");
u.setLastName("user");
Expand Down Expand Up @@ -129,16 +139,8 @@ public void configure(WebSecurity web) throws Exception {
};
}

@Bean
@Profile("!no-auth")
public AuditorAware<String> defaultAuditorAware() {
return new DefaultAuditorAware();
}

@Bean
@Profile("!no-auth")
public AdminUserService adminUserService(UserRepository userRepository) {
return new AdminUserService(userRepository);
private HttpFirewall defaultFirewall() {
return new DefaultHttpFirewall();
}

@Bean
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
package edu.internet2.tier.shibboleth.admin.ui.security.service;

import java.util.*;

import edu.internet2.tier.shibboleth.admin.ui.domain.EntityDescriptor;
import edu.internet2.tier.shibboleth.admin.ui.domain.IActivatable;
import edu.internet2.tier.shibboleth.admin.ui.domain.filters.MetadataFilter;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import edu.internet2.tier.shibboleth.admin.ui.exception.EntityNotFoundException;
import edu.internet2.tier.shibboleth.admin.ui.security.exception.GroupExistsConflictException;
import edu.internet2.tier.shibboleth.admin.ui.security.exception.OwnershipConflictException;
Expand All @@ -23,9 +14,21 @@
import edu.internet2.tier.shibboleth.admin.ui.security.repository.OwnershipRepository;
import edu.internet2.tier.shibboleth.admin.ui.security.repository.RoleRepository;
import edu.internet2.tier.shibboleth.admin.ui.security.repository.UserRepository;
import static edu.internet2.tier.shibboleth.admin.ui.security.service.UserAccess.ADMIN;
import static edu.internet2.tier.shibboleth.admin.ui.security.service.UserAccess.GROUP;
import static edu.internet2.tier.shibboleth.admin.ui.security.service.UserAccess.NONE;
import lombok.NoArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import static edu.internet2.tier.shibboleth.admin.ui.security.service.UserAccess.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;

@Service
@NoArgsConstructor
Expand Down Expand Up @@ -81,7 +84,7 @@ public boolean currentUserIsAdmin() {
public void delete(String username) throws EntityNotFoundException, OwnershipConflictException {
Optional<User> userToRemove = userRepository.findByUsername(username);
if (userToRemove.isEmpty()) throw new EntityNotFoundException("User does not exist");
if (!ownershipRepository.findOwnedByUser(username).isEmpty()) throw new OwnershipConflictException("User ["+username+"] has ownership of entities in the system. Please remove all items before attemtping to delete the user.");
if (!ownershipRepository.findOwnedByUser(username).isEmpty()) throw new OwnershipConflictException("User ["+username+"] has ownership of entities in the system. Please remove all items before attempting to delete the user.");

// ok, user exists and doesn't own anything in the system, so delete them
// If the user is owned by anything, clear that first
Expand All @@ -90,6 +93,10 @@ public void delete(String username) throws EntityNotFoundException, OwnershipCon
userRepository.delete(user);
}

public Optional<User> findByUsername(String username) {
return userRepository.findByUsername(username);
}

public User getCurrentUser() {
//TODO: Consider returning an Optional here
User user = null;
Expand Down Expand Up @@ -187,7 +194,7 @@ public User save(User user) {
if (g == null) {
try {
Group newGroup = ug;
Ownership o = ownershipRepository.saveAndFlush(new Ownership(newGroup, user));
ownershipRepository.saveAndFlush(new Ownership(newGroup, user));
g = groupService.createGroup(newGroup);
}
catch (GroupExistsConflictException e) {
Expand Down Expand Up @@ -219,7 +226,7 @@ public void updateUserRole(User user) {
throw new RuntimeException(String.format("User with username [%s] is defined with role [%s] which does not exist in the system!", user.getUsername(), user.getRole()));
}
} else {
throw new RuntimeException(String.format("User with username [%s] has no role defined and therefor cannot be updated!", user.getUsername()));
throw new RuntimeException(String.format("User with username [%s] has no role defined and therefore cannot be updated!", user.getUsername()));
}
}
}
5 changes: 4 additions & 1 deletion backend/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@ shibui.logout-url=/dashboard

# spring.profiles.active=default

#shibui.default-password=
## Default root user can be set in application.yml or here - setting in both places can be undeterministic
## Default password must be set for the default user to be configured and setup
#shibui.default-password={noop}somepassword
shibui.default-rootuser=root

shibui.metadata-sources-ui-schema-location=classpath:metadata-sources-ui-schema.json
shibui.entity-attributes-filters-ui-schema-location=classpath:entity-attributes-filters-ui-schema.json
Expand Down
4 changes: 4 additions & 0 deletions backend/src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
#shibui:
## Default password must be set for the default user to be configured and setup
# default-rootuser:root
## need to include the encoding for the password - be sure to quote the entire value as shown
# default-password: "{noop}foopassword"
# pac4j-enabled: true
# pac4j:
# keystorePath: "/etc/shibui/samlKeystore.jks"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,69 +1,60 @@
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.exception.GroupExistsConflictException;
import edu.internet2.tier.shibboleth.admin.ui.security.model.Group;
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.security.service.IGroupService;
import edu.internet2.tier.shibboleth.admin.ui.security.service.UserService;
import edu.internet2.tier.shibboleth.admin.ui.service.EmailService;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.pac4j.core.context.JEEContext;
import org.pac4j.core.context.session.JEESessionStore;
import org.pac4j.core.matching.matcher.Matcher;
import org.pac4j.core.profile.CommonProfile;
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;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.Transactional;

import java.io.IOException;
import java.util.List;
import java.util.Optional;

import lombok.extern.slf4j.Slf4j;
import java.util.*;

@Slf4j
public class AddNewUserFilter implements Filter {
private static final String ROLE_NONE = "ROLE_NONE";

private Optional<EmailService> emailService;
private IGroupService groupService;
private Matcher matcher;
private Pac4jConfigurationProperties pac4jConfigurationProperties;
private RoleRepository roleRepository;
private Pac4jConfigurationProperties.SimpleProfileMapping simpleProfileMapping;
private UserRepository userRepository;
private Matcher matcher;
private UserService userService;

public AddNewUserFilter(Pac4jConfigurationProperties pac4jConfigurationProperties, UserRepository userRepository, RoleRepository roleRepository, Matcher matcher, Optional<EmailService> emailService) {
this.userRepository = userRepository;
public AddNewUserFilter(Pac4jConfigurationProperties pac4jConfigurationProperties, UserService userService, RoleRepository roleRepository, Matcher matcher, IGroupService groupService, Optional<EmailService> emailService) {
this.userService = userService;
this.roleRepository = roleRepository;
this.emailService = emailService;
this.pac4jConfigurationProperties = pac4jConfigurationProperties;
this.matcher = matcher;
this.groupService = groupService;
simpleProfileMapping = this.pac4jConfigurationProperties.getSimpleProfileMapping();
}

@Transactional
private User buildAndPersistNewUserFromProfile(CommonProfile profile) {
User buildAndPersistNewUserFromProfile(CommonProfile profile) {
Optional<Role> noRole = roleRepository.findByName(ROLE_NONE);
Role newUserRole;
if (noRole.isEmpty()) {
newUserRole = new Role(ROLE_NONE);
newUserRole = roleRepository.save(newUserRole);
roleRepository.save(newUserRole);
}
newUserRole = noRole.get();

Expand All @@ -74,7 +65,23 @@ private User buildAndPersistNewUserFromProfile(CommonProfile profile) {
user.setFirstName(profile.getFirstName());
user.setLastName(profile.getFamilyName());
user.setEmailAddress(profile.getEmail());
User persistedUser = userRepository.save(user);

// get profile attribute for groups
Object obj = profile.getAttribute(simpleProfileMapping.getGroups());
if (obj != null) {
final ArrayList<String> groupNames = new ArrayList<>();
if (obj instanceof String) {
groupNames.add(obj.toString());
}
if (obj instanceof List) {
((List)obj).forEach(val -> groupNames.add(val.toString()));
}
if (!groupNames.isEmpty()) {
user.setUserGroups(findOrCreateGroups(groupNames));
}
}

User persistedUser = userService.save(user);
if (log.isDebugEnabled()) {
log.debug("Persisted new user:\n" + user);
}
Expand All @@ -97,7 +104,7 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
if (profile != null) {
String username = profile.getUsername();
if (username != null) {
Optional<User> persistedUser = userRepository.findByUsername(username);
Optional<User> persistedUser = userService.findByUsername(username);
User user;
if (persistedUser.isEmpty()) {
user = buildAndPersistNewUserFromProfile(profile);
Expand All @@ -122,7 +129,26 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
}
}

private Set<Group> findOrCreateGroups(ArrayList<String> groupNames) {
final HashSet<Group> result = new HashSet<>();
groupNames.forEach(name -> {
Group g = groupService.find(name);
if (g == null) {
g = new Group();
g.setResourceId(name);
g.setName(name);
try {
groupService.createGroup(g);
}
catch (GroupExistsConflictException shouldntHappen) {
}
}
result.add(g);
});
return result;
}

@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package net.unicon.shibui.pac4j;

import org.pac4j.saml.profile.SAML2Profile;

import net.unicon.shibui.pac4j.Pac4jConfigurationProperties.SimpleProfileMapping;
import org.pac4j.saml.profile.SAML2Profile;

import java.util.Collection;
import java.util.List;

public class BetterSAML2Profile extends SAML2Profile {
private SimpleProfileMapping profileMapping;
Expand All @@ -28,6 +28,10 @@ public String getFirstName() {
return (String) getAttribute(profileMapping.getFirstName());
}

public List<String> getGroups() {
return (List<String>) getAttribute(profileMapping.getGroups());
}

@Override
public String getUsername() {
Object username = getAttribute(profileMapping.getUsername());
Expand All @@ -38,4 +42,4 @@ public String getUsername() {
}
}

}
}
Loading

0 comments on commit 8005135

Please sign in to comment.