killbill-uncached

server: first pass at implementing RBAC Design document

8/9/2013 5:57:13 PM

Changes

Details

diff --git a/.idea/dictionaries/pierre.xml b/.idea/dictionaries/pierre.xml
index 118b145..3581090 100644
--- a/.idea/dictionaries/pierre.xml
+++ b/.idea/dictionaries/pierre.xml
@@ -1,3 +1,8 @@
 <component name="ProjectDictionaryState">
-  <dictionary name="pierre" />
+  <dictionary name="pierre">
+    <words>
+      <w>jdbc</w>
+      <w>killbill</w>
+    </words>
+  </dictionary>
 </component>
\ No newline at end of file
diff --git a/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountUserApi.java b/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountUserApi.java
index 0f7717f..96d6191 100644
--- a/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountUserApi.java
+++ b/account/src/main/java/com/ning/billing/account/api/user/DefaultAccountUserApi.java
@@ -64,7 +64,7 @@ public class DefaultAccountUserApi implements AccountUserApi {
         }
 
         final AccountModelDao account = new AccountModelDao(data);
-        accountDao.create(account, internalCallContextFactory.createInternalCallContext(account.getId(), context));
+        accountDao.create(account, internalCallContextFactory.createInternalCallContext(context));
 
         return new DefaultAccount(account);
     }
diff --git a/beatrix/src/main/java/com/ning/billing/beatrix/extbus/BeatrixListener.java b/beatrix/src/main/java/com/ning/billing/beatrix/extbus/BeatrixListener.java
index d0dc22e..c7fbe39 100644
--- a/beatrix/src/main/java/com/ning/billing/beatrix/extbus/BeatrixListener.java
+++ b/beatrix/src/main/java/com/ning/billing/beatrix/extbus/BeatrixListener.java
@@ -37,6 +37,7 @@ import com.ning.billing.util.callcontext.CallOrigin;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.callcontext.UserType;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.events.AccountChangeInternalEvent;
 import com.ning.billing.util.events.AccountCreationInternalEvent;
 import com.ning.billing.util.events.BusInternalEvent;
@@ -70,17 +71,19 @@ public class
     private final PersistentBus externalBus;
     private final InternalCallContextFactory internalCallContextFactory;
     private final AccountInternalApi accountApi;
-
+    private final NonEntityDao nonEntityDao;
 
     protected final ObjectMapper objectMapper;
 
     @Inject
     public BeatrixListener(@Named(BeatrixModule.EXTERNAL_BUS) final PersistentBus externalBus,
                            final InternalCallContextFactory internalCallContextFactory,
-                           final AccountInternalApi accountApi) {
+                           final AccountInternalApi accountApi,
+                           final NonEntityDao nonEntityDao) {
         this.externalBus = externalBus;
         this.internalCallContextFactory = internalCallContextFactory;
         this.accountApi = accountApi;
+        this.nonEntityDao = nonEntityDao;
         this.objectMapper = new ObjectMapper();
         objectMapper.registerModule(new JodaModule());
         objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
@@ -224,7 +227,7 @@ public class
             default:
         }
         final UUID accountId = getAccountIdFromRecordId(event.getBusEventType(), objectId, context.getAccountRecordId(), context);
-        final UUID tenantId = context.toTenantContext().getTenantId();
+        final UUID tenantId = nonEntityDao.retrieveIdFromObject(context.getTenantRecordId(), ObjectType.TENANT);
 
         return eventBusType != null ?
                new DefaultBusExternalEvent(objectId, objectType, eventBusType, accountId, tenantId, context.getAccountRecordId(), context.getTenantRecordId(), context.getUserToken()) :
diff --git a/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java b/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
index 1e5c462..6e425a2 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
@@ -36,6 +36,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.ning.billing.ErrorCode;
+import com.ning.billing.ObjectType;
 import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountApiException;
 import com.ning.billing.bus.api.PersistentBus;
@@ -64,6 +65,9 @@ import com.ning.billing.invoice.model.FixedPriceInvoiceItem;
 import com.ning.billing.invoice.model.RecurringInvoiceItem;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.clock.Clock;
+import com.ning.billing.util.callcontext.InternalTenantContext;
+import com.ning.billing.util.callcontext.TenantContext;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.events.BusInternalEvent;
 import com.ning.billing.util.events.EffectiveSubscriptionInternalEvent;
 import com.ning.billing.util.events.InvoiceAdjustmentInternalEvent;
