killbill-memoizeit

entitlement: Add explicit permission checks for Entitlement

10/16/2015 9:32:05 PM

Details

diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlement.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlement.java
index 97583ac..7a7ec33 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlement.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlement.java
@@ -21,10 +21,10 @@ import java.util.Collection;
 import java.util.List;
 import java.util.UUID;
 
+import org.apache.shiro.SecurityUtils;
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
-
 import org.killbill.billing.ErrorCode;
 import org.killbill.billing.callcontext.InternalCallContext;
 import org.killbill.billing.catalog.api.BillingActionPolicy;
@@ -35,35 +35,42 @@ import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
 import org.killbill.billing.catalog.api.PriceList;
 import org.killbill.billing.catalog.api.Product;
 import org.killbill.billing.catalog.api.ProductCategory;
-import org.killbill.billing.entitlement.api.EntitlementPluginExecution.WithEntitlementPlugin;
-import org.killbill.billing.entitlement.plugin.api.EntitlementContext;
-import org.killbill.billing.entitlement.plugin.api.OperationType;
-import org.killbill.billing.payment.api.PluginProperty;
-import org.killbill.clock.Clock;
 import org.killbill.billing.entitlement.DefaultEntitlementService;
 import org.killbill.billing.entitlement.EntitlementService;
 import org.killbill.billing.entitlement.EventsStream;
+import org.killbill.billing.entitlement.api.EntitlementPluginExecution.WithEntitlementPlugin;
 import org.killbill.billing.entitlement.block.BlockingChecker;
 import org.killbill.billing.entitlement.dao.BlockingStateDao;
 import org.killbill.billing.entitlement.engine.core.EntitlementNotificationKey;
 import org.killbill.billing.entitlement.engine.core.EntitlementNotificationKeyAction;
 import org.killbill.billing.entitlement.engine.core.EntitlementUtils;
 import org.killbill.billing.entitlement.engine.core.EventsStreamBuilder;
+import org.killbill.billing.entitlement.plugin.api.EntitlementContext;
+import org.killbill.billing.entitlement.plugin.api.OperationType;
 import org.killbill.billing.entity.EntityBase;
 import org.killbill.billing.junction.DefaultBlockingState;
-import org.killbill.notificationq.api.NotificationEvent;
-import org.killbill.notificationq.api.NotificationQueue;
-import org.killbill.notificationq.api.NotificationQueueService;
-import org.killbill.notificationq.api.NotificationQueueService.NoSuchNotificationQueue;
+import org.killbill.billing.payment.api.PluginProperty;
+import org.killbill.billing.security.Logical;
+import org.killbill.billing.security.Permission;
+import org.killbill.billing.security.SecurityApiException;
+import org.killbill.billing.security.api.SecurityApi;
 import org.killbill.billing.subscription.api.SubscriptionBase;
 import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
 import org.killbill.billing.subscription.api.user.SubscriptionBaseApiException;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.callcontext.TenantContext;
