Skip to content

Commit

Permalink
test(openshift): add OpenShiftAuthManagerTest
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewazores committed Jul 27, 2021
1 parent 3b8084e commit f06fb0b
Show file tree
Hide file tree
Showing 4 changed files with 346 additions and 34 deletions.
12 changes: 12 additions & 0 deletions pom.xml
Expand Up @@ -201,6 +201,18 @@
<version>${com.github.spotbugs.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-server-mock</artifactId>
<version>${io.fabric8.client.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>openshift-server-mock</artifactId>
<version>${io.fabric8.client.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
9 changes: 8 additions & 1 deletion src/main/java/io/cryostat/net/NetworkModule.java
Expand Up @@ -55,6 +55,8 @@
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoSet;
import io.fabric8.openshift.client.DefaultOpenShiftClient;
import io.fabric8.openshift.client.OpenShiftConfigBuilder;
import io.vertx.core.Vertx;
import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.client.WebClientOptions;
Expand Down Expand Up @@ -159,7 +161,12 @@ static BasicAuthManager provideBasicAuthManager(Logger logger, FileSystem fs) {
@Provides
@Singleton
static OpenShiftAuthManager provideOpenShiftAuthManager(Logger logger, FileSystem fs) {
return new OpenShiftAuthManager(logger, fs);
return new OpenShiftAuthManager(
logger,
fs,
token ->
new DefaultOpenShiftClient(
new OpenShiftConfigBuilder().withOauthToken(token).build()));
}

@Binds
Expand Down
85 changes: 52 additions & 33 deletions src/main/java/io/cryostat/net/OpenShiftAuthManager.java
Expand Up @@ -47,40 +47,42 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import io.cryostat.core.log.Logger;
import io.cryostat.core.sys.FileSystem;
import io.cryostat.net.security.ResourceAction;
import io.cryostat.net.security.ResourceType;
import io.cryostat.net.security.ResourceVerb;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import io.fabric8.kubernetes.api.model.authorization.v1.SelfSubjectAccessReview;
import io.fabric8.kubernetes.api.model.authorization.v1.SelfSubjectAccessReviewBuilder;
import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.KubernetesClientException;
import io.fabric8.openshift.client.DefaultOpenShiftClient;
import io.fabric8.openshift.client.OpenShiftClient;
import io.fabric8.openshift.client.OpenShiftConfigBuilder;
import jdk.jfr.Category;
import jdk.jfr.Event;
import jdk.jfr.Label;
import jdk.jfr.Name;
import org.apache.commons.lang3.StringUtils;

public class OpenShiftAuthManager extends AbstractAuthManager {

private static final String PERMISSION_NOT_REQUIRED = "PERMISSION_NOT_REQUIRED";

private final FileSystem fs;
private final Function<String, OpenShiftClient> clientProvider;

public OpenShiftAuthManager(Logger logger, FileSystem fs) {
OpenShiftAuthManager(
Logger logger, FileSystem fs, Function<String, OpenShiftClient> clientProvider) {
super(logger);
this.fs = fs;
this.clientProvider = clientProvider;
}

@Override
Expand All @@ -96,17 +98,15 @@ public Future<Boolean> validateToken(
return CompletableFuture.completedFuture(false);
}

try (OpenShiftClient authClient =
new DefaultOpenShiftClient(
new OpenShiftConfigBuilder().withOauthToken(token).build())) {
try (OpenShiftClient client = clientProvider.apply(token)) {
List<CompletableFuture<Boolean>> results =
resourceActions
.parallelStream()
.map(
resourceAction -> {
try {
return CompletableFuture.<Boolean>completedFuture(
validateAction(authClient, resourceAction));
validateAction(client, resourceAction));
} catch (IOException | PermissionDeniedException e) {
return CompletableFuture.<Boolean>failedFuture(e);
}
Expand Down Expand Up @@ -142,7 +142,7 @@ public Future<Boolean> validateToken(
}
}

private boolean validateAction(OpenShiftClient authClient, ResourceAction resourceAction)
private boolean validateAction(OpenShiftClient client, ResourceAction resourceAction)
throws IOException, PermissionDeniedException {
AuthRequest evt = new AuthRequest();
evt.begin();
Expand All @@ -167,7 +167,7 @@ private boolean validateAction(OpenShiftClient authClient, ResourceAction resour
.endSpec()
.build();
accessReview =
authClient.authorization().v1().selfSubjectAccessReview().create(accessReview);
client.authorization().v1().selfSubjectAccessReview().create(accessReview);
boolean allowed = accessReview.getStatus().getAllowed();
evt.setRequestSuccessful(true);
if (allowed) {
Expand All @@ -184,25 +184,6 @@ private boolean validateAction(OpenShiftClient authClient, ResourceAction resour
}
}

@Name("io.cryostat.net.OpenShiftAuthManager.AuthRequest")
@Label("AuthRequest")
@Category("Cryostat")
@SuppressFBWarnings(
value = "URF_UNREAD_FIELD",
justification = "Event fields are recorded with JFR instead of accessed directly")
public static class AuthRequest extends Event {

boolean requestSuccessful;

public AuthRequest() {
this.requestSuccessful = false;
}

public void setRequestSuccessful(boolean requestSuccessful) {
this.requestSuccessful = requestSuccessful;
}
}

@Override
public Future<Boolean> validateHttpHeader(
Supplier<String> headerProvider, Set<ResourceAction> resourceActions) {
Expand Down Expand Up @@ -254,7 +235,7 @@ private String getNamespace() throws IOException {
.get();
}

static String map(ResourceType resource) {
private static String map(ResourceType resource) {
switch (resource) {
case TARGET:
return "flightrecorders";
Expand All @@ -270,7 +251,7 @@ static String map(ResourceType resource) {
}
}

static String map(ResourceVerb verb) {
private static String map(ResourceVerb verb) {
switch (verb) {
case CREATE:
return "create";
Expand All @@ -288,12 +269,50 @@ static String map(ResourceVerb verb) {

@SuppressWarnings("serial")
public static class PermissionDeniedException extends Exception {
private final String namespace;
private final String resource;
private final String verb;

public PermissionDeniedException(
String namespace, String group, String resource, String verb, String reason) {
super(
String.format(
"Requesting client in namespace \"%s\" cannot %s %s.%s: %s",
namespace, verb, resource, group, reason));
this.namespace = namespace;
this.resource = resource;
this.verb = verb;
}

public String getNamespace() {
return namespace;
}

public String getResourceType() {
return resource;
}

public String getVerb() {
return verb;
}
}

@Name("io.cryostat.net.OpenShiftAuthManager.AuthRequest")
@Label("AuthRequest")
@Category("Cryostat")
@SuppressFBWarnings(
value = "URF_UNREAD_FIELD",
justification = "Event fields are recorded with JFR instead of accessed directly")
public static class AuthRequest extends Event {

boolean requestSuccessful;

public AuthRequest() {
this.requestSuccessful = false;
}

public void setRequestSuccessful(boolean requestSuccessful) {
this.requestSuccessful = requestSuccessful;
}
}
}

0 comments on commit f06fb0b

Please sign in to comment.