package com.hubspot.singularity;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.WebApplicationException;
import org.junit.Test;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableSet;
import com.hubspot.singularity.auth.SingularityAuthorizationHelper;
import com.hubspot.singularity.config.AuthConfiguration;
import com.hubspot.singularity.config.MesosConfiguration;
import com.hubspot.singularity.config.SingularityConfiguration;
import com.hubspot.singularity.data.RequestManager;
public class SingularityAuthorizationHelperTest {
public static SingularityConfiguration buildAuthDisabledConfig() {
AuthConfiguration authConfiguration = new AuthConfiguration();
authConfiguration.setEnabled(false);
SingularityConfiguration configuration = new SingularityConfiguration();
configuration.setAuthConfiguration(authConfiguration);
configuration.setMesosConfiguration(new MesosConfiguration());
return configuration;
}
public static SingularityConfiguration buildAuthEnabledConfig() {
return buildAuthEnabledConfig(Collections.<String>emptySet(), Collections.<String>emptySet(), Collections.<String>emptySet());
}
public static SingularityConfiguration buildAuthEnabledConfig(Set<String> requiredGroups, Set<String> adminGroups, Set<String> jitaGroups) {
AuthConfiguration authConfiguration = new AuthConfiguration();
authConfiguration.setEnabled(true);
authConfiguration.setRequiredGroups(requiredGroups);
authConfiguration.setAdminGroups(adminGroups);
authConfiguration.setJitaGroups(jitaGroups);
SingularityConfiguration configuration = new SingularityConfiguration();
configuration.setAuthConfiguration(authConfiguration);
configuration.setMesosConfiguration(new MesosConfiguration());
return configuration;
}
public static final SingularityRequest REQUEST_WITH_NO_GROUP = new SingularityRequestBuilder("test", RequestType.SERVICE).build();
public static final SingularityRequest REQUEST_WITH_GROUP_A = new SingularityRequestBuilder("test_a", RequestType.SERVICE).setGroup(Optional.of("a")).build();
public static final SingularityRequest REQUEST_WITH_GROUP_A_CHANGED_TO_B = new SingularityRequestBuilder("test_a", RequestType.SERVICE).setGroup(Optional.of("b")).build();
public static final SingularityRequest REQUEST_WITH_GROUP_B = new SingularityRequestBuilder("test_b", RequestType.SERVICE).setGroup(Optional.of("b")).build();
public static final Optional<SingularityUser> NOT_LOGGED_IN = Optional.absent();
public static final Optional<SingularityUser> USER_GROUP_A = Optional.of(new SingularityUser("test1", Optional.of("test user1"), Optional.of("test1@test.com"), ImmutableSet.of("a")));
public static final Optional<SingularityUser> USER_GROUP_AB = Optional.of(new SingularityUser("test2", Optional.of("test user2"), Optional.of("test2@test.com"), ImmutableSet.of("a", "b")));
public static final Optional<SingularityUser> USER_GROUP_B = Optional.of(new SingularityUser("test3", Optional.of("test user3"), Optional.of("test3@test.com"), ImmutableSet.of("b")));
public static final Optional<SingularityUser> USER_GROUP_ADMIN = Optional.of(new SingularityUser("admin", Optional.of("admin user"), Optional.of("admin@test.com"), ImmutableSet.of("admin")));
private SingularityAuthorizationHelper buildAuthorizationHelper(SingularityConfiguration configuration) {
return new SingularityAuthorizationHelper(requestManager, configuration);
}
private final RequestManager requestManager;
public SingularityAuthorizationHelperTest() {
requestManager = mock(RequestManager.class);
when(requestManager.getRequest(REQUEST_WITH_NO_GROUP.getId())).thenReturn(Optional.of(new SingularityRequestWithState(REQUEST_WITH_NO_GROUP, RequestState.ACTIVE, 0)));
when(requestManager.getRequest(REQUEST_WITH_GROUP_A.getId())).thenReturn(Optional.of(new SingularityRequestWithState(REQUEST_WITH_GROUP_A, RequestState.ACTIVE, 0)));
when(requestManager.getRequest(REQUEST_WITH_GROUP_B.getId())).thenReturn(Optional.of(new SingularityRequestWithState(REQUEST_WITH_GROUP_B, RequestState.ACTIVE, 0)));
}
@Test
public void testAuthDisabled() {
final SingularityAuthorizationHelper authorizationHelper = buildAuthorizationHelper(buildAuthDisabledConfig());
// anyone should be authorized for requests with no group
assertTrue(authorizationHelper.isAuthorizedForRequest(REQUEST_WITH_NO_GROUP, NOT_LOGGED_IN, SingularityAuthorizationScope.READ));
assertTrue(authorizationHelper.isAuthorizedForRequest(REQUEST_WITH_NO_GROUP, USER_GROUP_A, SingularityAuthorizationScope.READ));
// users with matching group(s) should be authorized
assertTrue(authorizationHelper.isAuthorizedForRequest(REQUEST_WITH_GROUP_A, USER_GROUP_A, SingularityAuthorizationScope.READ));
assertTrue(authorizationHelper.isAuthorizedForRequest(REQUEST_WITH_GROUP_A, USER_GROUP_AB, SingularityAuthorizationScope.READ));
// users without matching group(s) should be authorized
assertTrue(authorizationHelper.isAuthorizedForRequest(REQUEST_WITH_GROUP_A, USER_GROUP_B, SingularityAuthorizationScope.READ));
}
@Test
public void testAuth() {
final SingularityAuthorizationHelper authorizationHelper = buildAuthorizationHelper(buildAuthEnabledConfig());
// user must be authenticated
assertFalse(authorizationHelper.isAuthorizedForRequest(REQUEST_WITH_NO_GROUP, NOT_LOGGED_IN, SingularityAuthorizationScope.READ));
assertFalse(authorizationHelper.isAuthorizedForRequest(REQUEST_WITH_GROUP_A, NOT_LOGGED_IN, SingularityAuthorizationScope.READ));
// anyone should be authorized for requests with no group
assertTrue(authorizationHelper.isAuthorizedForRequest(REQUEST_WITH_NO_GROUP, USER_GROUP_A, SingularityAuthorizationScope.READ));
// user must be logged in to be authorized for any request
assertFalse(authorizationHelper.isAuthorizedForRequest(REQUEST_WITH_NO_GROUP, NOT_LOGGED_IN, SingularityAuthorizationScope.READ));
assertFalse(authorizationHelper.isAuthorizedForRequest(REQUEST_WITH_GROUP_A, NOT_LOGGED_IN, SingularityAuthorizationScope.READ));
// users with matching group(s) should be authorized
assertTrue(authorizationHelper.isAuthorizedForRequest(REQUEST_WITH_GROUP_A, USER_GROUP_A, SingularityAuthorizationScope.READ));
assertTrue(authorizationHelper.isAuthorizedForRequest(REQUEST_WITH_GROUP_A, USER_GROUP_AB, SingularityAuthorizationScope.READ));
// users without matching group(s) should not be authorized
assertFalse(authorizationHelper.isAuthorizedForRequest(REQUEST_WITH_GROUP_B, USER_GROUP_A, SingularityAuthorizationScope.READ));
}
@Test
public void testAuthRequiredGroup() {
final SingularityAuthorizationHelper authorizationHelper = buildAuthorizationHelper(buildAuthEnabledConfig(ImmutableSet.of("a"), Collections.<String>emptySet(), Collections.<String>emptySet()));
// users not in the required group are unauthorized
assertFalse(authorizationHelper.isAuthorizedForRequest(REQUEST_WITH_NO_GROUP, NOT_LOGGED_IN, SingularityAuthorizationScope.READ));
assertTrue(authorizationHelper.isAuthorizedForRequest(REQUEST_WITH_NO_GROUP, USER_GROUP_A, SingularityAuthorizationScope.READ));
assertFalse(authorizationHelper.isAuthorizedForRequest(REQUEST_WITH_NO_GROUP, USER_GROUP_B, SingularityAuthorizationScope.READ));
// user must be part of required group(s) and request group
assertTrue(authorizationHelper.isAuthorizedForRequest(REQUEST_WITH_GROUP_B, USER_GROUP_AB, SingularityAuthorizationScope.READ));
assertFalse(authorizationHelper.isAuthorizedForRequest(REQUEST_WITH_GROUP_B, USER_GROUP_A, SingularityAuthorizationScope.READ));
assertFalse(authorizationHelper.isAuthorizedForRequest(REQUEST_WITH_GROUP_B, USER_GROUP_B, SingularityAuthorizationScope.READ));
}
@Test
public void testAuthAdminGroup() {
final SingularityAuthorizationHelper authorizationHelper = buildAuthorizationHelper(buildAuthEnabledConfig(Collections.<String>emptySet(), ImmutableSet.of("admin"), Collections.<String>emptySet()));
// only users in admin group has admin authorization
assertFalse(authorizationHelper.hasAdminAuthorization(NOT_LOGGED_IN));
assertFalse(authorizationHelper.hasAdminAuthorization(USER_GROUP_A));
assertFalse(authorizationHelper.hasAdminAuthorization(USER_GROUP_AB));
assertTrue(authorizationHelper.hasAdminAuthorization(USER_GROUP_ADMIN));
// users in admin group have access to all
assertTrue(authorizationHelper.isAuthorizedForRequest(REQUEST_WITH_NO_GROUP, USER_GROUP_ADMIN, SingularityAuthorizationScope.READ));
assertTrue(authorizationHelper.isAuthorizedForRequest(REQUEST_WITH_GROUP_A, USER_GROUP_ADMIN, SingularityAuthorizationScope.READ));
assertTrue(authorizationHelper.isAuthorizedForRequest(REQUEST_WITH_GROUP_B, USER_GROUP_ADMIN, SingularityAuthorizationScope.READ));
}
@Test
public void testAuthJitaGroup() {
final SingularityAuthorizationHelper authorizationHelper = buildAuthorizationHelper(buildAuthEnabledConfig(Collections.<String>emptySet(), ImmutableSet.of("admin"), ImmutableSet.of("b")));
// user in JITA group(s) are authorized for all requests
assertTrue(authorizationHelper.isAuthorizedForRequest(REQUEST_WITH_NO_GROUP, USER_GROUP_B, SingularityAuthorizationScope.READ));
assertTrue(authorizationHelper.isAuthorizedForRequest(REQUEST_WITH_GROUP_A, USER_GROUP_B, SingularityAuthorizationScope.READ));
assertTrue(authorizationHelper.isAuthorizedForRequest(REQUEST_WITH_GROUP_B, USER_GROUP_B, SingularityAuthorizationScope.READ));
// but still aren't admins
assertFalse(authorizationHelper.hasAdminAuthorization(USER_GROUP_B));
}
@Test(expected = WebApplicationException.class)
public void testCheckAdminAuthorizationThrowsOnForbidden() {
final SingularityAuthorizationHelper authorizationHelper = buildAuthorizationHelper(buildAuthEnabledConfig(Collections.<String>emptySet(), ImmutableSet.of("admin"), Collections.<String>emptySet()));
authorizationHelper.checkAdminAuthorization(USER_GROUP_A);
}
@Test
public void testCheckAdminAuthorizationDoesntThrowOnAuthorized() {
final SingularityAuthorizationHelper authorizationHelper = buildAuthorizationHelper(buildAuthEnabledConfig(Collections.<String>emptySet(), ImmutableSet.of("admin"), Collections.<String>emptySet()));
authorizationHelper.checkAdminAuthorization(USER_GROUP_ADMIN);
}
@Test
public void testCheckForAuthorizationByTaskIdDoesntThrowOnAuthorized() {
final SingularityAuthorizationHelper authorizationHelper = buildAuthorizationHelper(buildAuthEnabledConfig(Collections.<String>emptySet(), ImmutableSet.of("admin"), Collections.<String>emptySet()));
authorizationHelper.checkForAuthorizationByRequestId(REQUEST_WITH_GROUP_A.getId(), USER_GROUP_A, SingularityAuthorizationScope.READ);
}
@Test(expected = WebApplicationException.class)
public void testCheckForAuthorizationByTaskIdThrowsOnForbidden() {
final SingularityAuthorizationHelper authorizationHelper = buildAuthorizationHelper(buildAuthEnabledConfig(Collections.<String>emptySet(), ImmutableSet.of("admin"), Collections.<String>emptySet()));
authorizationHelper.checkForAuthorizationByRequestId(REQUEST_WITH_GROUP_A.getId(), USER_GROUP_B, SingularityAuthorizationScope.READ);
}
@Test
public void testCheckForAuthorizationDoesntThrowOnAuthorized() {
final SingularityAuthorizationHelper authorizationHelper = buildAuthorizationHelper(buildAuthEnabledConfig(Collections.<String>emptySet(), ImmutableSet.of("admin"), Collections.<String>emptySet()));
authorizationHelper.checkForAuthorization(REQUEST_WITH_GROUP_A, USER_GROUP_A, SingularityAuthorizationScope.READ);
}
@Test(expected = WebApplicationException.class)
public void testCheckForAuthorizationThrowsOnForbidden() {
final SingularityAuthorizationHelper authorizationHelper = buildAuthorizationHelper(buildAuthEnabledConfig(Collections.<String>emptySet(), ImmutableSet.of("admin"), Collections.<String>emptySet()));
authorizationHelper.checkForAuthorization(REQUEST_WITH_GROUP_A, USER_GROUP_B, SingularityAuthorizationScope.READ);
}
@Test
public void testCheckForAuthorizationDoesntThrowOnValidChange() {
final SingularityAuthorizationHelper authorizationHelper = buildAuthorizationHelper(buildAuthEnabledConfig(Collections.<String>emptySet(), ImmutableSet.of("admin"), Collections.<String>emptySet()));
authorizationHelper.checkForAuthorization(REQUEST_WITH_GROUP_A_CHANGED_TO_B, USER_GROUP_AB, SingularityAuthorizationScope.READ);
}
@Test(expected = WebApplicationException.class)
public void testCheckForAuthorizationThrowsOnForbiddenChange() {
final SingularityAuthorizationHelper authorizationHelper = buildAuthorizationHelper(buildAuthEnabledConfig(Collections.<String>emptySet(), ImmutableSet.of("admin"), Collections.<String>emptySet()));
authorizationHelper.checkForAuthorization(REQUEST_WITH_GROUP_A_CHANGED_TO_B, USER_GROUP_A, SingularityAuthorizationScope.READ);
}
@Test(expected = WebApplicationException.class)
public void itRestrictsReadWriteChangesForNonAdminsAndGroupOwners() {
final SingularityAuthorizationHelper authorizationHelper = buildAuthorizationHelper(buildAuthEnabledConfig());
Set<String> readWriteGroupsOld = new HashSet<>();
readWriteGroupsOld.add("a");
final SingularityRequest oldRequest = new SingularityRequestBuilder("test_c", RequestType.SERVICE)
.setGroup(Optional.of("c"))
.setReadWriteGroups(Optional.of(readWriteGroupsOld))
.build();
Set<String> readWriteGroupsNew = new HashSet<>();
readWriteGroupsNew.addAll(readWriteGroupsOld);
readWriteGroupsNew.add("b");
final SingularityRequest newRequest = new SingularityRequestBuilder("test_c", RequestType.SERVICE)
.setGroup(Optional.of("c"))
.setReadWriteGroups(Optional.of(readWriteGroupsNew))
.build();
authorizationHelper.checkForAuthorizedChanges(newRequest, oldRequest, USER_GROUP_A);
}
}