+import org.killbill.clock.Clock;
+import org.killbill.notificationq.api.NotificationEvent;
+import org.killbill.notificationq.api.NotificationQueue;
+import org.killbill.notificationq.api.NotificationQueueService;
+import org.killbill.notificationq.api.NotificationQueueService.NoSuchNotificationQueue;
+
+import com.google.common.collect.ImmutableList;
 
 public class DefaultEntitlement extends EntityBase implements Entitlement {
 
+    private final SecurityApi securityApi;
     protected final EventsStreamBuilder eventsStreamBuilder;
     protected final EntitlementDateHelper dateHelper;
     protected final InternalCallContextFactory internalCallContextFactory;
@@ -84,18 +91,18 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
                               final EntitlementApi entitlementApi, final EntitlementPluginExecution pluginExecution, final BlockingStateDao blockingStateDao,
                               final SubscriptionBaseInternalApi subscriptionInternalApi, final BlockingChecker checker,
                               final NotificationQueueService notificationQueueService, final EntitlementUtils entitlementUtils,
-                              final EntitlementDateHelper dateHelper, final Clock clock,
+                              final EntitlementDateHelper dateHelper, final Clock clock, final SecurityApi securityApi,
                               final InternalCallContextFactory internalCallContextFactory, final TenantContext tenantContext) throws EntitlementApiException {
         this(eventsStreamBuilder.buildForEntitlement(entitlementId, tenantContext), eventsStreamBuilder,
              entitlementApi, pluginExecution, blockingStateDao, subscriptionInternalApi, checker, notificationQueueService,
-             entitlementUtils, dateHelper, clock, internalCallContextFactory);
+             entitlementUtils, dateHelper, clock, securityApi, internalCallContextFactory);
     }
 
     public DefaultEntitlement(final EventsStream eventsStream, final EventsStreamBuilder eventsStreamBuilder,
                               final EntitlementApi entitlementApi, final EntitlementPluginExecution pluginExecution, final BlockingStateDao blockingStateDao,
                               final SubscriptionBaseInternalApi subscriptionInternalApi, final BlockingChecker checker,
                               final NotificationQueueService notificationQueueService, final EntitlementUtils entitlementUtils,
-                              final EntitlementDateHelper dateHelper, final Clock clock, final InternalCallContextFactory internalCallContextFactory) {
+                              final EntitlementDateHelper dateHelper, final Clock clock, final SecurityApi securityApi, final InternalCallContextFactory internalCallContextFactory) {
         super(eventsStream.getEntitlementId(), eventsStream.getSubscriptionBase().getCreatedDate(), eventsStream.getSubscriptionBase().getUpdatedDate());
         this.eventsStreamBuilder = eventsStreamBuilder;
         this.eventsStream = eventsStream;
@@ -105,6 +112,7 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
         this.subscriptionInternalApi = subscriptionInternalApi;
         this.internalCallContextFactory = internalCallContextFactory;
         this.clock = clock;
+        this.securityApi = securityApi;
         this.checker = checker;
         this.blockingStateDao = blockingStateDao;
         this.notificationQueueService = notificationQueueService;
@@ -123,6 +131,7 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
              in.getEntitlementUtils(),
              in.getDateHelper(),
              in.getClock(),
+             in.getSecurityApi(),
              in.getInternalCallContextFactory());
     }
 
@@ -188,6 +197,10 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
         return entitlementUtils;
     }
 
+    public SecurityApi getSecurityApi() {
+        return securityApi;
+    }
+
     @Override
     public UUID getBaseEntitlementId() {
         return eventsStream.getEntitlementId();
@@ -253,8 +266,10 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
         return getSubscriptionBase().getLastActiveCategory();
     }
 