@@ -90,6 +94,7 @@ public class InvoiceDispatcher {
     private final AccountInternalApi accountApi;
     private final SubscriptionInternalApi subscriptionApi;
     private final InvoiceDao invoiceDao;
+    private final NonEntityDao nonEntityDao;
     private final InvoiceNotifier invoiceNotifier;
     private final GlobalLocker locker;
     private final PersistentBus eventBus;
@@ -100,6 +105,7 @@ public class InvoiceDispatcher {
                              final BillingInternalApi billingApi,
                              final SubscriptionInternalApi SubscriptionApi,
                              final InvoiceDao invoiceDao,
+                             final NonEntityDao nonEntityDao,
                              final InvoiceNotifier invoiceNotifier,
                              final GlobalLocker locker,
                              final PersistentBus eventBus,
@@ -109,6 +115,7 @@ public class InvoiceDispatcher {
         this.subscriptionApi = SubscriptionApi;
         this.accountApi = accountApi;
         this.invoiceDao = invoiceDao;
+        this.nonEntityDao = nonEntityDao;
         this.invoiceNotifier = invoiceNotifier;
         this.locker = locker;
         this.eventBus = eventBus;
@@ -255,7 +262,7 @@ public class InvoiceDispatcher {
             if (account.isNotifiedForInvoices() && invoice != null && !dryRun) {
                 // Need to re-hydrate the invoice object to get the invoice number (record id)
                 // API_FIX InvoiceNotifier public API?
-                invoiceNotifier.notify(account, new DefaultInvoice(invoiceDao.getById(invoice.getId(), context)), context.toTenantContext());
+                invoiceNotifier.notify(account, new DefaultInvoice(invoiceDao.getById(invoice.getId(), context)), buildTenantContext(context));
             }
 
             return invoice;
@@ -265,6 +272,9 @@ public class InvoiceDispatcher {
         }
     }
 
+    private TenantContext buildTenantContext(final InternalTenantContext context) {
+        return context.toTenantContext(nonEntityDao.retrieveIdFromObject(context.getTenantRecordId(), ObjectType.TENANT));
+    }
 
     @VisibleForTesting
     Map<UUID, DateTime> createNextFutureNotificationDate(final List<InvoiceItemModelDao> invoiceItems, final DateAndTimeZoneContext dateAndTimeZoneContext) {
diff --git a/invoice/src/test/java/com/ning/billing/invoice/InvoiceTestSuiteWithEmbeddedDB.java b/invoice/src/test/java/com/ning/billing/invoice/InvoiceTestSuiteWithEmbeddedDB.java
index 33b5b93..93a00f4 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/InvoiceTestSuiteWithEmbeddedDB.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/InvoiceTestSuiteWithEmbeddedDB.java
@@ -43,6 +43,7 @@ import com.ning.billing.util.api.TagUserApi;
 import com.ning.billing.util.cache.CacheControllerDispatcher;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.clock.Clock;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.svcapi.account.AccountInternalApi;
 import com.ning.billing.util.svcapi.subscription.SubscriptionInternalApi;
 import com.ning.billing.util.svcapi.invoice.InvoiceInternalApi;
@@ -84,6 +85,8 @@ public abstract class InvoiceTestSuiteWithEmbeddedDB extends GuicyKillbillTestSu
     @Inject
     protected InvoiceDao invoiceDao;
     @Inject
+    protected NonEntityDao nonEntityDao;
+    @Inject
     protected TagUserApi tagUserApi;
     @Inject
     protected GlobalLocker locker;
diff --git a/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java b/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
index 467cf0a..90fbb11 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceDispatcher.java
@@ -89,7 +89,7 @@ public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
 
         final InvoiceNotifier invoiceNotifier = new NullInvoiceNotifier();
         final InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountApi, billingApi, subscriptionApi, invoiceDao,
-                                                                   invoiceNotifier, locker, busService.getBus(),
+                                                                   nonEntityDao, invoiceNotifier, locker, busService.getBus(),
                                                                    clock);
 
         Invoice invoice = dispatcher.processAccount(accountId, target, true, internalCallContext);
@@ -143,7 +143,7 @@ public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
         Mockito.when(billingApi.getBillingEventsForAccountAndUpdateAccountBCD(Mockito.<UUID>any(), Mockito.<InternalCallContext>any())).thenReturn(events);
         final InvoiceNotifier invoiceNotifier = new NullInvoiceNotifier();
         final InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountApi, billingApi, subscriptionApi, invoiceDao,
-                                                                   invoiceNotifier, locker, busService.getBus(),
+                                                                   nonEntityDao, invoiceNotifier, locker, busService.getBus(),
                                                                    clock);
 
         final Invoice invoice = dispatcher.processAccount(account.getId(), new DateTime("2012-07-30T00:00:00.000Z"), false, internalCallContext);
@@ -203,7 +203,7 @@ public class TestInvoiceDispatcher extends InvoiceTestSuiteWithEmbeddedDB {
 
         final InvoiceNotifier invoiceNotifier = new NullInvoiceNotifier();
         final InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountApi, billingApi, subscriptionApi, invoiceDao,
-                                                                   invoiceNotifier, locker, busService.getBus(),
+                                                                   nonEntityDao, invoiceNotifier, locker, busService.getBus(),
                                                                    clock);
 
         final DateTime expectedBefore = clock.getUTCNow();
diff --git a/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceHelper.java b/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceHelper.java
index e2d5357..d078351 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceHelper.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/TestInvoiceHelper.java
@@ -60,6 +60,7 @@ import com.ning.billing.subscription.api.user.SubscriptionUserApiException;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
 import com.ning.billing.clock.Clock;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.entity.EntityPersistenceException;
 import com.ning.billing.util.svcapi.account.AccountInternalApi;
 import com.ning.billing.util.svcapi.subscription.SubscriptionInternalApi;
@@ -135,6 +136,7 @@ public class TestInvoiceHelper {
     private final GlobalLocker locker;
     private final  Clock clock;
     private final InternalCallContext internalCallContext;
+    private final NonEntityDao nonEntityDao;
 
     // Low level SqlDao used by the tests to directly insert rows
     private final InvoicePaymentSqlDao invoicePaymentSqlDao;
@@ -145,7 +147,7 @@ public class TestInvoiceHelper {
     @Inject
     public TestInvoiceHelper(final InvoiceGenerator generator, final IDBI dbi,
                              final BillingInternalApi billingApi, final AccountInternalApi accountApi, final SubscriptionInternalApi subscriptionApi, final BusService busService,
-                             final InvoiceDao invoiceDao, final GlobalLocker locker, final Clock clock, final InternalCallContext internalCallContext) {
+                             final InvoiceDao invoiceDao, final GlobalLocker locker, final Clock clock, final InternalCallContext internalCallContext, final NonEntityDao nonEntityDao) {
         this.generator = generator;
         this.billingApi = billingApi;
         this.accountApi = accountApi;
@@ -155,6 +157,7 @@ public class TestInvoiceHelper {
         this.locker = locker;
         this.clock = clock;
         this.internalCallContext = internalCallContext;
+        this.nonEntityDao = nonEntityDao;
         this.invoiceItemSqlDao = dbi.onDemand(InvoiceItemSqlDao.class);
         this.invoicePaymentSqlDao = dbi.onDemand(InvoicePaymentSqlDao.class);
     }
@@ -177,7 +180,7 @@ public class TestInvoiceHelper {
 
         final InvoiceNotifier invoiceNotifier = new NullInvoiceNotifier();
         final InvoiceDispatcher dispatcher = new InvoiceDispatcher(generator, accountApi, billingApi, subscriptionApi,
-                                                                   invoiceDao, invoiceNotifier, locker, busService.getBus(),
+                                                                   invoiceDao, nonEntityDao, invoiceNotifier, locker, busService.getBus(),
                                                                    clock);
 
         Invoice invoice = dispatcher.processAccount(account.getId(), targetDate, true, internalCallContext);
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxrsResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxrsResource.java
index fc53f23..c1c2817 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxrsResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/JaxrsResource.java
@@ -29,6 +29,12 @@ public interface JaxrsResource {
     public static final String SEARCH = "search";
 
     /*
+     * Multi-Tenancy headers
+     */
+    public static String HDR_API_KEY = "X-Killbill-ApiKey";
+    public static String HDR_API_SECRET = "X-Killbill-ApiSecret";
+
+    /*
      * Metadata Additional headers
      */
     public static String HDR_CREATED_BY = "X-Killbill-CreatedBy";
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/util/Context.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/util/Context.java
index 18b95b7..6776382 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/util/Context.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/util/Context.java
@@ -67,6 +67,7 @@ public class Context {
     }
 
     private Tenant getTenantFromRequest(final ServletRequest request) {
+        // See com.ning.billing.server.security.TenantFilter
         final Object tenantObject = request.getAttribute("killbill_tenant");
         if (tenantObject == null) {
             return null;
diff --git a/payment/src/main/java/com/ning/billing/payment/core/PaymentMethodProcessor.java b/payment/src/main/java/com/ning/billing/payment/core/PaymentMethodProcessor.java
index c2b3e15..c72e410 100644
--- a/payment/src/main/java/com/ning/billing/payment/core/PaymentMethodProcessor.java
+++ b/payment/src/main/java/com/ning/billing/payment/core/PaymentMethodProcessor.java
@@ -50,6 +50,7 @@ import com.ning.billing.payment.provider.DefaultPaymentMethodInfoPlugin;
 import com.ning.billing.payment.provider.ExternalPaymentProviderPlugin;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.svcapi.account.AccountInternalApi;
 import com.ning.billing.util.svcapi.invoice.InvoiceInternalApi;
 import com.ning.billing.util.svcapi.tag.TagInternalApi;
@@ -72,10 +73,11 @@ public class PaymentMethodProcessor extends ProcessorBase {
                                   final InvoiceInternalApi invoiceApi,
                                   final PersistentBus eventBus,
                                   final PaymentDao paymentDao,
+                                  final NonEntityDao nonEntityDao,
                                   final TagInternalApi tagUserApi,
                                   final GlobalLocker locker,
                                   @Named(PLUGIN_EXECUTOR_NAMED) final ExecutorService executor) {
-        super(pluginRegistry, accountInternalApi, eventBus, paymentDao, tagUserApi, locker, executor, invoiceApi);
+        super(pluginRegistry, accountInternalApi, eventBus, paymentDao, nonEntityDao, tagUserApi, locker, executor, invoiceApi);
     }
 
     public Set<String> getAvailablePlugins() {
@@ -139,7 +141,7 @@ public class PaymentMethodProcessor extends ProcessorBase {
         if (withPluginInfo) {
             try {
                 final PaymentPluginApi pluginApi = getPaymentPluginApi(paymentMethodModelDao.getPluginName());
-                paymentMethodPlugin = pluginApi.getPaymentMethodDetail(paymentMethodModelDao.getAccountId(), paymentMethodModelDao.getId(), context.toTenantContext());
+                paymentMethodPlugin = pluginApi.getPaymentMethodDetail(paymentMethodModelDao.getAccountId(), paymentMethodModelDao.getId(), buildTenantContext(context));
             } catch (PaymentPluginApiException e) {
                 log.warn("Error retrieving payment method " + paymentMethodModelDao.getId() + " from plugin " + paymentMethodModelDao.getPluginName(), e);
                 throw new PaymentApiException(ErrorCode.PAYMENT_GET_PAYMENT_METHODS, paymentMethodModelDao.getAccountId(), paymentMethodModelDao.getId());
@@ -171,7 +173,7 @@ public class PaymentMethodProcessor extends ProcessorBase {
         final PaymentPluginApi pluginApi = getPaymentPluginApi(pluginName);
         final List<PaymentMethodPlugin> paymentMethods;
         try {
-            paymentMethods = pluginApi.searchPaymentMethods(searchKey, internalTenantContext.toTenantContext());
+            paymentMethods = pluginApi.searchPaymentMethods(searchKey, buildTenantContext(internalTenantContext));
         } catch (PaymentPluginApiException e) {
             throw new PaymentApiException(e, ErrorCode.PAYMENT_PLUGIN_SEARCH_PAYMENT_METHODS, pluginName, searchKey);
         }
diff --git a/payment/src/main/java/com/ning/billing/payment/core/PaymentProcessor.java b/payment/src/main/java/com/ning/billing/payment/core/PaymentProcessor.java
index 13c1b27..81ea1b5 100644
--- a/payment/src/main/java/com/ning/billing/payment/core/PaymentProcessor.java
+++ b/payment/src/main/java/com/ning/billing/payment/core/PaymentProcessor.java
@@ -20,6 +20,7 @@ import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
 import com.google.inject.name.Named;
 import com.ning.billing.ErrorCode;
+import com.ning.billing.ObjectType;
 import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountApiException;
 import com.ning.billing.bus.api.PersistentBus;
@@ -48,7 +49,9 @@ import com.ning.billing.payment.retry.FailedPaymentRetryService.FailedPaymentRet
 import com.ning.billing.payment.retry.PluginFailureRetryService.PluginFailureRetryServiceScheduler;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
+import com.ning.billing.util.callcontext.TenantContext;
 import com.ning.billing.util.config.PaymentConfig;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.events.BusInternalEvent;
 import com.ning.billing.util.events.PaymentErrorInternalEvent;
 import com.ning.billing.util.svcapi.account.AccountInternalApi;
@@ -99,12 +102,13 @@ public class PaymentProcessor extends ProcessorBase {
                             final PluginFailureRetryServiceScheduler pluginFailureRetryService,
                             final AutoPayRetryServiceScheduler autoPayoffRetryService,
                             final PaymentDao paymentDao,
+                            final NonEntityDao nonEntityDao,
                             final PersistentBus eventBus,
                             final Clock clock,
                             final GlobalLocker locker,
                             final PaymentConfig paymentConfig,
                             @Named(PLUGIN_EXECUTOR_NAMED) final ExecutorService executor) {
-        super(pluginRegistry, accountUserApi, eventBus, paymentDao, tagUserApi, locker, executor, invoiceApi);
+        super(pluginRegistry, accountUserApi, eventBus, paymentDao, nonEntityDao, tagUserApi, locker, executor, invoiceApi);
         this.paymentMethodProcessor = paymentMethodProcessor;
         this.failedPaymentRetryService = failedPaymentRetryService;
         this.pluginFailureRetryService = pluginFailureRetryService;
@@ -125,7 +129,7 @@ public class PaymentProcessor extends ProcessorBase {
         PaymentInfoPlugin pluginInfo = null;
         if (plugin != null) {
             try {
-                pluginInfo = plugin.getPaymentInfo(model.getAccountId(), paymentId, context.toTenantContext());
+                pluginInfo = plugin.getPaymentInfo(model.getAccountId(), paymentId, buildTenantContext(context));
             } catch (PaymentPluginApiException e) {
                 throw new PaymentApiException(ErrorCode.PAYMENT_PLUGIN_GET_PAYMENT_INFO, paymentId, e.toString());
             }
@@ -133,7 +137,6 @@ public class PaymentProcessor extends ProcessorBase {
         return fromPaymentModelDao(model, pluginInfo, context);
     }
 
-
     public List<Payment> getInvoicePayments(final UUID invoiceId, final InternalTenantContext context) {
         return getPayments(paymentDao.getPaymentsForInvoice(invoiceId, context), context);
     }
diff --git a/payment/src/main/java/com/ning/billing/payment/core/ProcessorBase.java b/payment/src/main/java/com/ning/billing/payment/core/ProcessorBase.java
index 7d0801c..2b67354 100644
--- a/payment/src/main/java/com/ning/billing/payment/core/ProcessorBase.java
+++ b/payment/src/main/java/com/ning/billing/payment/core/ProcessorBase.java
@@ -44,6 +44,8 @@ import com.ning.billing.payment.plugin.api.PaymentPluginApi;
 import com.ning.billing.util.api.TagApiException;
 import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalTenantContext;
+import com.ning.billing.util.callcontext.TenantContext;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.events.BusInternalEvent;
 import com.ning.billing.util.globallocker.LockerType;
 import com.ning.billing.util.svcapi.account.AccountInternalApi;
@@ -65,6 +67,7 @@ public abstract class ProcessorBase {
     protected final GlobalLocker locker;
     protected final ExecutorService executor;
     protected final PaymentDao paymentDao;
+    protected final NonEntityDao nonEntityDao;
     protected final TagInternalApi tagInternalApi;
 
     private static final Logger log = LoggerFactory.getLogger(ProcessorBase.class);
@@ -74,6 +77,7 @@ public abstract class ProcessorBase {
                          final AccountInternalApi accountInternalApi,
                          final PersistentBus eventBus,
                          final PaymentDao paymentDao,
+                         final NonEntityDao nonEntityDao,
                          final TagInternalApi tagInternalApi,
                          final GlobalLocker locker,
                          final ExecutorService executor, final InvoiceInternalApi invoiceApi) {
@@ -81,6 +85,7 @@ public abstract class ProcessorBase {
         this.accountInternalApi = accountInternalApi;
         this.eventBus = eventBus;
         this.paymentDao = paymentDao;
+        this.nonEntityDao = nonEntityDao;
         this.locker = locker;
         this.executor = executor;
         this.tagInternalApi = tagInternalApi;
@@ -150,6 +155,10 @@ public abstract class ProcessorBase {
         return invoice;
     }
 
+    protected TenantContext buildTenantContext(final InternalTenantContext context) {
+        return context.toTenantContext(nonEntityDao.retrieveIdFromObject(context.getTenantRecordId(), ObjectType.TENANT));
+    }
+
     public interface WithAccountLockCallback<T> {
 
         public T doOperation() throws PaymentApiException;
diff --git a/payment/src/main/java/com/ning/billing/payment/core/RefundProcessor.java b/payment/src/main/java/com/ning/billing/payment/core/RefundProcessor.java
index 3e529b5..413a9c5 100644
--- a/payment/src/main/java/com/ning/billing/payment/core/RefundProcessor.java
+++ b/payment/src/main/java/com/ning/billing/payment/core/RefundProcessor.java
@@ -56,6 +56,7 @@ import com.ning.billing.util.callcontext.InternalCallContext;
 import com.ning.billing.util.callcontext.InternalCallContextFactory;
 import com.ning.billing.util.callcontext.InternalTenantContext;
 import com.ning.billing.util.callcontext.UserType;
+import com.ning.billing.util.dao.NonEntityDao;
 import com.ning.billing.util.svcapi.account.AccountInternalApi;
 import com.ning.billing.util.svcapi.invoice.InvoiceInternalApi;
 import com.ning.billing.util.svcapi.tag.TagInternalApi;
@@ -83,9 +84,10 @@ public class RefundProcessor extends ProcessorBase {
                            final InternalCallContextFactory internalCallContextFactory,
                            final TagInternalApi tagUserApi,
                            final PaymentDao paymentDao,
+                           final NonEntityDao nonEntityDao,
                            final GlobalLocker locker,
                            @Named(PLUGIN_EXECUTOR_NAMED) final ExecutorService executor) {
-        super(pluginRegistry, accountApi, eventBus, paymentDao, tagUserApi, locker, executor, invoiceApi);
+        super(pluginRegistry, accountApi, eventBus, paymentDao, nonEntityDao, tagUserApi, locker, executor, invoiceApi);
         this.internalCallContextFactory = internalCallContextFactory;
     }
 
diff --git a/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceListener.java b/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceListener.java
index 6337238..ba05640 100644
--- a/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceListener.java
+++ b/server/src/main/java/com/ning/billing/server/listeners/KillbillGuiceListener.java
@@ -66,7 +66,7 @@ public class KillbillGuiceListener extends SetupServer {
 
     @Override
     public void contextInitialized(final ServletContextEvent event) {
-        final boolean multitenant = Boolean.parseBoolean(System.getProperty(KILLBILL_MULTITENANT_PROPERTY, "false"));
+        final boolean multitenant = Boolean.parseBoolean(System.getProperty(KILLBILL_MULTITENANT_PROPERTY, "true"));
 
         final ServerModuleBuilder builder = new ServerModuleBuilder()
                 .addConfig(KillbillServerConfig.class)
diff --git a/server/src/main/java/com/ning/billing/server/security/TenantFilter.java b/server/src/main/java/com/ning/billing/server/security/TenantFilter.java
index 98a77aa..2eaa1a4 100644
--- a/server/src/main/java/com/ning/billing/server/security/TenantFilter.java
+++ b/server/src/main/java/com/ning/billing/server/security/TenantFilter.java
@@ -26,20 +26,28 @@ import javax.servlet.FilterConfig;
 import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 
-import org.apache.shiro.SecurityUtils;
-import org.apache.shiro.subject.Subject;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
+import org.apache.shiro.realm.Realm;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.ning.billing.jaxrs.resources.JaxrsResource;
 import com.ning.billing.tenant.api.Tenant;
 import com.ning.billing.tenant.api.TenantApiException;
 import com.ning.billing.tenant.api.TenantUserApi;
 
+import com.google.common.collect.ImmutableList;
+
 @Singleton
 public class TenantFilter implements Filter {
 
-    public static final String SUBJECT = "killbill_subject";
+    // See com.ning.billing.jaxrs.util.Context
     public static final String TENANT = "killbill_tenant";
 
     private static final Logger log = LoggerFactory.getLogger(TenantFilter.class);
@@ -47,23 +55,55 @@ public class TenantFilter implements Filter {
     @Inject
     private TenantUserApi tenantUserApi;
 
+    private final ModularRealmAuthenticator modularRealmAuthenticator;
+
+    public TenantFilter() {
+        final Realm killbillJdbcRealm = new KillbillJdbcRealm();
+
+        // We use Shiro to verify the api credentials - but the Shiro Subject is only used for RBAC
+        modularRealmAuthenticator = new ModularRealmAuthenticator();
+        modularRealmAuthenticator.setRealms(ImmutableList.<Realm>of(killbillJdbcRealm));
+    }
+
     @Override
     public void init(final FilterConfig filterConfig) throws ServletException {
     }
 
     @Override
     public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
-        final Subject subject = SecurityUtils.getSubject();
-        request.setAttribute(SUBJECT, subject);
-
-        final String apiKey = (String) subject.getPrincipal();
-        if (apiKey == null) {
-            // Resource not protected by Shiro?
+        if (shouldSkipFilter(request)) {
             chain.doFilter(request, response);
             return;
         }
 
+        // Lookup tenant information in the headers
+        String apiKey = null;
+        String apiSecret = null;
+        if (request instanceof HttpServletRequest) {
+            final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
+            apiKey = httpServletRequest.getHeader(JaxrsResource.HDR_API_KEY);
+            apiSecret = httpServletRequest.getHeader(JaxrsResource.HDR_API_SECRET);
+        }
+
+        // Multi-tenancy is enabled if this filter is installed, we can't continue without credentials
+        if (apiKey == null || apiSecret == null) {
+            final String errorMessage = String.format("Make sure to set the %s and %s headers", JaxrsResource.HDR_API_KEY, JaxrsResource.HDR_API_SECRET);
+            sendAuthError(response, errorMessage);
+            return;
+        }
+
+        // Verify the apiKey/apiSecret combo
+        final AuthenticationToken token = new UsernamePasswordToken(apiKey, apiSecret);
         try {
+            modularRealmAuthenticator.authenticate(token);
+        } catch (AuthenticationException e) {
+            final String errorMessage = e.getLocalizedMessage();
+            sendAuthError(response, errorMessage);
+            return;
+        }
+
+        try {
+            // Load the tenant in the request object (apiKey is unique across tenants)
             final Tenant tenant = tenantUserApi.getTenantByApiKey(apiKey);
             request.setAttribute(TENANT, tenant);
 
@@ -77,4 +117,26 @@ public class TenantFilter implements Filter {
     @Override
     public void destroy() {
     }
+
+    private boolean shouldSkipFilter(final ServletRequest request) {
+        boolean shouldSkip = false;
+
+        // Chicken - egg problem
+        if (request instanceof HttpServletRequest) {
+            final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
+            final String path = httpServletRequest.getRequestURI();
+            if ("/1.0/kb/tenants".equals(path) && "POST".equals(httpServletRequest.getMethod())) {
+                shouldSkip = true;
+            }
+        }
+
+        return shouldSkip;
+    }
+
+    private void sendAuthError(final ServletResponse response, final String errorMessage) throws IOException {
+        if (response instanceof HttpServletResponse) {
+            final HttpServletResponse httpServletResponse = (HttpServletResponse) response;
+            httpServletResponse.sendError(401, errorMessage);
+        }
+    }
 }
diff --git a/server/src/test/java/com/ning/billing/jaxrs/KillbillClient.java b/server/src/test/java/com/ning/billing/jaxrs/KillbillClient.java
index 80d7944..4534858 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/KillbillClient.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/KillbillClient.java
@@ -78,6 +78,8 @@ import com.google.common.collect.ImmutableMap;
 
 import static com.ning.billing.jaxrs.resources.JaxrsResource.ACCOUNTS;
 import static com.ning.billing.jaxrs.resources.JaxrsResource.BUNDLES;
+import static com.ning.billing.jaxrs.resources.JaxrsResource.HDR_API_KEY;
+import static com.ning.billing.jaxrs.resources.JaxrsResource.HDR_API_SECRET;
 import static com.ning.billing.jaxrs.resources.JaxrsResource.QUERY_DELETE_DEFAULT_PM_WITH_AUTO_PAY_OFF;
 import static com.ning.billing.jaxrs.resources.JaxrsResource.SUBSCRIPTIONS;
 import static org.testng.Assert.assertEquals;
@@ -87,7 +89,7 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
 
     protected static final String PLUGIN_NAME = "noop";
 
-    protected static final int DEFAULT_HTTP_TIMEOUT_SEC = 5;
+    protected static final int DEFAULT_HTTP_TIMEOUT_SEC = 20;
 
     protected static final Map<String, String> DEFAULT_EMPTY_QUERY = new HashMap<String, String>();
 
@@ -102,6 +104,12 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
     protected AsyncHttpClient httpClient;
     protected ObjectMapper mapper;
 
+    // Multi-Tenancy information, if enabled
+    protected String DEFAULT_API_KEY = UUID.randomUUID().toString();
+    protected String DEFAULT_API_SECRET = UUID.randomUUID().toString();
+    protected String apiKey = DEFAULT_API_KEY;
+    protected String apiSecret = DEFAULT_API_SECRET;
+
     // Context information to be passed around
     protected static final String createdBy = "Toto";
     protected static final String reason = "i am god";
@@ -1031,6 +1039,8 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
         }
 
         builder.addHeader(HEADER_CONTENT_TYPE, CONTENT_TYPE);
+        builder.addHeader(HDR_API_KEY, apiKey);
+        builder.addHeader(HDR_API_SECRET, apiSecret);
         for (final Entry<String, String> q : queryParams.entrySet()) {
             builder.addQueryParameter(q.getKey(), q.getValue());
         }
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java b/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java
index 73b0a44..239c4d3 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestAccount.java
@@ -257,7 +257,8 @@ public class TestAccount extends TestJaxrsBase {
 
     @Test(groups = "slow")
     public void testTags() throws Exception {
-        final String accountId = UUID.randomUUID().toString();
+        final AccountJson input = createAccount();
+        final String accountId = input.getAccountId();
         final String uri = JaxrsResource.ACCOUNTS_PATH + "/" + accountId + "/" + JaxrsResource.TAGS;
         final String accountTagsUrl = getUrlFromUri(uri);
         // Use tag definition for AUTO_PAY_OFF
@@ -287,7 +288,6 @@ public class TestAccount extends TestJaxrsBase {
 
     @Test(groups = "slow")
     public void testCustomFields() throws Exception {
-
         final AccountJson accountJson = createAccount("yoyoq", "gfgrqe", "yoyoq@yahoo.com");
         assertNotNull(accountJson);
 
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java b/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
index e1dff41..34ea64e 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
@@ -234,6 +234,9 @@ public class TestJaxrsBase extends KillbillClient {
         busHandler.reset();
         clock.resetDeltaFromReality();
         clock.setDay(new LocalDate(2012, 8, 25));
+
+        // Recreate the tenant (tables have been cleaned-up)
+        createTenant(DEFAULT_API_KEY, DEFAULT_API_SECRET);
     }
 
     @AfterMethod(groups = "slow")
@@ -246,16 +249,14 @@ public class TestJaxrsBase extends KillbillClient {
     public void beforeClass() throws Exception {
         loadConfig();
 
-
         listener.getInstantiatedInjector().injectMembers(this);
 
         httpClient = new AsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(DEFAULT_HTTP_TIMEOUT_SEC * 1000).build());
+
         mapper = new ObjectMapper();
         mapper.registerModule(new JodaModule());
         mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
 
-        //mapper.setPropertyNamingStrategy(new PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy());
-
         busHandler = new TestApiListener(null, dbi);
     }
 
@@ -277,13 +278,10 @@ public class TestJaxrsBase extends KillbillClient {
         loadConfig();
 
         listener = new TestKillbillGuiceListener(helper);
-        server = new HttpServer();
 
+        server = new HttpServer();
         server.configure(config, getListeners(), getFilters());
-
         server.start();
-
-        listener.getInstantiatedInjector().injectMembers(this);
     }
 
     protected Iterable<EventListener> getListeners() {
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestPushNotification.java b/server/src/test/java/com/ning/billing/jaxrs/TestPushNotification.java
index 83ab8cf..68d5a6d 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestPushNotification.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestPushNotification.java
@@ -68,7 +68,7 @@ public class TestPushNotification extends TestJaxrsBase {
 
     private boolean waitForCallbacksToComplete() throws InterruptedException {
 
-        long remainingMs = 5000;
+        long remainingMs = 20000;
         do {
             if (callbackCompleted) {
                 break;
diff --git a/server/src/test/java/com/ning/billing/server/security/TestTenantFilter.java b/server/src/test/java/com/ning/billing/server/security/TestTenantFilter.java
index d4a0dbf..ef60130 100644
--- a/server/src/test/java/com/ning/billing/server/security/TestTenantFilter.java
+++ b/server/src/test/java/com/ning/billing/server/security/TestTenantFilter.java
@@ -16,56 +16,30 @@
 
 package com.ning.billing.server.security;
 
-import java.util.EventListener;
-import java.util.Iterator;
-import java.util.Map;
-
 import javax.ws.rs.core.Response.Status;
 
-import org.apache.shiro.web.env.EnvironmentLoaderListener;
-import org.apache.shiro.web.servlet.ShiroFilter;
-import org.eclipse.jetty.servlet.FilterHolder;
 import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import com.ning.billing.jaxrs.TestJaxrsBase;
 import com.ning.billing.jaxrs.json.AccountJson;
 import com.ning.billing.server.listeners.KillbillGuiceListener;
-import com.ning.http.client.AsyncHttpClient;
-import com.ning.http.client.AsyncHttpClientConfig;
-import com.ning.http.client.Realm;
-import com.ning.http.client.Realm.AuthScheme;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
 
-public class TestTenantFilter extends TestJaxrsBase  {
-
-    @Override
-    protected void loadConfig() {
-        System.setProperty(KillbillGuiceListener.KILLBILL_MULTITENANT_PROPERTY, "true");
-        super.loadConfig();
-    }
+// Pure Multi-Tenancy test (no RBAC)
+public class TestTenantFilter extends TestJaxrsBase {
 
-    @Override
-    protected Iterable<EventListener> getListeners() {
-        return new Iterable<EventListener>() {
-            @Override
-            public Iterator<EventListener> iterator() {
-                return ImmutableList.<EventListener>of(listener, new EnvironmentLoaderListener()).iterator();
-            }
-        };
+    @AfterMethod(groups = "slow")
+    public void tearDown() throws Exception {
+        // Default credentials
+        loginTenant(DEFAULT_API_KEY, DEFAULT_API_SECRET);
     }
 
-    @Override
-    protected Map<FilterHolder, String> getFilters() {
-        return ImmutableMap.<FilterHolder, String>of(new FilterHolder(ShiroFilter.class), "/*");
-    }
-
-    // TODO Need to run by itself for now as the server from the test suite doesn't have the Shiro setup
-    @Test(groups = "slow", enabled = false)
+    @Test(groups = "slow")
     public void testTenantShouldOnlySeeOwnAccount() throws Exception {
         // Try to create an account without being logged-in
+        logoutTenant();
         Assert.assertEquals(createAccountNoValidation().getStatusCode(), Status.UNAUTHORIZED.getStatusCode());
 
         // Create the tenant
@@ -105,18 +79,12 @@ public class TestTenantFilter extends TestJaxrsBase  {
     }
 
     private void loginTenant(final String apiKey, final String apiSecret) {
-        final AsyncHttpClientConfig.Builder builder = new AsyncHttpClientConfig.Builder();
-        final Realm realm = new Realm.RealmBuilder()
-                .setPrincipal(apiKey)
-                .setPassword(apiSecret)
-                .setUsePreemptiveAuth(true)
-                .setScheme(AuthScheme.BASIC)
-                .build();
-        builder.setRealm(realm).setRequestTimeoutInMs(DEFAULT_HTTP_TIMEOUT_SEC * 1000).build();
-        httpClient = new AsyncHttpClient(builder.build());
+        this.apiKey = apiKey;
+        this.apiSecret = apiSecret;
     }
 
     private void logoutTenant() {
-        httpClient = new AsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(DEFAULT_HTTP_TIMEOUT_SEC * 1000).build());
+        apiKey = "";
+        apiSecret = "";
     }
 }
diff --git a/util/src/main/java/com/ning/billing/util/callcontext/DefaultTenantContext.java b/util/src/main/java/com/ning/billing/util/callcontext/DefaultTenantContext.java
index 4d072d2..a6dbf20 100644
--- a/util/src/main/java/com/ning/billing/util/callcontext/DefaultTenantContext.java
+++ b/util/src/main/java/com/ning/billing/util/callcontext/DefaultTenantContext.java
@@ -24,10 +24,6 @@ public class DefaultTenantContext implements TenantContext {
 
     private final UUID tenantId;
 
-    public DefaultTenantContext() {
-        this(null);
-    }
-
     public DefaultTenantContext(@Nullable final UUID tenantId) {
         this.tenantId = tenantId;
     }
diff --git a/util/src/main/java/com/ning/billing/util/callcontext/InternalTenantContext.java b/util/src/main/java/com/ning/billing/util/callcontext/InternalTenantContext.java
index 5454264..7dacd5e 100644
--- a/util/src/main/java/com/ning/billing/util/callcontext/InternalTenantContext.java
+++ b/util/src/main/java/com/ning/billing/util/callcontext/InternalTenantContext.java
@@ -16,6 +16,8 @@
 
 package com.ning.billing.util.callcontext;
 
+import java.util.UUID;
+
 import javax.annotation.Nullable;
 
 /**
@@ -35,8 +37,8 @@ public class InternalTenantContext {
         this(defaultTenantRecordId, null);
     }
 
-    public TenantContext toTenantContext() {
-        return new DefaultTenantContext();
+    public TenantContext toTenantContext(final UUID tenantId) {
+        return new DefaultTenantContext(tenantId);
     }
 
     public Long getAccountRecordId() {
diff --git a/util/src/main/java/com/ning/billing/util/dao/DefaultNonEntityDao.java b/util/src/main/java/com/ning/billing/util/dao/DefaultNonEntityDao.java
index 232983e..5631dbc 100644
--- a/util/src/main/java/com/ning/billing/util/dao/DefaultNonEntityDao.java
+++ b/util/src/main/java/com/ning/billing/util/dao/DefaultNonEntityDao.java
@@ -103,6 +103,11 @@ public class DefaultNonEntityDao implements NonEntityDao {
         return nonEntitySqlDao.getHistoryTargetRecordId(recordId, tableName.getTableName());
     }
 
+    @Override
+    public UUID retrieveIdFromObject(final Long recordId, final ObjectType objectType) {
+        final TableName tableName = TableName.fromObjectType(objectType);
+        return nonEntitySqlDao.getIdFromObject(recordId, tableName.getTableName());
+    }
 
     private interface OperationRetrieval<T> {
         public T doRetrieve(final UUID objectId, final ObjectType objectType);
diff --git a/util/src/main/java/com/ning/billing/util/dao/NonEntityDao.java b/util/src/main/java/com/ning/billing/util/dao/NonEntityDao.java
index 26be4a4..58f7ae3 100644
--- a/util/src/main/java/com/ning/billing/util/dao/NonEntityDao.java
+++ b/util/src/main/java/com/ning/billing/util/dao/NonEntityDao.java
@@ -39,6 +39,8 @@ public interface NonEntityDao {
     // This retrieves from the history table the latest record for which targetId matches the one we are passing
     public Long retrieveLastHistoryRecordIdFromTransaction(final Long targetRecordId, final TableName tableName, final NonEntitySqlDao transactional);
 
-    //This is the reverse from retrieveLastHistoryRecordIdFromTransaction; this retrieves the record_id of the object matching a given history row
+    // This is the reverse from retrieveLastHistoryRecordIdFromTransaction; this retrieves the record_id of the object matching a given history row
     public Long retrieveHistoryTargetRecordId(final Long recordId, final TableName tableName);
+
+    public UUID retrieveIdFromObject(final Long recordId, final ObjectType objectType);
 }
diff --git a/util/src/main/java/com/ning/billing/util/dao/NonEntitySqlDao.java b/util/src/main/java/com/ning/billing/util/dao/NonEntitySqlDao.java
index f0a119d..36d7811 100644
--- a/util/src/main/java/com/ning/billing/util/dao/NonEntitySqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/dao/NonEntitySqlDao.java
@@ -16,6 +16,8 @@
 
 package com.ning.billing.util.dao;
 
+import java.util.UUID;
+
 import org.skife.jdbi.v2.sqlobject.Bind;
 import org.skife.jdbi.v2.sqlobject.SqlQuery;
 import org.skife.jdbi.v2.sqlobject.customizers.Define;
@@ -30,6 +32,9 @@ public interface NonEntitySqlDao extends Transactional<NonEntitySqlDao>, CloseMe
     public Long getRecordIdFromObject(@Bind("id") String id, @Define("tableName") final String tableName);
 
     @SqlQuery
+    public UUID getIdFromObject(@Bind("recordId") Long recordId, @Define("tableName") final String tableName);
+
+    @SqlQuery
     public Long getAccountRecordIdFromAccount(@Bind("id") String id);
 
     @SqlQuery
diff --git a/util/src/main/resources/com/ning/billing/util/dao/NonEntitySqlDao.sql.stg b/util/src/main/resources/com/ning/billing/util/dao/NonEntitySqlDao.sql.stg
index 3e11edb..1969615 100644
--- a/util/src/main/resources/com/ning/billing/util/dao/NonEntitySqlDao.sql.stg
+++ b/util/src/main/resources/com/ning/billing/util/dao/NonEntitySqlDao.sql.stg
@@ -8,6 +8,14 @@ where id = :id
 ;
 >>
 
+getIdFromObject(tableName) ::= <<
+select
+  id
+from <tableName>
+where record_id = :recordId
+;
+>>
+
 getAccountRecordIdFromAccountHistory() ::= <<
 select
   target_record_id
diff --git a/util/src/test/java/com/ning/billing/dao/MockNonEntityDao.java b/util/src/test/java/com/ning/billing/dao/MockNonEntityDao.java
index 4444bdf..3bb80f9 100644
--- a/util/src/test/java/com/ning/billing/dao/MockNonEntityDao.java
+++ b/util/src/test/java/com/ning/billing/dao/MockNonEntityDao.java
@@ -52,4 +52,9 @@ public class MockNonEntityDao implements NonEntityDao {
     public Long retrieveHistoryTargetRecordId(final Long recordId, final TableName tableName) {
         return null;
     }
+
+    @Override
+    public UUID retrieveIdFromObject(final Long recordId, final ObjectType objectType) {
+        return null;
+    }
 }