Skip to content

Commit

Permalink
Merge pull request #3336 from ingef/feature/short-cut-admin-ui-login
Browse files Browse the repository at this point in the history
Feature/short cut admin UI login
  • Loading branch information
thoniTUB authored Mar 7, 2024
2 parents 88ba41b + 2459a82 commit 44eec14
Show file tree
Hide file tree
Showing 32 changed files with 265 additions and 178 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import java.util.concurrent.TimeUnit;

import javax.validation.Validator;
import javax.ws.rs.client.Client;

import com.bakdata.conquery.io.cps.CPSTypeIdResolver;
import com.bakdata.conquery.io.jackson.MutableInjectableValues;
Expand All @@ -30,15 +29,13 @@
import com.bakdata.conquery.resources.ResourcesProvider;
import com.bakdata.conquery.resources.admin.AdminServlet;
import com.bakdata.conquery.resources.admin.ShutdownTask;
import com.bakdata.conquery.resources.unprotected.AuthServlet;
import com.bakdata.conquery.tasks.PermissionCleanupTask;
import com.bakdata.conquery.tasks.QueryCleanupTask;
import com.bakdata.conquery.tasks.ReloadMetaStorageTask;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.google.common.base.Throwables;
import io.dropwizard.client.JerseyClientBuilder;
import io.dropwizard.jersey.DropwizardResourceConfig;
import io.dropwizard.lifecycle.Managed;
import io.dropwizard.setup.Environment;
Expand Down Expand Up @@ -68,14 +65,9 @@ public class ManagerNode extends IoHandlerAdapter implements Managed {
private AuthorizationController authController;
private ScheduledExecutorService maintenanceService;
private final List<ResourcesProvider> providers = new ArrayList<>();
private Client client;
@Delegate(excludes = Managed.class)
private Manager manager;

// Resources without authentication
private DropwizardResourceConfig unprotectedAuthApi;
private DropwizardResourceConfig unprotectedAuthAdmin;

// For registering form providers
private FormScanner formScanner;

Expand All @@ -92,9 +84,6 @@ public void run(Manager manager) throws InterruptedException {
ConqueryConfig config = manager.getConfig();
validator = environment.getValidator();

client = new JerseyClientBuilder(environment).using(config.getJerseyClient())
.build(getName());

this.manager = manager;

final ObjectMapper objectMapper = environment.getObjectMapper();
Expand Down Expand Up @@ -124,17 +113,11 @@ public void run(Manager manager) throws InterruptedException {

loadMetaStorage();

authController = new AuthorizationController(getStorage(), config.getAuthorizationRealms());
environment.lifecycle().manage(authController);

unprotectedAuthAdmin = AuthServlet.generalSetup(environment.metrics(), config, environment.admin(), objectMapper);
unprotectedAuthApi = AuthServlet.generalSetup(environment.metrics(), config, environment.servlets(), objectMapper);

// Create AdminServlet first to make it available to the realms
admin = new AdminServlet(this);

authController.externalInit(this, config.getAuthenticationRealms());

authController = new AuthorizationController(getStorage(), config, environment, admin);
environment.lifecycle().manage(authController);

// Register default components for the admin interface
admin.register();
Expand Down Expand Up @@ -289,7 +272,5 @@ public void stop() throws Exception {
log.error("{} could not be closed", getStorage(), e);
}

client.close();

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import java.util.stream.Collectors;

import com.bakdata.conquery.apiv1.auth.ProtoUser;
import com.bakdata.conquery.commands.ManagerNode;
import com.bakdata.conquery.io.storage.MetaStorage;
import com.bakdata.conquery.models.auth.basic.JWTokenHandler;
import com.bakdata.conquery.models.auth.conquerytoken.ConqueryTokenRealm;
Expand All @@ -21,7 +20,11 @@
import com.bakdata.conquery.models.config.auth.AuthenticationRealmFactory;
import com.bakdata.conquery.models.config.auth.AuthorizationConfig;
import com.bakdata.conquery.models.identifiable.ids.specific.UserId;
import com.bakdata.conquery.resources.admin.AdminServlet;
import com.bakdata.conquery.resources.unprotected.AuthServlet;
import io.dropwizard.jersey.DropwizardResourceConfig;
import io.dropwizard.lifecycle.Managed;
import io.dropwizard.setup.Environment;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -49,10 +52,15 @@
public final class AuthorizationController implements Managed{

@NonNull
private final AuthorizationConfig authorizationConfig;
private final ConqueryConfig config;
@NonNull
private final Environment environment;
@NonNull
@Getter
private final MetaStorage storage;
@Getter
private final AdminServlet adminServlet;
@Getter
private final ConqueryTokenRealm conqueryTokenRealm;
@Getter
private final List<ConqueryAuthenticationRealm> authenticationRealms = new ArrayList<>();
Expand All @@ -65,14 +73,33 @@ public final class AuthorizationController implements Managed{

private final DefaultSecurityManager securityManager;

public AuthorizationController(MetaStorage storage, AuthorizationConfig authorizationConfig) {

// Resources without authentication
@Getter
private DropwizardResourceConfig unprotectedAuthApi;
@Getter
private DropwizardResourceConfig unprotectedAuthAdmin;

public AuthorizationController(MetaStorage storage, ConqueryConfig config, Environment environment, AdminServlet adminServlet) {
this.storage = storage;
this.authorizationConfig = authorizationConfig;
this.config = config;
this.environment = environment;
this.adminServlet = adminServlet;

// Create Jersey filter for authentication. The filter is registered here for the api and the but can be used by
// any servlet. In the following configured realms can register TokenExtractors in the filter.
authenticationFilter = DefaultAuthFilter.asDropwizardFeature(storage);
redirectingAuthFilter = new RedirectingAuthFilter(authenticationFilter);

if (adminServlet != null) {
adminServlet.getJerseyConfig().register(authenticationFilter);
adminServlet.getJerseyConfigUI().register(redirectingAuthFilter);
}


unprotectedAuthAdmin = AuthServlet.generalSetup(environment.metrics(), config, environment.admin(), environment.getObjectMapper());
unprotectedAuthApi = AuthServlet.generalSetup(environment.metrics(), config, environment.servlets(), environment.getObjectMapper());


// Add the user token realm
conqueryTokenRealm = new ConqueryTokenRealm(storage);
Expand All @@ -90,18 +117,14 @@ public AuthorizationController(MetaStorage storage, AuthorizationConfig authoriz

registerStaticSecurityManager();

// Register initial users for authorization and authentication (if the realm is able to)
initializeAuthConstellation(authorizationConfig, realms, storage);
}

public void externalInit(ManagerNode manager, List<AuthenticationRealmFactory> authenticationRealmFactories) {
manager.getAdmin().getJerseyConfig().register(authenticationFilter);
manager.getEnvironment().jersey().register(authenticationFilter);

private void externalInit() {


// Init authentication realms provided by the config.
for (AuthenticationRealmFactory authenticationConf : authenticationRealmFactories) {
ConqueryAuthenticationRealm realm = authenticationConf.createRealm(manager);
for (AuthenticationRealmFactory authenticationConf : config.getAuthenticationRealms()) {
ConqueryAuthenticationRealm realm = authenticationConf.createRealm(environment, config, this);
authenticationRealms.add(realm);
realms.add(realm);
}
Expand All @@ -115,6 +138,11 @@ public void externalInit(ManagerNode manager, List<AuthenticationRealmFactory> a
public void start() throws Exception {
// Call Shiros init on all realms
LifecycleUtils.init(realms);

externalInit();

// Register initial users for authorization and authentication (if the realm is able to)
initializeAuthConstellation(config.getAuthorizationRealms(), realms, storage);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package com.bakdata.conquery.models.auth;

import java.net.URI;

import javax.annotation.Nullable;

import com.bakdata.conquery.models.auth.entities.Subject;
import com.bakdata.conquery.models.auth.util.SubjectPrincipalCollection;
import com.bakdata.conquery.models.identifiable.ids.specific.UserId;
Expand Down Expand Up @@ -29,12 +33,25 @@ public class ConqueryAuthenticationInfo implements AuthenticationInfo {
/**
* A realm can indicate whether a logout button is shown for the user or not
*/
private final boolean displayLogout;
private final boolean displayLogout;

/**
* An uri a user can be redirected to perform an external logout.
*/
@Nullable
private final URI frontChannelLogout;

public ConqueryAuthenticationInfo(Subject subject, Object credentials, ConqueryAuthenticationRealm realm, boolean displayLogout) {
public ConqueryAuthenticationInfo(
Subject subject,
Object credentials,
ConqueryAuthenticationRealm realm,
boolean displayLogout,
@Nullable URI frontChannelLogout
) {
this.credentials = credentials;
this.displayLogout = displayLogout;
principals = new SubjectPrincipalCollection(subject, realm);
this.frontChannelLogout = frontChannelLogout;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public ConqueryAuthenticationInfo doGetAuthenticationInfo(AuthenticationToken to

final User user = getUserOrThrowUnknownAccount(storage, userId);

return new ConqueryAuthenticationInfo(user, token, this, true);
return new ConqueryAuthenticationInfo(user, token, this, true, null);
}


Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.bakdata.conquery.models.auth.develop;

import com.bakdata.conquery.io.storage.MetaStorage;
import com.bakdata.conquery.models.auth.entities.User;
import com.bakdata.conquery.models.config.auth.AuthorizationConfig;
import com.bakdata.conquery.models.auth.ConqueryAuthenticationInfo;
import com.bakdata.conquery.models.auth.ConqueryAuthenticationRealm;
import com.bakdata.conquery.models.auth.entities.User;
import com.bakdata.conquery.models.auth.util.SkippingCredentialsMatcher;
import com.bakdata.conquery.models.config.auth.AuthorizationConfig;
import com.bakdata.conquery.models.identifiable.ids.specific.UserId;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
Expand Down Expand Up @@ -60,6 +60,6 @@ public ConqueryAuthenticationInfo doGetAuthenticationInfo(AuthenticationToken to
}
DevelopmentToken devToken = (DevelopmentToken) token;
final User user = getUserOrThrowUnknownAccount(storage, devToken.getPrincipal());
return new ConqueryAuthenticationInfo(user, devToken.getCredentials(), this, true);
return new ConqueryAuthenticationInfo(user, devToken.getCredentials(), this, true, null);
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package com.bakdata.conquery.models.auth.develop;

import com.bakdata.conquery.commands.ManagerNode;
import com.bakdata.conquery.io.cps.CPSType;
import com.bakdata.conquery.models.auth.AuthorizationController;
import com.bakdata.conquery.models.auth.ConqueryAuthenticationRealm;
import com.bakdata.conquery.models.auth.entities.User;
import com.bakdata.conquery.models.config.ConqueryConfig;
import com.bakdata.conquery.models.config.auth.AuthenticationRealmFactory;
import com.bakdata.conquery.models.config.auth.AuthenticationRealmFactory;
import io.dropwizard.setup.Environment;

/**
* Default configuration for the auth system. Sets up all other default components.
Expand All @@ -15,15 +16,15 @@
public class DevAuthConfig implements AuthenticationRealmFactory {

@Override
public ConqueryAuthenticationRealm createRealm(ManagerNode managerNode) {
User defaultUser = managerNode.getConfig()
public ConqueryAuthenticationRealm createRealm(Environment environment, ConqueryConfig config, AuthorizationController authorizationController) {
User defaultUser = config
.getAuthorizationRealms()
.getInitialUsers()
.get(0)
.createOrOverwriteUser(managerNode.getStorage());
.createOrOverwriteUser(authorizationController.getStorage());

managerNode.getAuthController().getAuthenticationFilter().registerTokenExtractor(new UserIdTokenExtractor(defaultUser));
authorizationController.getAuthenticationFilter().registerTokenExtractor(new UserIdTokenExtractor(defaultUser));

return new DefaultInitialUserRealm(managerNode.getStorage());
return new DefaultInitialUserRealm(authorizationController.getStorage());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import java.util.List;
import java.util.concurrent.Callable;

import com.bakdata.conquery.models.identifiable.ids.specific.PermissionOwnerId;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
package com.bakdata.conquery.models.auth.entities;

import java.security.Principal;
import java.util.Collection;
import java.util.List;
import java.util.Set;

import com.bakdata.conquery.models.auth.ConqueryAuthenticationInfo;
import com.bakdata.conquery.models.auth.permissions.Ability;
import com.bakdata.conquery.models.auth.permissions.Authorized;
import com.bakdata.conquery.models.auth.permissions.ConqueryPermission;
import com.bakdata.conquery.models.identifiable.ids.specific.UserId;
import lombok.NonNull;

import java.security.Principal;
import java.util.Collection;
import java.util.List;
import java.util.Set;

/**
* An interface for classes that facade a user or represent a user.
*
Expand All @@ -36,6 +35,8 @@ public interface Subject extends Principal {

boolean isDisplayLogout();

ConqueryAuthenticationInfo getAuthenticationInfo();

void setAuthenticationInfo(ConqueryAuthenticationInfo info);

User getUser();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,13 @@ public void setAuthenticationInfo(ConqueryAuthenticationInfo info) {
shiroUserAdapter.getAuthenticationInfo().set(info);
}


@JsonIgnore
@Override
public ConqueryAuthenticationInfo getAuthenticationInfo() {
return shiroUserAdapter.getAuthenticationInfo().get();
}

@Override
@JsonIgnore
public User getUser() {
Expand All @@ -169,7 +176,7 @@ public class ShiroUserAdapter extends FilteredUser {

@Getter
private final ThreadLocal<ConqueryAuthenticationInfo> authenticationInfo =
ThreadLocal.withInitial(() -> new ConqueryAuthenticationInfo(User.this, null, null, false));
ThreadLocal.withInitial(() -> new ConqueryAuthenticationInfo(User.this, null, null, false, null));

@Override
public void checkPermission(Permission permission) throws AuthorizationException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ public ConqueryAuthenticationInfo doGetAuthenticationInfo(AuthenticationToken to

final User user = storage.getUser(userId);

return new ConqueryAuthenticationInfo(user, token, this, true);
final String logoutEndpoint = authProviderConf.getAuthClient(true).getServerConfiguration().getLogoutEndpoint();
return new ConqueryAuthenticationInfo(user, token, this, true, URI.create(logoutEndpoint));
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public ConqueryAuthenticationInfo doGetAuthenticationInfo(AuthenticationToken to
User user = storage.getUser(userId);
if (user != null) {
log.trace("Successfully authenticated user {}", userId);
return new ConqueryAuthenticationInfo(user, token, this, true);
return new ConqueryAuthenticationInfo(user, token, this, true, idpConfiguration.logoutEndpoint());
}

// Try alternative ids
Expand All @@ -125,7 +125,7 @@ public ConqueryAuthenticationInfo doGetAuthenticationInfo(AuthenticationToken to
user = storage.getUser(userId);
if (user != null) {
log.trace("Successfully mapped subject {} using user id {}", subject, userId);
return new ConqueryAuthenticationInfo(user, token, this, true);
return new ConqueryAuthenticationInfo(user, token, this, true, idpConfiguration.logoutEndpoint());
}
}

Expand Down
Loading

0 comments on commit 44eec14

Please sign in to comment.