Skip to content

Commit

Permalink
Merge pull request #2092 from HubSpot/groups_scopes_rework
Browse files Browse the repository at this point in the history
Rework auth to include scopes as well as groups
  • Loading branch information
ssalinas authored Jun 4, 2020
2 parents 80bd62d + 8f698fd commit 10eb704
Show file tree
Hide file tree
Showing 51 changed files with 1,797 additions and 340 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
public enum SingularityAuthorizationScope {
READ,
WRITE,
ADMIN
ADMIN,
DEPLOY
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,16 @@

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Function;
import java.util.Optional;
import javax.annotation.Nonnull;
import java.util.function.Function;

public class SingularityRequestWithState {
private final SingularityRequest request;
private final RequestState state;
private final long timestamp;

public static Function<SingularityRequestWithState, String> REQUEST_STATE_TO_REQUEST_ID = new Function<SingularityRequestWithState, String>() {

@Override
public String apply(@Nonnull SingularityRequestWithState input) {
return input.getRequest().getId();
}
};
public static Function<SingularityRequestWithState, String> REQUEST_STATE_TO_REQUEST_ID = input ->
input.getRequest().getId();

public static String getRequestState(
Optional<SingularityRequestWithState> maybeRequestWithState
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import io.swagger.v3.oas.annotations.media.Schema;
import java.security.Principal;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
Expand All @@ -17,6 +18,7 @@ public class SingularityUser implements Principal {
private final Optional<String> name;
private final Optional<String> email;
private final Set<String> groups;
private final Set<String> scopes;
private final boolean authenticated;

public static SingularityUser DEFAULT_USER = new SingularityUser(
Expand All @@ -36,18 +38,44 @@ public SingularityUser(
this(id, name, email, groups, true);
}

public SingularityUser(
String id,
Optional<String> name,
Optional<String> email,
Set<String> groups,
boolean authenticated
) {
this(id, name, email, groups, Collections.emptySet(), authenticated);
}

public SingularityUser withOnlyGroups() {
Set<String> mergedGroups = new HashSet<>();
mergedGroups.addAll(groups);
mergedGroups.addAll(scopes);
return new SingularityUser(
id,
name,
email,
mergedGroups,
Collections.emptySet(),
authenticated
);
}

@JsonCreator
public SingularityUser(
@JsonProperty("id") String id,
@JsonProperty("name") Optional<String> name,
@JsonProperty("email") Optional<String> email,
@JsonProperty("groups") Set<String> groups,
@JsonProperty("scopes") Set<String> scopes,
@JsonProperty("authenticated") boolean authenticated
) {
this.id = id;
this.name = name;
this.email = email;
this.groups = copyOf(groups);
this.scopes = scopes != null ? copyOf(scopes) : Collections.emptySet();
this.authenticated = authenticated;
}

Expand All @@ -71,32 +99,38 @@ public Set<String> getGroups() {
return groups;
}

@Schema(description = "Scopes this user has")
public Set<String> getScopes() {
return scopes;
}

@Schema(description = "True if the user was successfully authenticated")
public boolean isAuthenticated() {
return authenticated;
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (obj instanceof SingularityUser) {
final SingularityUser that = (SingularityUser) obj;
return (
Objects.equals(this.authenticated, that.authenticated) &&
Objects.equals(this.id, that.id) &&
Objects.equals(this.name, that.name) &&
Objects.equals(this.email, that.email) &&
Objects.equals(this.groups, that.groups)
);
if (o == null || getClass() != o.getClass()) {
return false;
}
return false;
SingularityUser that = (SingularityUser) o;
return (
authenticated == that.authenticated &&
Objects.equals(id, that.id) &&
Objects.equals(name, that.name) &&
Objects.equals(email, that.email) &&
Objects.equals(groups, that.groups) &&
Objects.equals(scopes, that.scopes)
);
}

@Override
public int hashCode() {
return Objects.hash(id, name, email, groups, authenticated);
return Objects.hash(id, name, email, groups, scopes, authenticated);
}

@Override
Expand All @@ -112,6 +146,8 @@ public String toString() {
email +
", groups=" +
groups +
", scopes=" +
scopes +
", authenticated=" +
authenticated +
'}'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.hubspot.singularity;

import static com.google.common.collect.ImmutableSet.copyOf;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

public class WebhookAuthUser {
private final String uid;
private final Set<String> groups;
private final Set<String> scopes;

@JsonCreator
public WebhookAuthUser(
@JsonProperty("uid") String uid,
@JsonProperty("groups") Set<String> groups,
@JsonProperty("scopes") Set<String> scopes
) {
this.uid = uid;
this.groups = groups;
this.scopes = scopes;
}

public String getUid() {
return uid;
}

public Set<String> getGroups() {
return groups;
}

public Set<String> getScopes() {
return scopes;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
WebhookAuthUser that = (WebhookAuthUser) o;
return (
Objects.equals(uid, that.uid) &&
Objects.equals(groups, that.groups) &&
Objects.equals(scopes, that.scopes)
);
}

@Override
public int hashCode() {
return Objects.hash(uid, groups, scopes);
}

@Override
public String toString() {
return (
"WebhookAuthUser{" +
"uid='" +
uid +
'\'' +
", groups=" +
groups +
", scopes=" +
scopes +
'}'
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,13 @@
import com.google.inject.Module;
import com.google.inject.Scopes;
import com.google.inject.Stage;
import com.google.inject.util.Modules;
import com.hubspot.dropwizard.guicier.GuiceBundle;
import com.hubspot.jackson.datatype.protobuf.ProtobufModule;
import com.hubspot.singularity.auth.SingularityAuthModule;
import com.hubspot.singularity.bundles.CorsBundle;
import com.hubspot.singularity.config.ApiPaths;
import com.hubspot.singularity.config.MergingSourceProvider;
import com.hubspot.singularity.config.SingularityConfiguration;
import com.hubspot.singularity.data.history.SingularityDbModule;
import com.hubspot.singularity.guice.DropwizardObjectMapperProvider;
import io.dropwizard.Application;
import io.dropwizard.Bundle;
Expand All @@ -34,7 +33,6 @@
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.info.Info;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.Optional;

@OpenAPIDefinition(
info = @Info(title = "Singularity"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import com.google.inject.Singleton;
import com.hubspot.dropwizard.guicier.DropwizardAwareModule;
import com.hubspot.mesos.client.SingularityMesosClientModule;
import com.hubspot.singularity.auth.SingularityAuthenticatorClass;
import com.hubspot.singularity.auth.dw.SingularityAuthenticatorClass;
import com.hubspot.singularity.config.IndexViewConfiguration;
import com.hubspot.singularity.config.SingularityConfiguration;
import com.hubspot.singularity.data.SingularityDataModule;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
package com.hubspot.singularity;
package com.hubspot.singularity.auth;

import com.google.inject.Binder;
import com.google.inject.Scopes;
import com.google.inject.multibindings.Multibinder;
import com.google.inject.name.Names;
import com.hubspot.dropwizard.guicier.DropwizardAwareModule;
import com.hubspot.singularity.auth.SingularityAuthFeature;
import com.hubspot.singularity.auth.SingularityAuthenticatorClass;
import com.hubspot.singularity.auth.SingularityAuthorizationHelper;
import com.hubspot.singularity.SingularityAsyncHttpClient;
import com.hubspot.singularity.auth.authenticator.RawUserResponseParser;
import com.hubspot.singularity.auth.authenticator.SingularityAuthenticator;
import com.hubspot.singularity.auth.authenticator.SingularityMultiMethodAuthenticator;
import com.hubspot.singularity.auth.authenticator.WebhookResponseParser;
import com.hubspot.singularity.auth.authenticator.WrappedUserResponseParser;
import com.hubspot.singularity.auth.datastore.SingularityAuthDatastore;
import com.hubspot.singularity.auth.dw.SingularityAuthFeature;
import com.hubspot.singularity.auth.dw.SingularityAuthenticatorClass;
import com.hubspot.singularity.config.AuthConfiguration;
import com.hubspot.singularity.config.SingularityConfiguration;
import com.ning.http.client.AsyncHttpClient;
import com.ning.http.client.AsyncHttpClientConfig;
import java.util.HashSet;
import java.util.Set;

public class SingularityAuthModule
extends DropwizardAwareModule<SingularityConfiguration> {
Expand All @@ -25,13 +30,22 @@ public SingularityAuthModule() {}

@Override
public void configure(Binder binder) {
binder
.bind(AuthConfiguration.class)
.toInstance(getConfiguration().getAuthConfiguration());
Multibinder<SingularityAuthenticator> multibinder = Multibinder.newSetBinder(
binder,
SingularityAuthenticator.class
);
// don't double bind, but maintain ordering
Set<SingularityAuthenticatorClass> bound = new HashSet<>();
for (SingularityAuthenticatorClass clazz : getConfiguration()
.getAuthConfiguration()
.getAuthenticators()) {
if (bound.contains(clazz)) {
continue;
}
bound.add(clazz);
multibinder.addBinding().to(clazz.getAuthenticatorClass());
if (clazz == SingularityAuthenticatorClass.WEBHOOK) {
AuthConfiguration authConfiguration = getConfiguration().getAuthConfiguration();
Expand All @@ -50,13 +64,50 @@ public void configure(Binder binder) {
}
}

switch (getConfiguration().getAuthConfiguration().getAuthMode()) {
case GROUPS_SCOPES:
binder
.bind(SingularityAuthorizer.class)
.to(SingularityGroupsScopesAuthorizer.class)
.in(Scopes.SINGLETON);
break;
case GROUPS_LOG_SCOPES:
binder
.bind(SingularityAuthorizer.class)
.to(SingularityDualAuthorizer.class)
.in(Scopes.SINGLETON);
break;
case GROUPS:
default:
binder
.bind(SingularityAuthorizer.class)
.to(SingularityGroupsAuthorizer.class)
.in(Scopes.SINGLETON);
break;
}

switch (getConfiguration().getAuthConfiguration().getAuthResponseParser()) {
case RAW:
binder
.bind(WebhookResponseParser.class)
.to(RawUserResponseParser.class)
.in(Scopes.SINGLETON);
break;
case WRAPPED:
default:
binder
.bind(WebhookResponseParser.class)
.to(WrappedUserResponseParser.class)
.in(Scopes.SINGLETON);
break;
}

binder.bind(SingularityAuthFeature.class);
binder.bind(SingularityMultiMethodAuthenticator.class);
binder
.bind(SingularityAuthDatastore.class)
.to(
getConfiguration().getAuthConfiguration().getDatastore().getAuthDatastoreClass()
);
binder.bind(SingularityAuthorizationHelper.class).in(Scopes.SINGLETON);
}
}
Loading

0 comments on commit 10eb704

Please sign in to comment.