Commit 55ddb6f0 authored by Gradl, Tobias's avatar Gradl, Tobias
Browse files

2: Migrate core behavior to new base

Task-Url: #2
parent 6a7cf6f8
Pipeline #17547 passed with stage
in 2 minutes and 4 seconds
......@@ -40,6 +40,7 @@ subprojects {
apply plugin: 'io.spring.dependency-management'
apply plugin: 'java'
apply plugin: 'maven-publish'
apply plugin: 'eclipse'
publishing {
publications {
......
......@@ -4,20 +4,22 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.pac4j.core.context.WebContext;
import org.pac4j.core.credentials.Credentials;
import org.pac4j.core.profile.UserProfile;
import org.pac4j.core.profile.creator.ProfileCreator;
import eu.dariah.de.dariahsp.config.model.RoleMapping;
import eu.dariah.de.dariahsp.model.ExtendedUserProfile;
import eu.dariah.de.dariahsp.model.config.RoleDefinition;
import lombok.Data;
@Data
public class UserProfileCreator<C extends Credentials> implements ProfileCreator<C> {
private static final String ROLE_PREFIX = "ROLE_";
private final String clientName;
private List<RoleMapping> roleMappings;
private List<RoleDefinition> roleDefinitions;
@Override
public Optional<UserProfile> create(final C credentials, final WebContext context) {
......@@ -25,8 +27,18 @@ public class UserProfileCreator<C extends Credentials> implements ProfileCreator
return Optional.empty();
}
ExtendedUserProfile profile = new ExtendedUserProfile(credentials.getUserProfile());
Set<RoleDefinition> mappedDefinitions;
if (this.canMapRoles(profile)) {
profile.setRoles(this.getMappedRoles(profile));
// Determine applicable role definitions
mappedDefinitions = this.getMappedRoles(profile);
// Set applicable roles as Strings
profile.setRoles(mappedDefinitions.stream()
.map(mr -> ROLE_PREFIX + mr.getRole().toUpperCase())
.collect(Collectors.toSet()));
// Set maximum applicable level
profile.setLevel(mappedDefinitions.stream()
.mapToInt(RoleDefinition::getLevel)
.max().orElse(0));
}
return Optional.ofNullable(profile);
}
......@@ -34,19 +46,21 @@ public class UserProfileCreator<C extends Credentials> implements ProfileCreator
private boolean canMapRoles(ExtendedUserProfile profile) {
return clientName!=null &&
profile.getExternalRoles()!=null && !profile.getExternalRoles().isEmpty() &&
roleMappings!=null && !roleMappings.isEmpty();
roleDefinitions!=null && !roleDefinitions.isEmpty();
}
private Set<String> getMappedRoles(ExtendedUserProfile profile) {
Set<String> roles = new LinkedHashSet<>();
for (RoleMapping rm : roleMappings) {
private Set<RoleDefinition> getMappedRoles(ExtendedUserProfile profile) {
Set<RoleDefinition> roles = new LinkedHashSet<>();
for (RoleDefinition rm : roleDefinitions) {
for (String client : rm.getMappings().keySet()) {
if (!client.equals(clientName)) {
continue;
}
for (String extRole : profile.getExternalRoles()) {
if (!extRole.trim().isEmpty() && rm.getMappings().get(client).contains(extRole.trim())) {
roles.add(ROLE_PREFIX + rm.getRole().toUpperCase());
if (!extRole.trim().isEmpty() &&
rm.getMappings().get(client).contains(extRole.trim()) &&
!roles.contains(rm)) {
roles.add(rm);
}
}
}
......
package eu.dariah.de.dariahsp.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import eu.dariah.de.dariahsp.web.AuthInfoHandlerInterceptor;
import eu.dariah.de.dariahsp.web.AuthInfoHelper;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class DefaultWebMvcConfigurer implements WebMvcConfigurer {
@Autowired private AuthInfoHelper authInfoHelper;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInfoHandlerInterceptor());
log.info("AuthInfoHandlerInterceptor has been registered");
}
private AuthInfoHandlerInterceptor authInfoHandlerInterceptor() {
AuthInfoHandlerInterceptor i = new AuthInfoHandlerInterceptor();
i.setAuthInfoHelper(authInfoHelper);
return i;
}
}
......@@ -33,8 +33,9 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import eu.dariah.de.dariahsp.CustomAuthorizer;
import eu.dariah.de.dariahsp.authenticator.LocalUsernamePasswordAuthenticator;
import eu.dariah.de.dariahsp.authenticator.UserProfileCreator;
import eu.dariah.de.dariahsp.config.model.RoleMapping;
import eu.dariah.de.dariahsp.metadata.MetadataHelper;
import eu.dariah.de.dariahsp.model.config.RoleDefinition;
import eu.dariah.de.dariahsp.web.AuthInfoHelper;
import lombok.Data;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
......@@ -51,7 +52,7 @@ public class SecurityConfig {
@Getter private String salt;
@Getter private String roleHierarchy;
@Getter private final List<RoleMapping> roleMappings;
@Getter private final List<RoleDefinition> roleDefinitions;
@Bean
public Optional<LocalUsernamePasswordAuthenticator> localUsernamePasswordAuthenticator() {
......@@ -64,6 +65,11 @@ public class SecurityConfig {
return Optional.of(localAuthenticator);
}
@Bean
public AuthInfoHelper authInfoHelper() {
return new AuthInfoHelper();
}
@Bean
public BaseUrl baseUrl() {
return new BaseUrl(saml.getSp().getBaseUrl());
......@@ -107,7 +113,6 @@ public class SecurityConfig {
config.addAuthorizer("custom", new CustomAuthorizer());
//config.addMatcher("excludedPath", new PathMatcher().excludeRegex("^/*$"));
return config;
}
......@@ -171,13 +176,13 @@ public class SecurityConfig {
private UserProfileCreator<SAML2Credentials> saml2ProfileCreator() {
UserProfileCreator<SAML2Credentials> saml2ProfileCreator = new UserProfileCreator<>(saml.getAuthorizerName());
saml2ProfileCreator.setRoleMappings(roleMappings);
saml2ProfileCreator.setRoleDefinitions(roleDefinitions);
return saml2ProfileCreator;
}
private UserProfileCreator<UsernamePasswordCredentials> localProfileCreator() {
UserProfileCreator<UsernamePasswordCredentials> localProfileCreator = new UserProfileCreator<>(local.getAuthorizerName());
localProfileCreator.setRoleMappings(roleMappings);
localProfileCreator.setRoleDefinitions(roleDefinitions);
return localProfileCreator;
}
}
......@@ -15,6 +15,7 @@ import lombok.ToString;
@EqualsAndHashCode(callSuper=true)
public class ExtendedUserProfile extends CommonProfile {
private Set<String> externalRoles;
private int level;
public ExtendedUserProfile(CommonProfile profile) {
this.setId(profile.getId());
......@@ -41,7 +42,9 @@ public class ExtendedUserProfile extends CommonProfile {
@Override
public String toString() {
return super.toString();
return CommonHelper.toNiceString(this.getClass(), "id", this.getId(), "level", this.getLevel(),
"attributes", this.getAttributes(), "roles", this.getRoles(), "externalRoles", this.getExternalRoles(),
"isRemembered", this.isRemembered(), "clientName", this.getClientName());
}
}
package eu.dariah.de.dariahsp.config.model;
package eu.dariah.de.dariahsp.model.config;
import java.util.Map;
import java.util.Set;
......@@ -6,7 +6,8 @@ import java.util.Set;
import lombok.Data;
@Data
public class RoleMapping {
public class RoleDefinition {
private String role;
private int level;
private Map<String,Set<String>> mappings;
}
package eu.dariah.de.dariahsp.model.web;
import java.util.Set;
import lombok.Data;
@Data
public class AuthPojo {
private boolean auth;
private String userId;
private String sessionId;
private int level;
private String displayName;
private String language;
private Set<String> roles;
}
package eu.dariah.de.dariahsp.web;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.springframework.web.servlet.support.RequestContextUtils;
import eu.dariah.de.dariahsp.model.web.AuthPojo;
public class AuthInfoHandlerInterceptor extends HandlerInterceptorAdapter {
private AuthInfoHelper authInfoHelper;
public AuthInfoHelper getAuthInfoHelper() { return authInfoHelper; }
public void setAuthInfoHelper(AuthInfoHelper authInfoHelper) { this.authInfoHelper = authInfoHelper; }
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
if (modelAndView==null) {
return;
}
AuthPojo auth = authInfoHelper.getAuth();
if (auth!=null && auth.isAuth()) {
modelAndView.addObject("_auth", auth);
setUserLocale(request, response, auth.getLanguage());
}
}
private void setUserLocale(final HttpServletRequest request, final HttpServletResponse response, String localeString) {
if (localeString != null && !localeString.isEmpty()) {
LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
if (localeResolver == null) {
throw new IllegalStateException("No LocaleResolver found: not in a DispatcherServlet request?");
}
localeResolver.setLocale(request, response, StringUtils.parseLocaleString(localeString));
}
}
}
\ No newline at end of file
package eu.dariah.de.dariahsp.web;
import java.util.List;
import org.pac4j.core.context.JEEContext;
import org.pac4j.core.profile.ProfileManager;
import org.springframework.beans.factory.annotation.Autowired;
import eu.dariah.de.dariahsp.model.ExtendedUserProfile;
import eu.dariah.de.dariahsp.model.web.AuthPojo;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class AuthInfoHelper {
@Autowired private JEEContext jeeContext;
@Autowired private ProfileManager<ExtendedUserProfile> profileManager;
public AuthPojo getAuth() {
return this.getCurrentUserDetails();
}
public String getUserId() {
AuthPojo user = getCurrentUserDetails();
if (user!=null) {
return user.getUserId();
} else {
return "";
}
}
public AuthPojo getCurrentUserDetails() {
List<ExtendedUserProfile> profiles = profileManager.getAll(true);
if (profiles==null || profiles.isEmpty()) {
return new AuthPojo();
}
if (profiles.size()>1) {
log.warn("Multiple user profiles available for the session => using first");
}
return getFromExtendedUserProfile(profiles.get(0));
}
private AuthPojo getFromExtendedUserProfile(ExtendedUserProfile profile) {
AuthPojo pojo = null;
if (profile != null) {
pojo = new AuthPojo();
pojo.setAuth(!profile.isExpired());
pojo.setDisplayName(profile.getDisplayName());
pojo.setRoles(profile.getRoles());
pojo.setLevel(profile.getLevel());
pojo.setUserId(profile.getId());
pojo.setSessionId((jeeContext.getSessionStore()).getOrCreateSessionId(jeeContext));
}
return pojo;
}
}
......@@ -3,16 +3,19 @@
auth:
salt: Qmwp4CO7LDkOUDouAcCcUqd9ZGNbRG5Jyr5lpntOuB9
rolehierarchy: ROLE_ADMINISTRATOR > ROLE_CONTRIBUTOR > ROLE_USER
rolemappings:
roleDefinitions:
- role: ADMINISTRATOR
level: 100
mappings:
local: ["application_admin"]
saml2: ["application_admin"]
- role: CONTRIBUTOR
level: 50
mappings:
local: ["application_contributor"]
saml2: ["application_contributor"]
- role: USER
level: 10
mappings:
local: ["application_user"]
saml2: ["application_user"]
......
......@@ -2,11 +2,12 @@ package eu.dariah.de.dariahsp.sample.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import eu.dariah.de.dariahsp.config.DefaultWebMvcConfigurer;
import eu.dariah.de.dariahsp.config.SecurityConfig;
@Configuration
@Import({SecurityConfig.class})
@Import({SecurityConfig.class, DefaultWebMvcConfigurer.class})
public class SampleConfig {
}
......@@ -28,6 +28,8 @@ import eu.dariah.de.dariahsp.error.AuthenticatorNotAvailable;
import eu.dariah.de.dariahsp.error.NotFoundException;
import eu.dariah.de.dariahsp.error.SAML2MetadataNotFoundException;
import eu.dariah.de.dariahsp.metadata.MetadataHelper;
import eu.dariah.de.dariahsp.model.ExtendedUserProfile;
import eu.dariah.de.dariahsp.web.AuthInfoHelper;
@Controller
public class SampleController {
......@@ -41,14 +43,14 @@ public class SampleController {
@Autowired private SecurityConfig securityConfig;
@Autowired private Config config;
@Autowired private JEEContext jeeContext;
@Autowired private ProfileManager profileManager;
@Autowired private ProfileManager<ExtendedUserProfile> profileManager;
@Autowired private AuthInfoHelper authInfoHelper;
@Autowired private MetadataHelper metadataHelper;
@GetMapping("/")
public String greeting(@RequestParam(name="name", required=false, defaultValue="World") String name, Map<String, Object> map) {
map.put("name", name);
map.put(PROFILES, profileManager.getAll(true));
map.put(SESSION_ID, jeeContext.getSessionStore().getOrCreateSessionId(jeeContext));
return "home";
}
......
......@@ -11,16 +11,19 @@ logging:
auth:
salt: Qmwp4CO7LDkOUDouAcCcUqd9ZGNbRG5Jyr5lpntOuB9
rolehierarchy: ROLE_ADMINISTRATOR > ROLE_CONTRIBUTOR > ROLE_USER
rolemappings:
roleDefinitions:
- role: ADMINISTRATOR
level: 100
mappings:
local: ["application_admin"]
saml2: ["application_admin"]
- role: CONTRIBUTOR
level: 50
mappings:
local: ["application_contributor"]
saml2: ["application_contributor"]
- role: USER
level: 10
mappings:
local: ["application_user"]
saml2: ["application_user"]
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment