/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.brooklyn.core.mgmt.entitlement;
import org.apache.brooklyn.api.entity.Application;
import org.apache.brooklyn.api.entity.EntitySpec;
import org.apache.brooklyn.api.location.Location;
import org.apache.brooklyn.api.mgmt.ManagementContext;
import org.apache.brooklyn.core.entity.Entities;
import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
import org.apache.brooklyn.core.internal.BrooklynProperties;
import org.apache.brooklyn.core.mgmt.entitlement.Entitlements;
import org.apache.brooklyn.core.mgmt.entitlement.NotEntitledException;
import org.apache.brooklyn.core.mgmt.entitlement.Entitlements.EntityAndItem;
import org.apache.brooklyn.core.mgmt.entitlement.Entitlements.StringAndArgument;
import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext;
import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests;
import org.apache.brooklyn.entity.stock.BasicApplication;
import org.apache.brooklyn.util.core.config.ConfigBag;
import org.apache.brooklyn.util.exceptions.Exceptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
public class EntityEntitlementTest {
private static final Logger log = LoggerFactory.getLogger(EntityEntitlementTest.class);
ManagementContext mgmt;
Application app;
public void setup(ConfigBag cfg) {
mgmt = new LocalManagementContextForTests(BrooklynProperties.Factory.newEmpty().addFrom(cfg));
app = ApplicationBuilder.newManagedApp(EntitySpec.create(BasicApplication.class), mgmt);
}
@AfterMethod(alwaysRun=true)
public void tearDown() {
if (app != null) Entities.destroyAll(app.getManagementContext());
if (mgmt != null) Entities.destroyAll(mgmt);
app = null;
mgmt = null;
}
@Test
public void testDefaultRootAllows() {
setup(ConfigBag.newInstance());
// default "root" access allows ROOT permission, and invoke effector, etc
Assert.assertTrue(mgmt.getEntitlementManager().isEntitled(null, Entitlements.ROOT, null));
Assert.assertTrue(mgmt.getEntitlementManager().isEntitled(null, Entitlements.SEE_ENTITY, app));
Assert.assertTrue(mgmt.getEntitlementManager().isEntitled(null, Entitlements.INVOKE_EFFECTOR, EntityAndItem.of(app, StringAndArgument.of("any-eff", null))));
Assert.assertTrue(mgmt.getEntitlementManager().isEntitled(null, Entitlements.SEE_SENSOR, EntityAndItem.of(app, "any-sensor")));
// and can invoke methods, without any user/login registered
confirmEffectorEntitlement(true);
confirmSensorEntitlement(true);
}
@Test
public void testExplicitRootAllows() {
setup(ConfigBag.newInstance().configure(Entitlements.GLOBAL_ENTITLEMENT_MANAGER, "root"));
Assert.assertTrue(mgmt.getEntitlementManager().isEntitled(null, Entitlements.ROOT, null));
Assert.assertTrue(mgmt.getEntitlementManager().isEntitled(null, Entitlements.SEE_ENTITY, app));
Assert.assertTrue(mgmt.getEntitlementManager().isEntitled(null, Entitlements.INVOKE_EFFECTOR, EntityAndItem.of(app, StringAndArgument.of("any-eff", null))));
Assert.assertTrue(mgmt.getEntitlementManager().isEntitled(null, Entitlements.SEE_SENSOR, EntityAndItem.of(app, "any-sensor")));
confirmEffectorEntitlement(true);
confirmSensorEntitlement(true);
}
@Test
public void testReadOnlyThrowsNotEntitled() {
try {
setup(ConfigBag.newInstance().configure(Entitlements.GLOBAL_ENTITLEMENT_MANAGER, "readonly"));
// eventually above call will fail in app creation, but for now the call below falls
((BasicApplication)app).start(ImmutableList.<Location>of());
tearDown();
Assert.fail("something should have been disallowed");
} catch (Exception e) {
checkNotEntitledException(e);
} finally {
app = null;
if (mgmt!=null) ((LocalManagementContext)mgmt).terminate();
mgmt = null;
}
}
@Test(enabled=false)
// this test (and minimal below) currently work fine until tearDown,
// but then of course they don't have entitlement to call 'stop';
// (as more entitlement checks are added app creation will fail).
//
// TODO these tests should set up a user with the permission,
// e.g. so system has root, but 'bob' has read-only, then we can test read-only;
// TODO rest api tests, as some of the permissions will only be enforced at REST level
public void testReadOnlyAllowsSome() {
setup(ConfigBag.newInstance().configure(Entitlements.GLOBAL_ENTITLEMENT_MANAGER, "readonly"));
Assert.assertFalse(mgmt.getEntitlementManager().isEntitled(null, Entitlements.ROOT, null));
Assert.assertTrue(mgmt.getEntitlementManager().isEntitled(null, Entitlements.SEE_ENTITY, app));
Assert.assertFalse(mgmt.getEntitlementManager().isEntitled(null, Entitlements.INVOKE_EFFECTOR, EntityAndItem.of(app, StringAndArgument.of("any-eff", null))));
Assert.assertTrue(mgmt.getEntitlementManager().isEntitled(null, Entitlements.SEE_SENSOR, EntityAndItem.of(app, "any-sensor")));
confirmEffectorEntitlement(false);
confirmSensorEntitlement(true);
}
@Test(enabled=false)
public void testMinimalDisallows() {
setup(ConfigBag.newInstance().configure(Entitlements.GLOBAL_ENTITLEMENT_MANAGER, "minimal"));
Assert.assertFalse(mgmt.getEntitlementManager().isEntitled(null, Entitlements.ROOT, null));
Assert.assertFalse(mgmt.getEntitlementManager().isEntitled(null, Entitlements.SEE_ENTITY, app));
Assert.assertFalse(mgmt.getEntitlementManager().isEntitled(null, Entitlements.INVOKE_EFFECTOR, EntityAndItem.of(app, StringAndArgument.of("any-eff", null))));
Assert.assertFalse(mgmt.getEntitlementManager().isEntitled(null, Entitlements.SEE_SENSOR, EntityAndItem.of(app, "any-sensor")));
confirmEffectorEntitlement(false);
confirmSensorEntitlement(false);
}
protected void confirmSensorEntitlement(boolean shouldSucceed) {
// TODO... based on above
// (though maybe we should test against REST API classes rather than lower level programmatic?
// TBC...)
log.warn("confirmSensorEntitlement still required!");
}
// TODO specific users tests
protected void confirmEffectorEntitlement(boolean shouldSucceed) {
try {
((BasicApplication)app).start(ImmutableList.<Location>of());
checkNoException(shouldSucceed);
} catch (Exception e) {
checkNotEntitledException(shouldSucceed, e);
}
}
private void checkNoException(boolean shouldBeEntitled) {
checkNotEntitledException(shouldBeEntitled, null);
}
private void checkNotEntitledException(Exception e) {
checkNotEntitledException(false, e);
}
private void checkNotEntitledException(boolean shouldBeEntitled, Exception e) {
if (e==null) {
if (shouldBeEntitled) return;
Assert.fail("entitlement should have been denied");
}
Exception notEntitled = Exceptions.getFirstThrowableOfType(e, NotEntitledException.class);
if (notEntitled==null)
throw Exceptions.propagate(e);
if (!shouldBeEntitled) {
/* denied, as it should have been */
return;
}
Assert.fail("entitlement should have been granted, but was denied: "+e);
}
}