add user profile refresh after changing effective user id
This commit is contained in:
parent
be8f6ef4b3
commit
4d844e4347
10 changed files with 127 additions and 33 deletions
|
@ -1,3 +1,3 @@
|
|||
group = org.xbib
|
||||
name = net-http
|
||||
version = 4.7.1
|
||||
version = 4.8.0
|
||||
|
|
|
@ -3,6 +3,8 @@ package org.xbib.net.http.server.application;
|
|||
import java.nio.file.Path;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.xbib.net.http.server.domain.HttpSecurityDomain;
|
||||
import org.xbib.net.http.server.executor.Executor;
|
||||
import org.xbib.net.http.server.route.HttpRouter;
|
||||
import org.xbib.net.mime.MimeTypeService;
|
||||
|
@ -15,6 +17,8 @@ public interface ApplicationBuilder {
|
|||
|
||||
ApplicationBuilder setSecret(String hexSecret);
|
||||
|
||||
ApplicationBuilder setSecurityDomain(HttpSecurityDomain securityDomain);
|
||||
|
||||
ApplicationBuilder setSessionsEnabled(boolean sessionsEnabled);
|
||||
|
||||
ApplicationBuilder setLocale(Locale locale);
|
||||
|
|
|
@ -246,8 +246,10 @@ public class BaseApplication implements Application {
|
|||
);
|
||||
}
|
||||
|
||||
protected Collection<HttpHandler> newPersistHandlers(Codec<UserProfile> userProfileCodec, Codec<Session> sessionCodec) {
|
||||
return List.of(new PersistSessionHandler(sessionCodec), new PersistUserProfileHandler(userProfileCodec));
|
||||
protected Collection<HttpHandler> newPersistHandlers(Codec<UserProfile> userProfileCodec,
|
||||
Codec<Session> sessionCodec) {
|
||||
return List.of(new PersistSessionHandler(sessionCodec),
|
||||
new PersistUserProfileHandler(userProfileCodec, builder.securityDomain));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -7,6 +7,7 @@ import java.util.Locale;
|
|||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.xbib.net.http.server.domain.HttpSecurityDomain;
|
||||
import org.xbib.net.http.server.executor.BaseExecutor;
|
||||
import org.xbib.net.http.server.executor.Executor;
|
||||
import org.xbib.net.http.server.route.HttpRouter;
|
||||
|
@ -32,6 +33,8 @@ public class BaseApplicationBuilder implements ApplicationBuilder {
|
|||
|
||||
protected String secret;
|
||||
|
||||
protected HttpSecurityDomain securityDomain;
|
||||
|
||||
protected boolean sessionsEnabled;
|
||||
|
||||
protected Locale locale;
|
||||
|
@ -87,6 +90,12 @@ public class BaseApplicationBuilder implements ApplicationBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApplicationBuilder setSecurityDomain(HttpSecurityDomain securityDomain) {
|
||||
this.securityDomain = securityDomain;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApplicationBuilder setSessionsEnabled(boolean sessionsEnabled) {
|
||||
this.sessionsEnabled = sessionsEnabled;
|
||||
|
|
|
@ -26,12 +26,15 @@ public class BaseUserProfile implements UserProfile {
|
|||
|
||||
private Collection<String> effectivePermissions;
|
||||
|
||||
private boolean refresh;
|
||||
|
||||
public BaseUserProfile() {
|
||||
this.attributes = new BaseAttributes();
|
||||
this.roles = new ArrayList<>();
|
||||
this.effectiveRoles = new ArrayList<>();
|
||||
this.permissions = new ArrayList<>();
|
||||
this.effectivePermissions = new ArrayList<>();
|
||||
this.refresh = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -134,6 +137,16 @@ public class BaseUserProfile implements UserProfile {
|
|||
attributes.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void triggerRefresh(boolean refresh) {
|
||||
this.refresh = refresh;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRefreshTriggered() {
|
||||
return refresh;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Attributes getAttributes() {
|
||||
return attributes;
|
||||
|
@ -197,24 +210,22 @@ public class BaseUserProfile implements UserProfile {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static UserProfile fromMap(UserProfile userProfile, Map<String, Object> map) {
|
||||
if (userProfile.getName() == null && map.containsKey(NAME)) {
|
||||
if (map.containsKey(NAME)) {
|
||||
userProfile.setName((String) map.get(NAME));
|
||||
}
|
||||
if (userProfile.getUserId() == null && map.containsKey(USER_ID)) {
|
||||
String userId = (String) map.get(USER_ID);
|
||||
userProfile.setUserId(userId);
|
||||
if (map.containsKey(USER_ID)) {
|
||||
userProfile.setUserId((String) map.get(USER_ID));
|
||||
}
|
||||
if (map.containsKey(EFFECTIVE_USER_ID)) {
|
||||
String eUserId = (String) map.get(EFFECTIVE_USER_ID);
|
||||
userProfile.setEffectiveUserId(eUserId);
|
||||
userProfile.setEffectiveUserId((String) map.get(EFFECTIVE_USER_ID));
|
||||
}
|
||||
if ((userProfile.getRoles() == null || userProfile.getRoles().isEmpty()) && map.containsKey(ROLES)) {
|
||||
if (map.containsKey(ROLES)) {
|
||||
userProfile.setRoles((Collection<String>) map.get(ROLES));
|
||||
}
|
||||
if (map.containsKey(EFFECTIVE_ROLES)) {
|
||||
userProfile.setEffectiveRoles((Collection<String>) map.get(EFFECTIVE_ROLES));
|
||||
}
|
||||
if ((userProfile.getPermissions() == null || userProfile.getPermissions().isEmpty()) && map.containsKey(PERMISSIONS)) {
|
||||
if (map.containsKey(PERMISSIONS)) {
|
||||
userProfile.setPermissions((Collection<String>) map.get(PERMISSIONS));
|
||||
}
|
||||
if (map.containsKey(EFFECTIVE_PERMISSIONS)) {
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package org.xbib.net.http.server.auth;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
@ -54,6 +56,20 @@ public class LoginAuthenticationHandler implements HttpHandler {
|
|||
logger.log(Level.FINE, "no user profile found in context");
|
||||
return;
|
||||
}
|
||||
if (userProfile.isRefreshTriggered()) {
|
||||
try {
|
||||
List<String> roles = new ArrayList<>();
|
||||
userProfile.setRoles(roles);
|
||||
List<String> effectiveRoles = new ArrayList<>();
|
||||
userProfile.setEffectiveRoles(effectiveRoles);
|
||||
loadRoles(userProfile);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, e.getMessage(), e);
|
||||
} finally {
|
||||
userProfile.triggerRefresh(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (userProfile.getUserId() != null) {
|
||||
logger.log(Level.FINE, "user id already set");
|
||||
return;
|
||||
|
@ -102,7 +118,15 @@ public class LoginAuthenticationHandler implements HttpHandler {
|
|||
} else {
|
||||
userProfile.setEffectiveUserId(authContext.getUsername());
|
||||
}
|
||||
GroupsProvider.Context groupContext = new GroupsProvider.Context(authContext.getUsername(), null);
|
||||
loadRoles(userProfile);
|
||||
return true;
|
||||
}
|
||||
logger.log(Level.FINE, "authentication failure for user " + username);
|
||||
return false;
|
||||
}
|
||||
|
||||
private void loadRoles(UserProfile userProfile) {
|
||||
GroupsProvider.Context groupContext = new GroupsProvider.Context(userProfile.getUserId(), null);
|
||||
Collection<String> groups = securityRealm.getGroupsProvider().getGroups(groupContext);
|
||||
for (String group : groups) {
|
||||
userProfile.addRole(group);
|
||||
|
@ -117,11 +141,5 @@ public class LoginAuthenticationHandler implements HttpHandler {
|
|||
userProfile.addEffectiveRole(group);
|
||||
}
|
||||
}
|
||||
// TODO permissions and effective permissions
|
||||
logger.log(Level.FINE, "user and role setup completed for " + username);
|
||||
return true;
|
||||
}
|
||||
logger.log(Level.FINE, "authentication failure for user " + username);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,19 @@
|
|||
package org.xbib.net.http.server.auth;
|
||||
|
||||
import org.xbib.net.GroupsProvider;
|
||||
import org.xbib.net.SecurityRealm;
|
||||
import org.xbib.net.UserProfile;
|
||||
import org.xbib.net.http.HttpResponseStatus;
|
||||
import org.xbib.net.http.server.HttpException;
|
||||
import org.xbib.net.http.server.HttpHandler;
|
||||
import org.xbib.net.http.server.domain.HttpSecurityDomain;
|
||||
import org.xbib.net.http.server.persist.Codec;
|
||||
import org.xbib.net.http.server.route.HttpRouterContext;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
@ -17,16 +23,42 @@ public class PersistUserProfileHandler implements HttpHandler {
|
|||
|
||||
private final Codec<UserProfile> userProfileCodec;
|
||||
|
||||
public PersistUserProfileHandler(Codec<UserProfile> userProfileCodec) {
|
||||
private final HttpSecurityDomain securityDomain;
|
||||
|
||||
public PersistUserProfileHandler(Codec<UserProfile> userProfileCodec,
|
||||
HttpSecurityDomain securityDomain) {
|
||||
this.userProfileCodec = userProfileCodec;
|
||||
this.securityDomain = securityDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(HttpRouterContext context) throws IOException {
|
||||
UserProfile userProfile = context.getAttributes().get(UserProfile.class, "userprofile");
|
||||
if (userProfile != null && userProfile.getUserId() != null) {
|
||||
if (userProfile.isRefreshTriggered()) {
|
||||
if (securityDomain == null) {
|
||||
logger.log(Level.FINE, "unable to refresh, security domain is null");
|
||||
return;
|
||||
}
|
||||
if (securityDomain.getRealm() == null) {
|
||||
logger.log(Level.FINE, "unable to refresh, security realm is null");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
logger.log(Level.FINEST, "writing user profile id " + userProfile.getUserId());
|
||||
// reset roles and load again
|
||||
List<String> roles = new ArrayList<>();
|
||||
userProfile.setRoles(roles);
|
||||
List<String> effectiveRoles = new ArrayList<>();
|
||||
userProfile.setEffectiveRoles(effectiveRoles);
|
||||
loadRoles(userProfile, securityDomain.getRealm());
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, e.getMessage(), e);
|
||||
} finally {
|
||||
userProfile.triggerRefresh(false);
|
||||
}
|
||||
}
|
||||
try {
|
||||
logger.log(Level.FINEST, "writing user profile id = " + userProfile.getUserId());
|
||||
userProfileCodec.write(userProfile.getUserId(), userProfile);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, e.getMessage(), e);
|
||||
|
@ -37,4 +69,23 @@ public class PersistUserProfileHandler implements HttpHandler {
|
|||
(userProfile != null ? userProfile.getUserId() : null));
|
||||
}
|
||||
}
|
||||
|
||||
private void loadRoles(UserProfile userProfile, SecurityRealm securityRealm) {
|
||||
String username = userProfile.getUserId();
|
||||
GroupsProvider.Context groupContext = new GroupsProvider.Context(username, null);
|
||||
Collection<String> groups = securityRealm.getGroupsProvider().getGroups(groupContext);
|
||||
for (String group : groups) {
|
||||
userProfile.addRole(group);
|
||||
}
|
||||
if (!userProfile.getUserId().equals(userProfile.getEffectiveUserId())) {
|
||||
GroupsProvider.Context effectiveGroupContext = new GroupsProvider.Context(userProfile.getEffectiveUserId(), null);
|
||||
for (String group : securityRealm.getGroupsProvider().getGroups(effectiveGroupContext)) {
|
||||
userProfile.addEffectiveRole(group);
|
||||
}
|
||||
} else {
|
||||
for (String group : groups) {
|
||||
userProfile.addEffectiveRole(group);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.xbib.net.http.server.domain;
|
|||
|
||||
import java.util.List;
|
||||
import org.xbib.net.SecurityDomain;
|
||||
import org.xbib.net.UserProfile;
|
||||
import org.xbib.net.http.server.HttpHandler;
|
||||
|
||||
public interface HttpSecurityDomain extends SecurityDomain {
|
||||
|
|
|
@ -105,12 +105,10 @@ public class IncomingContextHandler implements HttpHandler {
|
|||
logger.log(Level.FINE, "new session created, id = " + session.id());
|
||||
}
|
||||
}
|
||||
// important
|
||||
context.getAttributes().put("session", session);
|
||||
if (userProfile == null) {
|
||||
userProfile = recoverUserProfile(context, session, payload);
|
||||
}
|
||||
// important
|
||||
context.getAttributes().put("userprofile", userProfile);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ dependencyResolutionManagement {
|
|||
version('netty', '4.1.110.Final')
|
||||
version('netty-tcnative', '2.0.65.Final')
|
||||
version('datastructures', '5.1.0')
|
||||
version('net', '4.7.0')
|
||||
version('net', '4.8.0')
|
||||
library('netty-codec-http2', 'io.netty', 'netty-codec-http2').versionRef('netty')
|
||||
library('netty-handler', 'io.netty', 'netty-handler').versionRef('netty')
|
||||
library('netty-handler-proxy', 'io.netty', 'netty-handler-proxy').versionRef('netty')
|
||||
|
|
Loading…
Reference in a new issue