+
     @Override
     public Entitlement cancelEntitlementWithPolicy(final EntitlementActionPolicy entitlementPolicy, final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
+
         // Get the latest state from disk - required to have the latest CTD
         refresh(callContext);
 
@@ -264,6 +279,9 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
 
     @Override
     public Entitlement cancelEntitlementWithDate(final LocalDate localCancelDate, final boolean overrideBillingEffectiveDate, final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
+
+        checkForPermissions(Permission.ENTITLEMENT_CAN_CANCEL, callContext);
+
         // Get the latest state from disk
         refresh(callContext);
 
@@ -302,6 +320,9 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
 
     @Override
     public void uncancelEntitlement(final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
+
+        checkForPermissions(Permission.ENTITLEMENT_CAN_CANCEL, callContext);
+
         // Get the latest state from disk
         refresh(callContext);
 
@@ -342,6 +363,8 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
     @Override
     public Entitlement cancelEntitlementWithDateOverrideBillingPolicy(final LocalDate localCancelDate, final BillingActionPolicy billingPolicy, final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
 
+        checkForPermissions(Permission.ENTITLEMENT_CAN_CANCEL, callContext);
+
         // Get the latest state from disk
         refresh(callContext);
 
@@ -405,6 +428,10 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
 
     @Override
     public Entitlement changePlan(final String productName, final BillingPeriod billingPeriod, final String priceList, final List<PlanPhasePriceOverride> overrides, final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
+
+
+        checkForPermissions(Permission.ENTITLEMENT_CAN_CHANGE_PLAN, callContext);
+
         // Get the latest state from disk
         refresh(callContext);
 
@@ -450,6 +477,9 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
 
     @Override
     public Entitlement changePlanWithDate(final String productName, final BillingPeriod billingPeriod, final String priceList, final List<PlanPhasePriceOverride> overrides, final LocalDate localDate, final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
+
+        checkForPermissions(Permission.ENTITLEMENT_CAN_CHANGE_PLAN, callContext);
+
         // Get the latest state from disk
         refresh(callContext);
 
@@ -495,6 +525,9 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
 
     @Override
     public Entitlement changePlanOverrideBillingPolicy(final String productName, final BillingPeriod billingPeriod, final String priceList, final List<PlanPhasePriceOverride> overrides, final LocalDate localDate, final BillingActionPolicy actionPolicy, final Iterable<PluginProperty> properties, final CallContext callContext) throws EntitlementApiException {
+
+        checkForPermissions(Permission.ENTITLEMENT_CAN_CHANGE_PLAN, callContext);
+
         // Get the latest state from disk
         refresh(callContext);
 
@@ -586,4 +619,21 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
             throw new RuntimeException(e);
         }
     }
+
+    //
+    // Unfortunately the permission checks for the entitlement api cannot *simply* rely on the KillBillShiroAopModule because some of the operations (CANCEL, CHANGE) are
+    // done through objects that are not injected by Guice, and so the check needs to happen explicitly.
+    //
+    private void checkForPermissions(final Permission permission, final CallContext callContext) throws EntitlementApiException {
+        //
+        // If authentication had been done (CorsBasicHttpAuthenticationFilter) we verify the correct permissions exist.
+        //
+        if (SecurityUtils.getSubject().isAuthenticated()) {
+            try {
+                securityApi.checkCurrentUserPermissions(ImmutableList.of(permission), Logical.AND, callContext);
+            } catch (final SecurityApiException e) {
+                throw new EntitlementApiException(ErrorCode.SECURITY_INVALID_PERMISSIONS, permission.toString());
+            }
+        }
+    }
 }
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java
index 0157fef..6f8f43a 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlementApi.java
@@ -50,6 +50,7 @@ import org.killbill.billing.entitlement.plugin.api.EntitlementContext;
 import org.killbill.billing.entitlement.plugin.api.OperationType;
 import org.killbill.billing.junction.DefaultBlockingState;
 import org.killbill.billing.payment.api.PluginProperty;
+import org.killbill.billing.security.api.SecurityApi;
 import org.killbill.billing.subscription.api.SubscriptionBase;
 import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
 import org.killbill.billing.subscription.api.transfer.SubscriptionBaseTransferApi;
@@ -96,6 +97,8 @@ public class DefaultEntitlementApi implements EntitlementApi {
     private final EntitlementUtils entitlementUtils;
     private final NotificationQueueService notificationQueueService;
     private final EntitlementPluginExecution pluginExecution;
+    private final SecurityApi securityApi;
+
 
     @Inject
     public DefaultEntitlementApi(final PersistentBus eventBus, final InternalCallContextFactory internalCallContextFactory,
@@ -103,7 +106,8 @@ public class DefaultEntitlementApi implements EntitlementApi {
                                  final AccountInternalApi accountApi, final BlockingStateDao blockingStateDao, final Clock clock,
                                  final BlockingChecker checker, final NotificationQueueService notificationQueueService,
                                  final EventsStreamBuilder eventsStreamBuilder, final EntitlementUtils entitlementUtils,
-                                 final EntitlementPluginExecution pluginExecution) {
+                                 final EntitlementPluginExecution pluginExecution,
+                                 final SecurityApi securityApi) {
         this.eventBus = eventBus;
         this.internalCallContextFactory = internalCallContextFactory;
         this.subscriptionBaseInternalApi = subscriptionInternalApi;
@@ -116,6 +120,7 @@ public class DefaultEntitlementApi implements EntitlementApi {
         this.eventsStreamBuilder = eventsStreamBuilder;
         this.entitlementUtils = entitlementUtils;
         this.pluginExecution = pluginExecution;
+        this.securityApi = securityApi;
         this.dateHelper = new EntitlementDateHelper(accountApi, clock);
     }
 
@@ -151,7 +156,7 @@ public class DefaultEntitlementApi implements EntitlementApi {
 
                     return new DefaultEntitlement(subscription.getId(), eventsStreamBuilder, entitlementApi, pluginExecution,
                                                   blockingStateDao, subscriptionBaseInternalApi, checker, notificationQueueService,
-                                                  entitlementUtils, dateHelper, clock, internalCallContextFactory, callContext);
+                                                  entitlementUtils, dateHelper, clock, securityApi, internalCallContextFactory, callContext);
                 } catch (SubscriptionBaseApiException e) {
                     throw new EntitlementApiException(e);
                 }
@@ -197,7 +202,7 @@ public class DefaultEntitlementApi implements EntitlementApi {
 
                     return new DefaultEntitlement(subscription.getId(), eventsStreamBuilder, entitlementApi, pluginExecution,
                                                   blockingStateDao, subscriptionBaseInternalApi, checker, notificationQueueService,
-                                                  entitlementUtils, dateHelper, clock, internalCallContextFactory, callContext);
+                                                  entitlementUtils, dateHelper, clock, securityApi, internalCallContextFactory, callContext);
                 } catch (SubscriptionBaseApiException e) {
                     throw new EntitlementApiException(e);
                 }
@@ -226,7 +231,7 @@ public class DefaultEntitlementApi implements EntitlementApi {
         final EventsStream eventsStream = eventsStreamBuilder.buildForEntitlement(uuid, tenantContext);
         return new DefaultEntitlement(eventsStream, eventsStreamBuilder, this, pluginExecution,
                                       blockingStateDao, subscriptionBaseInternalApi, checker, notificationQueueService,
-                                      entitlementUtils, dateHelper, clock, internalCallContextFactory);
+                                      entitlementUtils, dateHelper, clock, securityApi, internalCallContextFactory);
     }
 
     @Override
@@ -273,7 +278,7 @@ public class DefaultEntitlementApi implements EntitlementApi {
                                                               public Entitlement apply(final EventsStream eventsStream) {
                                                                   return new DefaultEntitlement(eventsStream, eventsStreamBuilder, entitlementApi, pluginExecution,
                                                                                                 blockingStateDao, subscriptionBaseInternalApi, checker, notificationQueueService,
-                                                                                                entitlementUtils, dateHelper, clock, internalCallContextFactory);
+                                                                                                entitlementUtils, dateHelper, clock, securityApi, internalCallContextFactory);
                                                               }
                                                           });
     }
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java
index b4c8459..b9fb7af 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/svcs/DefaultEntitlementInternalApi.java
@@ -27,6 +27,7 @@ import javax.inject.Inject;
 import org.killbill.billing.account.api.AccountInternalApi;
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.entitlement.api.EntitlementPluginExecution;
+import org.killbill.billing.security.api.SecurityApi;
 import org.killbill.clock.Clock;
 import org.killbill.billing.entitlement.AccountEntitlements;
 import org.killbill.billing.entitlement.AccountEventsStreams;
@@ -59,6 +60,7 @@ public class DefaultEntitlementInternalApi implements EntitlementInternalApi {
     private final EntitlementUtils entitlementUtils;
     private final NotificationQueueService notificationQueueService;
     private final EntitlementPluginExecution pluginExecution;
+    private final SecurityApi securityApi;
 
     @Inject
     public DefaultEntitlementInternalApi(final EntitlementApi entitlementApi, final EntitlementPluginExecution pluginExecution,
@@ -66,7 +68,7 @@ public class DefaultEntitlementInternalApi implements EntitlementInternalApi {
                                          final SubscriptionBaseInternalApi subscriptionInternalApi,
                                          final AccountInternalApi accountApi, final BlockingStateDao blockingStateDao, final Clock clock,
                                          final BlockingChecker checker, final NotificationQueueService notificationQueueService,
-                                         final EventsStreamBuilder eventsStreamBuilder, final EntitlementUtils entitlementUtils) {
+                                         final EventsStreamBuilder eventsStreamBuilder, final EntitlementUtils entitlementUtils, final SecurityApi securityApi) {
         this.entitlementApi = entitlementApi;
         this.pluginExecution= pluginExecution;
         this.internalCallContextFactory = internalCallContextFactory;
@@ -77,6 +79,7 @@ public class DefaultEntitlementInternalApi implements EntitlementInternalApi {
         this.notificationQueueService = notificationQueueService;
         this.eventsStreamBuilder = eventsStreamBuilder;
         this.entitlementUtils = entitlementUtils;
+        this.securityApi = securityApi;
         this.dateHelper = new EntitlementDateHelper(accountApi, clock);
     }
 
@@ -95,7 +98,7 @@ public class DefaultEntitlementInternalApi implements EntitlementInternalApi {
             for (final EventsStream eventsStream : accountEventsStreams.getEventsStreams().get(bundleId)) {
                 final Entitlement entitlement = new DefaultEntitlement(eventsStream, eventsStreamBuilder, entitlementApi, pluginExecution,
                                                                        blockingStateDao, subscriptionInternalApi, checker, notificationQueueService,
-                                                                       entitlementUtils, dateHelper, clock, internalCallContextFactory);
+                                                                       entitlementUtils, dateHelper, clock, securityApi, internalCallContextFactory);
                 entitlementsPerBundle.get(bundleId).add(entitlement);
             }
         }
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/glue/DefaultEntitlementModule.java b/entitlement/src/main/java/org/killbill/billing/entitlement/glue/DefaultEntitlementModule.java
index abb79ff..e8187b5 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/glue/DefaultEntitlementModule.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/glue/DefaultEntitlementModule.java
@@ -40,6 +40,7 @@ import org.killbill.billing.junction.BlockingInternalApi;
 import org.killbill.billing.osgi.api.OSGIServiceRegistration;
 import org.killbill.billing.platform.api.KillbillConfigSource;
 import org.killbill.billing.util.glue.KillBillModule;
+import org.killbill.billing.util.glue.SecurityModule;
 
 import com.google.inject.TypeLiteral;
 
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java b/entitlement/src/test/java/org/killbill/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java
index 760de7d..5c9770c 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/EntitlementTestSuiteWithEmbeddedDB.java
@@ -20,6 +20,15 @@ package org.killbill.billing.entitlement;
 
 import java.util.UUID;
 
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.config.Ini;
+import org.apache.shiro.config.IniSecurityManagerFactory;
+import org.apache.shiro.mgt.SecurityManager;
+import org.apache.shiro.subject.Subject;
+import org.apache.shiro.util.Factory;
+import org.apache.shiro.util.ThreadContext;
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 import org.killbill.billing.GuicyKillbillTestSuiteWithEmbeddedDB;
@@ -41,6 +50,7 @@ import org.killbill.billing.junction.BlockingInternalApi;
 import org.killbill.billing.lifecycle.api.BusService;
 import org.killbill.billing.mock.MockAccountBuilder;
 import org.killbill.billing.platform.api.KillbillConfigSource;
+import org.killbill.billing.security.Permission;
 import org.killbill.billing.subscription.api.SubscriptionBaseInternalApi;
 import org.killbill.billing.subscription.api.SubscriptionBaseService;
 import org.killbill.billing.subscription.engine.core.DefaultSubscriptionBaseService;
@@ -127,10 +137,50 @@ public class EntitlementTestSuiteWithEmbeddedDB extends GuicyKillbillTestSuiteWi
 
         // Make sure we start with a clean state
         assertListenerStatus();
+
+        configureShiro();
+        login("EntitlementUser");
+    }
+
+    private void login(final String username) {
+        logout();
+        final AuthenticationToken token = new UsernamePasswordToken(username, "password");
+        final Subject currentUser = SecurityUtils.getSubject();
+        currentUser.login(token);
+    }
+
+    private void logout() {
+        final Subject currentUser = SecurityUtils.getSubject();
+        if (currentUser.isAuthenticated()) {
+            currentUser.logout();
+        }
+    }
+
+    protected void configureShiro() {
+        final Ini config = new Ini();
+        config.addSection("users");
+        config.getSection("users").put("EntitlementUser", "password, entitlement");
+        config.addSection("roles");
+        config.getSection("roles").put("entitlement", Permission.ACCOUNT_CAN_CREATE.toString() +
+                                                      "," + Permission.ENTITLEMENT_CAN_CREATE.toString() +
+                                                      "," + Permission.ENTITLEMENT_CAN_CHANGE_PLAN.toString() +
+                                                      "," + Permission.ENTITLEMENT_CAN_PAUSE_RESUME.toString() +
+                                                      "," + Permission.ENTITLEMENT_CAN_TRANSFER.toString() +
+                                                      "," + Permission.ENTITLEMENT_CAN_CANCEL.toString());
+
+        // Reset the security manager
+        ThreadContext.unbindSecurityManager();
+
+        final Factory<SecurityManager> factory = new IniSecurityManagerFactory(config);
+        final SecurityManager securityManager = factory.getInstance();
+        SecurityUtils.setSecurityManager(securityManager);
     }
 
     @AfterMethod(groups = "slow")
     public void afterMethod() throws Exception {
+
+        logout();
+
         // Make sure we finish in a clean state
         assertListenerStatus();
 
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/glue/TestEntitlementModule.java b/entitlement/src/test/java/org/killbill/billing/entitlement/glue/TestEntitlementModule.java
index 78b500e..5b7aab2 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/glue/TestEntitlementModule.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/glue/TestEntitlementModule.java
@@ -22,6 +22,10 @@ import org.killbill.billing.mock.glue.MockTenantModule;
 import org.killbill.billing.platform.api.KillbillConfigSource;
 import org.killbill.billing.util.glue.CacheModule;
 import org.killbill.billing.util.glue.CallContextModule;
+import org.killbill.billing.util.glue.KillBillShiroAopModule;
+import org.killbill.billing.util.glue.KillBillShiroModule;
+import org.killbill.billing.util.glue.SecurityModule;
+import org.killbill.billing.util.glue.TestUtilModuleNoDB.ShiroModuleNoDB;
 
 public class TestEntitlementModule extends DefaultEntitlementModule {
 
@@ -38,5 +42,25 @@ public class TestEntitlementModule extends DefaultEntitlementModule {
         install(new CacheModule(configSource));
         install(new CallContextModule(configSource));
         install(new MockTenantModule(configSource));
+
+        install(new KillBillShiroModuleOnlyIniRealm(configSource));
+        install(new KillBillShiroAopModule());
+
+        install(new SecurityModule(configSource));
+
     }
+
+
+    private static class KillBillShiroModuleOnlyIniRealm extends KillBillShiroModule {
+
+        public KillBillShiroModuleOnlyIniRealm(final KillbillConfigSource configSource) {
+            super(configSource);
+        }
+        protected void configureJDBCRealm() {
+        }
+        protected void configureLDAPRealm() {
+        }
+
+    }
+
 }
diff --git a/junction/src/test/java/org/killbill/billing/junction/glue/TestJunctionModule.java b/junction/src/test/java/org/killbill/billing/junction/glue/TestJunctionModule.java
index 93e461b..d2bb7aa 100644
--- a/junction/src/test/java/org/killbill/billing/junction/glue/TestJunctionModule.java
+++ b/junction/src/test/java/org/killbill/billing/junction/glue/TestJunctionModule.java
@@ -29,6 +29,9 @@ import org.killbill.billing.mock.glue.MockTenantModule;
 import org.killbill.billing.platform.api.KillbillConfigSource;
 import org.killbill.billing.util.glue.CacheModule;
 import org.killbill.billing.util.glue.CallContextModule;
+import org.killbill.billing.util.glue.KillBillShiroAopModule;
+import org.killbill.billing.util.glue.KillBillShiroModule;
+import org.killbill.billing.util.glue.SecurityModule;
 
 public class TestJunctionModule extends DefaultJunctionModule {
 
@@ -43,6 +46,9 @@ public class TestJunctionModule extends DefaultJunctionModule {
         install(new CacheModule(configSource));
         install(new CallContextModule(configSource));
         install(new MockTenantModule(configSource));
+        // Needed because Entitlement depends on Security
+        install(new KillBillShiroModuleOnlyIniRealm(configSource));
+        install(new SecurityModule(configSource));
     }
 
     public class MockEntitlementModuleForJunction extends MockEntitlementModule {
@@ -66,4 +72,17 @@ public class TestJunctionModule extends DefaultJunctionModule {
             bind(BlockingChecker.class).to(MockBlockingChecker.class).asEagerSingleton();
         }
     }
+
+    private static class KillBillShiroModuleOnlyIniRealm extends KillBillShiroModule {
+
+        public KillBillShiroModuleOnlyIniRealm(final KillbillConfigSource configSource) {
+            super(configSource);
+        }
+
+        protected void configureJDBCRealm() {
+        }
+
+        protected void configureLDAPRealm() {
+        }
+    }
 }
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestSecurity.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestSecurity.java
index b7d67d8..15ca63c 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestSecurity.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestSecurity.java
@@ -21,6 +21,7 @@ package org.killbill.billing.jaxrs;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import javax.annotation.Nullable;
 import javax.ws.rs.core.Response.Status;
@@ -65,22 +66,22 @@ public class TestSecurity extends TestJaxrsBase {
 
     @Test(groups = "slow")
     public void testDynamicUserRolesAllPermissions() throws Exception {
-        testDynamicUserRolesInternal("wqeqwe", "jdsh763s", "all", "*", true);
+        testDynamicUserRolesInternal("wqeqwe", "jdsh763s", "all", ImmutableList.of("*"), true);
     }
 
     @Test(groups = "slow")
     public void testDynamicUserRolesAllCatalogPermissions() throws Exception {
-        testDynamicUserRolesInternal("wqeqsdswe", "jsddsh763s", "allcatalog", "catalog:*", true);
+        testDynamicUserRolesInternal("wqeqsdswe", "jsddsh763s", "allcatalog", ImmutableList.of("catalog:*","tenant:add_keys"), true);
     }
 
     @Test(groups = "slow")
     public void testDynamicUserRolesCorrectCatalogPermissions() throws Exception {
-        testDynamicUserRolesInternal("wqeq23f6we", "jds5gh763s", "correctcatalog", "catalog:config_upload", true);
+        testDynamicUserRolesInternal("wqeq23f6we", "jds5gh763s", "correctcatalog", ImmutableList.of("catalog:config_upload","tenant:add_keys"), true);
     }
 
     @Test(groups = "slow")
     public void testDynamicUserRolesIncorrectPermissions() throws Exception {
-        testDynamicUserRolesInternal("wqsdeqwe", "jd23fsh63s", "incorrect", "account:*", false);
+        testDynamicUserRolesInternal("wqsdeqwe", "jd23fsh63s", "incorrect", ImmutableList.of("account:*"), false);
     }
 
     @Test(groups = "slow")
@@ -176,9 +177,9 @@ public class TestSecurity extends TestJaxrsBase {
 
     }
 
-    private void testDynamicUserRolesInternal(final String username, final String password, final String roleDefinition, final String permissions, final boolean expectPermissionSuccess) throws Exception {
+    private void testDynamicUserRolesInternal(final String username, final String password, final String roleDefinition, final List<String> permissions, final boolean expectPermissionSuccess) throws Exception {
 
-        Response response = killBillClient.addRoleDefinition(new RoleDefinition(roleDefinition, ImmutableList.of(permissions)), createdBy, reason, comment);
+        Response response = killBillClient.addRoleDefinition(new RoleDefinition(roleDefinition, permissions), createdBy, reason, comment);
         Assert.assertEquals(response.getStatusCode(), 201);
 
         response = killBillClient.addUserRoles(new UserRoles(username, password, ImmutableList.of(roleDefinition)), createdBy, reason, comment);