/*
* Copyright © 2016 Cask Data, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package co.cask.cdap.security;
import co.cask.cdap.AllProgramsApp;
import co.cask.cdap.ConfigTestApp;
import co.cask.cdap.common.conf.Constants;
import co.cask.cdap.common.namespace.NamespaceAdmin;
import co.cask.cdap.common.utils.Tasks;
import co.cask.cdap.gateway.handlers.InMemoryAuthorizer;
import co.cask.cdap.internal.test.AppJarHelper;
import co.cask.cdap.proto.NamespaceMeta;
import co.cask.cdap.proto.artifact.AppRequest;
import co.cask.cdap.proto.artifact.ArtifactSummary;
import co.cask.cdap.proto.id.ApplicationId;
import co.cask.cdap.proto.id.ArtifactId;
import co.cask.cdap.proto.id.Ids;
import co.cask.cdap.proto.id.InstanceId;
import co.cask.cdap.proto.id.NamespaceId;
import co.cask.cdap.proto.id.ProgramId;
import co.cask.cdap.proto.security.Action;
import co.cask.cdap.proto.security.Principal;
import co.cask.cdap.proto.security.Privilege;
import co.cask.cdap.security.spi.authentication.SecurityRequestContext;
import co.cask.cdap.security.spi.authorization.Authorizer;
import co.cask.cdap.security.spi.authorization.UnauthorizedException;
import co.cask.cdap.test.ApplicationManager;
import co.cask.cdap.test.ArtifactManager;
import co.cask.cdap.test.ServiceManager;
import co.cask.cdap.test.SlowTests;
import co.cask.cdap.test.TestBase;
import co.cask.cdap.test.TestConfiguration;
import co.cask.cdap.test.app.DummyApp;
import co.cask.cdap.test.artifacts.plugins.ToStringPlugin;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import org.apache.twill.filesystem.LocalLocationFactory;
import org.apache.twill.filesystem.Location;
import org.apache.twill.filesystem.LocationFactory;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.rules.ExternalResource;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
/**
* Unit tests with authorization enabled.
*/
public class AuthorizationTest extends TestBase {
private static final String OLD_USER = SecurityRequestContext.getUserId();
private static final Principal ALICE = new Principal("alice", Principal.PrincipalType.USER);
private static final Principal BOB = new Principal("bob", Principal.PrincipalType.USER);
private static final NamespaceId AUTH_NAMESPACE = new NamespaceId("authorization");
private static final NamespaceMeta AUTH_NAMESPACE_META =
new NamespaceMeta.Builder().setName(AUTH_NAMESPACE.getNamespace()).build();
private static InstanceId instance;
/**
* An {@link ExternalResource} that wraps a {@link TemporaryFolder} and {@link TestConfiguration} to execute them in
* a chain.
*/
private static final class AuthTestConf extends ExternalResource {
private final TemporaryFolder tmpFolder = new TemporaryFolder();
private TestConfiguration testConf;
@Override
public Statement apply(final Statement base, final Description description) {
// Apply the TemporaryFolder on a Statement that creates a TestConfiguration and applies on base
return tmpFolder.apply(new Statement() {
@Override
public void evaluate() throws Throwable {
testConf = new TestConfiguration(getAuthConfigs(tmpFolder.newFolder()));
testConf.apply(base, description).evaluate();
}
}, description);
}
private static String[] getAuthConfigs(File tmpDir) throws IOException {
LocationFactory locationFactory = new LocalLocationFactory(tmpDir);
Location authExtensionJar = AppJarHelper.createDeploymentJar(locationFactory, InMemoryAuthorizer.class);
return new String[] {
Constants.Security.ENABLED, "true",
Constants.Security.Authorization.ENABLED, "true",
Constants.Security.Authorization.EXTENSION_JAR_PATH, authExtensionJar.toURI().getPath()
};
}
}
@ClassRule
public static final AuthTestConf AUTH_TEST_CONF = new AuthTestConf();
@BeforeClass
public static void setup() {
instance = new InstanceId(getConfiguration().get(Constants.INSTANCE_NAME));
SecurityRequestContext.setUserId(ALICE.getName());
}
@Before
public void setupTest() throws Exception {
Assert.assertEquals(ImmutableSet.of(), getAuthorizer().listPrivileges(ALICE));
}
@Test
public void testNamespaces() throws Exception {
NamespaceAdmin namespaceAdmin = getNamespaceAdmin();
Authorizer authorizer = getAuthorizer();
try {
namespaceAdmin.create(AUTH_NAMESPACE_META);
Assert.fail("Namespace create should have failed because alice is not authorized on " + instance);
} catch (UnauthorizedException expected) {
// expected
}
authorizer.grant(instance, ALICE, ImmutableSet.of(Action.ADMIN));
Assert.assertEquals(ImmutableSet.of(new Privilege(instance, Action.ADMIN)), authorizer.listPrivileges(ALICE));
namespaceAdmin.create(AUTH_NAMESPACE_META);
// create should grant all privileges
Assert.assertEquals(
ImmutableSet.of(new Privilege(instance, Action.ADMIN), new Privilege(AUTH_NAMESPACE, Action.ALL)),
authorizer.listPrivileges(ALICE)
);
// No authorization currently for listing and retrieving namespace
namespaceAdmin.list();
namespaceAdmin.get(AUTH_NAMESPACE.toId());
// revoke privileges
authorizer.revoke(AUTH_NAMESPACE);
Assert.assertEquals(ImmutableSet.of(new Privilege(instance, Action.ADMIN)), authorizer.listPrivileges(ALICE));
try {
namespaceAdmin.deleteDatasets(AUTH_NAMESPACE.toId());
Assert.fail("Namespace delete datasets should have failed because alice's privileges on the namespace have " +
"been revoked");
} catch (UnauthorizedException expected) {
// expected
}
// grant privileges again
authorizer.grant(AUTH_NAMESPACE, ALICE, ImmutableSet.of(Action.ADMIN));
Assert.assertEquals(
ImmutableSet.of(new Privilege(instance, Action.ADMIN), new Privilege(AUTH_NAMESPACE, Action.ADMIN)),
authorizer.listPrivileges(ALICE)
);
namespaceAdmin.deleteDatasets(AUTH_NAMESPACE.toId());
// deleting datasets does not revoke privileges.
Assert.assertEquals(
ImmutableSet.of(new Privilege(instance, Action.ADMIN), new Privilege(AUTH_NAMESPACE, Action.ADMIN)),
authorizer.listPrivileges(ALICE)
);
NamespaceMeta updated = new NamespaceMeta.Builder(AUTH_NAMESPACE_META).setDescription("new desc").build();
namespaceAdmin.updateProperties(AUTH_NAMESPACE.toId(), updated);
namespaceAdmin.delete(AUTH_NAMESPACE.toId());
// once the namespace has been deleted, privileges on that namespace should be revoked
Assert.assertEquals(ImmutableSet.of(new Privilege(instance, Action.ADMIN)), authorizer.listPrivileges(ALICE));
// revoke alice's ADMIN privilege on the instance, so we get back to the same state as at the beginning of the test
authorizer.revoke(instance);
Assert.assertEquals(ImmutableSet.of(), authorizer.listPrivileges(ALICE));
}
@Test
@Category(SlowTests.class)
public void testApps() throws Exception {
try {
deployApplication(NamespaceId.DEFAULT.toId(), DummyApp.class);
Assert.fail("App deployment should fail because alice does not have WRITE access on the default namespace");
} catch (RuntimeException e) {
Assert.assertTrue(e.getCause() instanceof UnauthorizedException);
}
Authorizer authorizer = getAuthorizer();
authorizer.grant(instance, ALICE, ImmutableSet.of(Action.ADMIN));
getNamespaceAdmin().create(AUTH_NAMESPACE_META);
Assert.assertEquals(
ImmutableSet.of(new Privilege(instance, Action.ADMIN), new Privilege(AUTH_NAMESPACE, Action.ALL)),
authorizer.listPrivileges(ALICE)
);
// deployment should succeed in the authorized namespace because alice has all privileges on it
ApplicationManager appManager = deployApplication(AUTH_NAMESPACE.toId(), DummyApp.class);
// alice should get all privileges on the app after deployment succeeds
ApplicationId dummyAppId = AUTH_NAMESPACE.app(DummyApp.class.getSimpleName());
ArtifactSummary artifact = appManager.getInfo().getArtifact();
ArtifactId dummyArtifact =
Ids.namespace(dummyAppId.getNamespace()).artifact(artifact.getName(), artifact.getVersion());
ProgramId greetingServiceId = dummyAppId.service(DummyApp.Greeting.SERVICE_NAME);
Assert.assertEquals(
ImmutableSet.of(
new Privilege(instance, Action.ADMIN),
new Privilege(AUTH_NAMESPACE, Action.ALL),
new Privilege(dummyAppId, Action.ALL),
new Privilege(dummyArtifact, Action.ALL),
new Privilege(greetingServiceId, Action.ALL)
),
authorizer.listPrivileges(ALICE)
);
// Bob should not have any privileges on Alice's app
Assert.assertTrue("Bob should not have any privileges on alice's app", authorizer.listPrivileges(BOB).isEmpty());
// This is necessary because in tests, artifacts have auto-generated versions when an app is deployed without
// first creating an artifact
String version = artifact.getVersion();
// update should succeed because alice has admin privileges on the app
appManager.update(new AppRequest(artifact));
// Update should fail for Bob
SecurityRequestContext.setUserId(BOB.getName());
try {
appManager.update(new AppRequest(new ArtifactSummary(DummyApp.class.getSimpleName(), version)));
Assert.fail("App update should have failed because Alice does not have admin privileges on the app.");
} catch (UnauthorizedException expected) {
// expected
}
// grant READ and WRITE to Bob
authorizer.grant(dummyAppId, BOB, ImmutableSet.of(Action.READ, Action.WRITE));
// delete should fail
try {
appManager.delete();
} catch (UnauthorizedException expected) {
// expected
}
// grant ADMIN to Bob. Now delete should succeed
authorizer.grant(dummyAppId, BOB, ImmutableSet.of(Action.ADMIN));
Assert.assertEquals(
ImmutableSet.of(
new Privilege(dummyAppId, Action.READ),
new Privilege(dummyAppId, Action.WRITE),
new Privilege(dummyAppId, Action.ADMIN)
),
authorizer.listPrivileges(BOB)
);
appManager.delete();
// All privileges on the app should have been revoked
Assert.assertEquals(
ImmutableSet.of(
new Privilege(instance, Action.ADMIN),
new Privilege(AUTH_NAMESPACE, Action.ALL),
new Privilege(dummyArtifact, Action.ALL)
),
authorizer.listPrivileges(ALICE)
);
Assert.assertTrue("Bob should not have any privileges because all privileges on the app have been revoked " +
"since the app got deleted", authorizer.listPrivileges(BOB).isEmpty());
// switch back to Alice
SecurityRequestContext.setUserId(ALICE.getName());
// Deploy a couple of apps in the namespace
appManager = deployApplication(AUTH_NAMESPACE.toId(), DummyApp.class);
artifact = appManager.getInfo().getArtifact();
ArtifactId updatedDummyArtifact = AUTH_NAMESPACE.artifact(artifact.getName(), artifact.getVersion());
appManager = deployApplication(AUTH_NAMESPACE.toId(), AllProgramsApp.class);
artifact = appManager.getInfo().getArtifact();
ArtifactId workflowArtifact = AUTH_NAMESPACE.artifact(artifact.getName(), artifact.getVersion());
ApplicationId workflowAppId = AUTH_NAMESPACE.app(AllProgramsApp.NAME);
ProgramId flowId = workflowAppId.flow(AllProgramsApp.NoOpFlow.NAME);
ProgramId classicMapReduceId = workflowAppId.mr(AllProgramsApp.NoOpMR.NAME);
ProgramId mapReduceId = workflowAppId.mr(AllProgramsApp.NoOpMR2.NAME);
ProgramId sparkId = workflowAppId.spark(AllProgramsApp.NoOpSpark.NAME);
ProgramId workflowId = workflowAppId.workflow(AllProgramsApp.NoOpWorkflow.NAME);
ProgramId serviceId = workflowAppId.service(AllProgramsApp.NoOpService.NAME);
ProgramId workerId = workflowAppId.worker(AllProgramsApp.NoOpWorker.NAME);
Assert.assertEquals(
ImmutableSet.of(
new Privilege(instance, Action.ADMIN),
new Privilege(AUTH_NAMESPACE, Action.ALL),
new Privilege(dummyArtifact, Action.ALL),
new Privilege(updatedDummyArtifact, Action.ALL),
new Privilege(workflowArtifact, Action.ALL),
new Privilege(dummyAppId, Action.ALL),
new Privilege(workflowAppId, Action.ALL),
new Privilege(greetingServiceId, Action.ALL),
new Privilege(flowId, Action.ALL),
new Privilege(classicMapReduceId, Action.ALL),
new Privilege(mapReduceId, Action.ALL),
new Privilege(sparkId, Action.ALL),
new Privilege(workflowId, Action.ALL),
new Privilege(serviceId, Action.ALL),
new Privilege(workerId, Action.ALL)
),
authorizer.listPrivileges(ALICE)
);
// revoke all privileges on an app.
authorizer.revoke(workflowAppId);
// TODO: CDAP-5428 Revoking privileges on an app should revoke privileges on the contents of the app
authorizer.revoke(flowId);
authorizer.revoke(classicMapReduceId);
authorizer.revoke(mapReduceId);
authorizer.revoke(sparkId);
authorizer.revoke(workflowId);
authorizer.revoke(serviceId);
authorizer.revoke(workerId);
Assert.assertEquals(
ImmutableSet.of(
new Privilege(instance, Action.ADMIN),
new Privilege(AUTH_NAMESPACE, Action.ALL),
new Privilege(dummyArtifact, Action.ALL),
new Privilege(updatedDummyArtifact, Action.ALL),
new Privilege(workflowArtifact, Action.ALL),
new Privilege(dummyAppId, Action.ALL),
new Privilege(greetingServiceId, Action.ALL)
),
authorizer.listPrivileges(ALICE)
);
// deleting all apps should fail because alice does not have admin privileges on the Workflow app
try {
deleteAllApplications(AUTH_NAMESPACE);
Assert.fail("Deleting all applications in the namespace should have failed because alice does not have ADMIN " +
"privilege on the workflow app.");
} catch (UnauthorizedException expected) {
// expected
}
// grant admin privilege on the WorkflowApp. deleting all applications should succeed.
authorizer.grant(workflowAppId, ALICE, ImmutableSet.of(Action.ADMIN));
deleteAllApplications(AUTH_NAMESPACE);
// deleting all apps should remove all privileges on all apps, but the privilege on the namespace should still exist
Assert.assertEquals(
ImmutableSet.of(
new Privilege(instance, Action.ADMIN),
new Privilege(AUTH_NAMESPACE, Action.ALL),
new Privilege(dummyArtifact, Action.ALL),
new Privilege(updatedDummyArtifact, Action.ALL),
new Privilege(workflowArtifact, Action.ALL)
),
authorizer.listPrivileges(ALICE)
);
// clean up. remove the namespace. all privileges on the namespace should be revoked
getNamespaceAdmin().delete(AUTH_NAMESPACE.toId());
Assert.assertEquals(ImmutableSet.of(new Privilege(instance, Action.ADMIN)), authorizer.listPrivileges(ALICE));
// revoke privileges on the instance
authorizer.revoke(instance);
Assert.assertEquals(ImmutableSet.of(), authorizer.listPrivileges(ALICE));
}
@Test
public void testArtifacts() throws Exception {
String appArtifactName = "app-artifact";
String appArtifactVersion = "1.1.1";
try {
ArtifactId defaultNsArtifact = NamespaceId.DEFAULT.artifact(appArtifactName, appArtifactVersion);
addAppArtifact(defaultNsArtifact, ConfigTestApp.class);
Assert.fail("Should not be able to add an app artifact to the default namespace because alice does not have " +
"write privileges on the default namespace.");
} catch (UnauthorizedException expected) {
// expected
}
String pluginArtifactName = "plugin-artifact";
String pluginArtifactVersion = "1.2.3";
try {
ArtifactId defaultNsArtifact = NamespaceId.DEFAULT.artifact(pluginArtifactName, pluginArtifactVersion);
addAppArtifact(defaultNsArtifact, ToStringPlugin.class);
Assert.fail("Should not be able to add a plugin artifact to the default namespace because alice does not have " +
"write privileges on the default namespace.");
} catch (UnauthorizedException expected) {
// expected
}
// create a new namespace, alice should get ALL privileges on the namespace
Authorizer authorizer = getAuthorizer();
authorizer.grant(instance, ALICE, ImmutableSet.of(Action.ADMIN));
getNamespaceAdmin().create(AUTH_NAMESPACE_META);
Assert.assertEquals(
ImmutableSet.of(new Privilege(instance, Action.ADMIN), new Privilege(AUTH_NAMESPACE, Action.ALL)),
authorizer.listPrivileges(ALICE)
);
// artifact deployment in this namespace should now succeed, and alice should have ALL privileges on the artifacts
ArtifactId appArtifactId = new ArtifactId(AUTH_NAMESPACE.getNamespace(), appArtifactName, appArtifactVersion);
ArtifactManager appArtifactManager = addAppArtifact(appArtifactId, ConfigTestApp.class);
ArtifactId pluginArtifactId =
new ArtifactId(AUTH_NAMESPACE.getNamespace(), pluginArtifactName, pluginArtifactVersion);
ArtifactManager pluginArtifactManager = addPluginArtifact(pluginArtifactId, appArtifactId, ToStringPlugin.class);
Assert.assertEquals(
ImmutableSet.of(
new Privilege(instance, Action.ADMIN),
new Privilege(AUTH_NAMESPACE, Action.ALL),
new Privilege(appArtifactId, Action.ALL),
new Privilege(pluginArtifactId, Action.ALL)
),
authorizer.listPrivileges(ALICE)
);
// Bob should not be able to delete artifacts that he does not have ADMIN permission on
SecurityRequestContext.setUserId(BOB.getName());
try {
appArtifactManager.writeProperties(ImmutableMap.of("authorized", "no"));
Assert.fail("Writing properties to artifact should have failed because Bob does not have admin privileges on " +
"the artifact");
} catch (UnauthorizedException expected) {
// expected
}
try {
appArtifactManager.delete();
Assert.fail("Deleting artifact should have failed because Bob does not have admin privileges on the artifact");
} catch (UnauthorizedException expected) {
// expected
}
try {
pluginArtifactManager.writeProperties(ImmutableMap.of("authorized", "no"));
Assert.fail("Writing properties to artifact should have failed because Bob does not have admin privileges on " +
"the artifact");
} catch (UnauthorizedException expected) {
// expected
}
try {
pluginArtifactManager.removeProperties();
Assert.fail("Removing properties to artifact should have failed because Bob does not have admin privileges on " +
"the artifact");
} catch (UnauthorizedException expected) {
// expected
}
try {
pluginArtifactManager.delete();
Assert.fail("Deleting artifact should have failed because Bob does not have admin privileges on the artifact");
} catch (UnauthorizedException expected) {
// expected
}
// alice should be permitted to update properties/delete artifact
SecurityRequestContext.setUserId(ALICE.getName());
appArtifactManager.writeProperties(ImmutableMap.of("authorized", "yes"));
appArtifactManager.removeProperties();
appArtifactManager.delete();
pluginArtifactManager.delete();
// upon successful deletion, alice should lose all privileges on the artifact
Assert.assertEquals(
ImmutableSet.of(
new Privilege(instance, Action.ADMIN),
new Privilege(AUTH_NAMESPACE, Action.ALL)
),
authorizer.listPrivileges(ALICE)
);
// clean up. remove the namespace. all privileges on the namespace should be revoked
getNamespaceAdmin().delete(AUTH_NAMESPACE.toId());
Assert.assertEquals(ImmutableSet.of(new Privilege(instance, Action.ADMIN)), authorizer.listPrivileges(ALICE));
// revoke privileges on the instance
authorizer.revoke(instance);
Assert.assertEquals(ImmutableSet.of(), authorizer.listPrivileges(ALICE));
}
@Test
public void testPrograms() throws Exception {
Authorizer authorizer = getAuthorizer();
authorizer.grant(instance, ALICE, ImmutableSet.of(Action.ADMIN));
getNamespaceAdmin().create(AUTH_NAMESPACE_META);
Assert.assertEquals(
ImmutableSet.of(new Privilege(instance, Action.ADMIN), new Privilege(AUTH_NAMESPACE, Action.ALL)),
authorizer.listPrivileges(ALICE)
);
final ApplicationManager dummyAppManager = deployApplication(AUTH_NAMESPACE.toId(), DummyApp.class);
ArtifactSummary dummyArtifactSummary = dummyAppManager.getInfo().getArtifact();
ArtifactId dummyArtifact = AUTH_NAMESPACE.artifact(dummyArtifactSummary.getName(),
dummyArtifactSummary.getVersion());
ApplicationId appId = AUTH_NAMESPACE.app(DummyApp.class.getSimpleName());
final ProgramId serviceId = appId.service(DummyApp.Greeting.SERVICE_NAME);
Assert.assertEquals(
ImmutableSet.of(
new Privilege(instance, Action.ADMIN),
new Privilege(AUTH_NAMESPACE, Action.ALL),
new Privilege(dummyArtifact, Action.ALL),
new Privilege(appId, Action.ALL),
new Privilege(serviceId, Action.ALL)
),
authorizer.listPrivileges(ALICE)
);
// alice should be able to start and stop programs in the app she deployed
dummyAppManager.startProgram(serviceId.toId());
Tasks.waitFor(true, new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return dummyAppManager.isRunning(serviceId.toId());
}
}, 5, TimeUnit.SECONDS);
ServiceManager greetingService = dummyAppManager.getServiceManager(serviceId.getProgram());
// alice should be able to set instances for the program
greetingService.setInstances(2);
Assert.assertEquals(2, greetingService.getProvisionedInstances());
// alice should also be able to save runtime arguments for all future runs of the program
Map<String, String> args = ImmutableMap.of("key", "value");
greetingService.setRuntimeArgs(args);
dummyAppManager.stopProgram(serviceId.toId());
Tasks.waitFor(false, new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return dummyAppManager.isRunning(serviceId.toId());
}
}, 5, TimeUnit.SECONDS);
// Bob should not be able to start programs in dummy app because he does not have privileges on it
SecurityRequestContext.setUserId(BOB.getName());
try {
dummyAppManager.startProgram(serviceId.toId());
Assert.fail("Bob should not be able to start the service because he does not have admin privileges on it.");
} catch (RuntimeException expected) {
//noinspection ThrowableResultOfMethodCallIgnored
Assert.assertTrue(Throwables.getRootCause(expected) instanceof UnauthorizedException);
}
// TODO: CDAP-5452 can't verify running programs in this case, because DefaultApplicationManager maintains an
// in-memory map of running processes that does not use ApplicationLifecycleService to get the runtime status.
// So no matter if the start/stop call succeeds or fails, it updates its running state in the in-memory map.
// Also have to switch back to being alice, start the program, and then stop it as Bob because otherwise AppManager
// doesn't send the request to the app fabric service, but just makes decisions based on an in-memory
// ConcurrentHashMap.
// Also add a test for stopping with unauthorized user after the above bug is fixed
// setting instances should fail because Bob does not have admin privileges on the program
try {
greetingService.setInstances(3);
Assert.fail("Setting instances should have failed because bob does not have admin privileges on the service.");
} catch (RuntimeException expected) {
//noinspection ThrowableResultOfMethodCallIgnored
Assert.assertTrue(Throwables.getRootCause(expected) instanceof UnauthorizedException);
}
try {
greetingService.setRuntimeArgs(args);
Assert.fail("Setting runtime arguments should have failed because bob does not have admin privileges on the " +
"service");
} catch (UnauthorizedException expected) {
// expected
}
SecurityRequestContext.setUserId(ALICE.getName());
dummyAppManager.delete();
Assert.assertEquals(
ImmutableSet.of(
new Privilege(instance, Action.ADMIN),
new Privilege(AUTH_NAMESPACE, Action.ALL),
new Privilege(dummyArtifact, Action.ALL)
),
authorizer.listPrivileges(ALICE)
);
getNamespaceAdmin().delete(AUTH_NAMESPACE.toId());
// revoke alice's ADMIN privilege on the instance, so we get back to the same state as at the beginning of the test
authorizer.revoke(instance);
Assert.assertEquals(ImmutableSet.of(), authorizer.listPrivileges(ALICE));
}
@AfterClass
public static void cleanup() throws Exception {
// we want to execute TestBase's @AfterClass after unsetting userid, because the old userid has been granted ADMIN
// on default namespace in TestBase so it can clean the namespace.
SecurityRequestContext.setUserId(OLD_USER);
finish();
}
}