killbill-uncached

security: add persistent sessions support Store sessions

8/16/2013 8:22:49 AM

Changes

util/pom.xml 9(+9 -0)

Details

diff --git a/.idea/libraries/Maven__org_apache_shiro_shiro_ehcache_1_2_2.xml b/.idea/libraries/Maven__org_apache_shiro_shiro_ehcache_1_2_2.xml
new file mode 100644
index 0000000..45c2ed3
--- /dev/null
+++ b/.idea/libraries/Maven__org_apache_shiro_shiro_ehcache_1_2_2.xml
@@ -0,0 +1,13 @@
+<component name="libraryTable">
+  <library name="Maven: org.apache.shiro:shiro-ehcache:1.2.2">
+    <CLASSES>
+      <root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-ehcache/1.2.2/shiro-ehcache-1.2.2.jar!/" />
+    </CLASSES>
+    <JAVADOC>
+      <root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-ehcache/1.2.2/shiro-ehcache-1.2.2-javadoc.jar!/" />
+    </JAVADOC>
+    <SOURCES>
+      <root url="jar://$MAVEN_REPOSITORY$/org/apache/shiro/shiro-ehcache/1.2.2/shiro-ehcache-1.2.2-sources.jar!/" />
+    </SOURCES>
+  </library>
+</component>
\ No newline at end of file
diff --git a/account/killbill-account.iml b/account/killbill-account.iml
index 408368a..5e3a72e 100644
--- a/account/killbill-account.iml
+++ b/account/killbill-account.iml
@@ -49,8 +49,10 @@
     <orderEntry type="library" name="Maven: javax.activation:activation:1.1" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-core:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: commons-beanutils:commons-beanutils:1.8.3" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-ehcache:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-guice:1.2.2" level="project" />
     <orderEntry type="library" scope="PROVIDED" name="Maven: com.google.inject.extensions:guice-multibindings:3.0" level="project" />
+    <orderEntry type="library" name="Maven: org.slf4j:jcl-over-slf4j:1.7.5" level="project" />
     <orderEntry type="module" module-name="killbill-util" scope="TEST" production-on-test="" />
     <orderEntry type="library" scope="TEST" name="Maven: com.ning.billing:killbill-util:test-jar:tests:0.4.1-SNAPSHOT" level="project" />
     <orderEntry type="library" scope="TEST" name="Maven: com.ning.billing.commons:killbill-clock:test-jar:tests:0.2.1" level="project" />
diff --git a/beatrix/killbill-beatrix.iml b/beatrix/killbill-beatrix.iml
index 705afc7..14dcd72 100644
--- a/beatrix/killbill-beatrix.iml
+++ b/beatrix/killbill-beatrix.iml
@@ -56,8 +56,10 @@
     <orderEntry type="library" name="Maven: javax.activation:activation:1.1" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-core:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: commons-beanutils:commons-beanutils:1.8.3" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-ehcache:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-guice:1.2.2" level="project" />
     <orderEntry type="library" scope="PROVIDED" name="Maven: com.google.inject.extensions:guice-multibindings:3.0" level="project" />
+    <orderEntry type="library" name="Maven: org.slf4j:jcl-over-slf4j:1.7.5" level="project" />
     <orderEntry type="module" module-name="killbill-account" scope="TEST" />
     <orderEntry type="module" module-name="killbill-catalog" />
     <orderEntry type="module" module-name="killbill-entitlement" />
diff --git a/catalog/killbill-catalog.iml b/catalog/killbill-catalog.iml
index c74e183..fb7751e 100644
--- a/catalog/killbill-catalog.iml
+++ b/catalog/killbill-catalog.iml
@@ -50,8 +50,10 @@
     <orderEntry type="library" name="Maven: javax.activation:activation:1.1" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-core:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: commons-beanutils:commons-beanutils:1.8.3" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-ehcache:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-guice:1.2.2" level="project" />
     <orderEntry type="library" scope="PROVIDED" name="Maven: com.google.inject.extensions:guice-multibindings:3.0" level="project" />
+    <orderEntry type="library" name="Maven: org.slf4j:jcl-over-slf4j:1.7.5" level="project" />
     <orderEntry type="module" module-name="killbill-util" scope="TEST" production-on-test="" />
     <orderEntry type="library" scope="TEST" name="Maven: com.ning.billing:killbill-util:test-jar:tests:0.4.1-SNAPSHOT" level="project" />
     <orderEntry type="library" scope="TEST" name="Maven: com.ning.billing.commons:killbill-clock:test-jar:tests:0.2.1" level="project" />
diff --git a/entitlement/killbill-entitlement.iml b/entitlement/killbill-entitlement.iml
index e85e990..0d3a379 100644
--- a/entitlement/killbill-entitlement.iml
+++ b/entitlement/killbill-entitlement.iml
@@ -52,8 +52,10 @@
     <orderEntry type="library" name="Maven: javax.activation:activation:1.1" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-core:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: commons-beanutils:commons-beanutils:1.8.3" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-ehcache:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-guice:1.2.2" level="project" />
     <orderEntry type="library" scope="PROVIDED" name="Maven: com.google.inject.extensions:guice-multibindings:3.0" level="project" />
+    <orderEntry type="library" name="Maven: org.slf4j:jcl-over-slf4j:1.7.5" level="project" />
     <orderEntry type="module" module-name="killbill-catalog" scope="TEST" />
     <orderEntry type="module" module-name="killbill-util" scope="TEST" production-on-test="" />
     <orderEntry type="library" scope="TEST" name="Maven: com.ning.billing:killbill-util:test-jar:tests:0.4.1-SNAPSHOT" level="project" />
diff --git a/invoice/killbill-invoice.iml b/invoice/killbill-invoice.iml
index 748b28b..9eae04f 100644
--- a/invoice/killbill-invoice.iml
+++ b/invoice/killbill-invoice.iml
@@ -56,8 +56,10 @@
     <orderEntry type="library" name="Maven: javax.activation:activation:1.1" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-core:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: commons-beanutils:commons-beanutils:1.8.3" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-ehcache:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-guice:1.2.2" level="project" />
     <orderEntry type="library" scope="PROVIDED" name="Maven: com.google.inject.extensions:guice-multibindings:3.0" level="project" />
+    <orderEntry type="library" name="Maven: org.slf4j:jcl-over-slf4j:1.7.5" level="project" />
     <orderEntry type="module" module-name="killbill-catalog" scope="TEST" production-on-test="" />
     <orderEntry type="library" scope="TEST" name="Maven: com.ning.billing:killbill-catalog:test-jar:tests:0.4.1-SNAPSHOT" level="project" />
     <orderEntry type="module" module-name="killbill-util" scope="TEST" production-on-test="" />
diff --git a/jaxrs/killbill-jaxrs.iml b/jaxrs/killbill-jaxrs.iml
index 6cf2197..ce8f5da 100644
--- a/jaxrs/killbill-jaxrs.iml
+++ b/jaxrs/killbill-jaxrs.iml
@@ -49,8 +49,10 @@
     <orderEntry type="library" name="Maven: javax.activation:activation:1.1" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-core:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: commons-beanutils:commons-beanutils:1.8.3" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-ehcache:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-guice:1.2.2" level="project" />
     <orderEntry type="library" scope="PROVIDED" name="Maven: com.google.inject.extensions:guice-multibindings:3.0" level="project" />
+    <orderEntry type="library" name="Maven: org.slf4j:jcl-over-slf4j:1.7.5" level="project" />
     <orderEntry type="module" module-name="killbill-util" scope="TEST" production-on-test="" />
     <orderEntry type="library" scope="TEST" name="Maven: com.ning.billing:killbill-util:test-jar:tests:0.4.1-SNAPSHOT" level="project" />
     <orderEntry type="library" scope="TEST" name="Maven: com.ning.billing.commons:killbill-clock:test-jar:tests:0.2.1" level="project" />
diff --git a/junction/killbill-junction.iml b/junction/killbill-junction.iml
index 0d36506..3d7c8cc 100644
--- a/junction/killbill-junction.iml
+++ b/junction/killbill-junction.iml
@@ -52,8 +52,10 @@
     <orderEntry type="library" name="Maven: javax.activation:activation:1.1" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-core:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: commons-beanutils:commons-beanutils:1.8.3" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-ehcache:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-guice:1.2.2" level="project" />
     <orderEntry type="library" scope="PROVIDED" name="Maven: com.google.inject.extensions:guice-multibindings:3.0" level="project" />
+    <orderEntry type="library" name="Maven: org.slf4j:jcl-over-slf4j:1.7.5" level="project" />
     <orderEntry type="module" module-name="killbill-catalog" scope="TEST" />
     <orderEntry type="module" module-name="killbill-entitlement" scope="TEST" production-on-test="" />
     <orderEntry type="library" scope="TEST" name="Maven: com.ning.billing:killbill-entitlement:test-jar:tests:0.4.1-SNAPSHOT" level="project" />
diff --git a/osgi/killbill-osgi.iml b/osgi/killbill-osgi.iml
index e52c435..8c3960f 100644
--- a/osgi/killbill-osgi.iml
+++ b/osgi/killbill-osgi.iml
@@ -57,8 +57,10 @@
     <orderEntry type="library" name="Maven: javax.activation:activation:1.1" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-core:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: commons-beanutils:commons-beanutils:1.8.3" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-ehcache:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-guice:1.2.2" level="project" />
     <orderEntry type="library" scope="PROVIDED" name="Maven: com.google.inject.extensions:guice-multibindings:3.0" level="project" />
+    <orderEntry type="library" name="Maven: org.slf4j:jcl-over-slf4j:1.7.5" level="project" />
     <orderEntry type="module" module-name="killbill-util" scope="TEST" production-on-test="" />
     <orderEntry type="library" scope="TEST" name="Maven: com.ning.billing:killbill-util:test-jar:tests:0.4.1-SNAPSHOT" level="project" />
     <orderEntry type="library" scope="TEST" name="Maven: com.ning.billing.commons:killbill-clock:test-jar:tests:0.2.1" level="project" />
diff --git a/osgi-bundles/tests/payment/killbill-osgi-bundles-test-payment.iml b/osgi-bundles/tests/payment/killbill-osgi-bundles-test-payment.iml
index e8d74bb..11fbfa3 100644
--- a/osgi-bundles/tests/payment/killbill-osgi-bundles-test-payment.iml
+++ b/osgi-bundles/tests/payment/killbill-osgi-bundles-test-payment.iml
@@ -49,12 +49,14 @@
     <orderEntry type="library" name="Maven: javax.activation:activation:1.1" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-core:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: commons-beanutils:commons-beanutils:1.8.3" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-ehcache:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-guice:1.2.2" level="project" />
     <orderEntry type="library" scope="PROVIDED" name="Maven: com.google.guava:guava:14.0.1" level="project" />
     <orderEntry type="library" scope="PROVIDED" name="Maven: com.google.inject:guice:3.0" level="project" />
     <orderEntry type="library" scope="PROVIDED" name="Maven: javax.inject:javax.inject:1" level="project" />
     <orderEntry type="library" scope="PROVIDED" name="Maven: aopalliance:aopalliance:1.0" level="project" />
     <orderEntry type="library" scope="PROVIDED" name="Maven: com.google.inject.extensions:guice-multibindings:3.0" level="project" />
+    <orderEntry type="library" name="Maven: org.slf4j:jcl-over-slf4j:1.7.5" level="project" />
     <orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-all:1.9.0" level="project" />
     <orderEntry type="library" name="Maven: org.osgi:org.osgi.core:4.3.1" level="project" />
     <orderEntry type="library" scope="TEST" name="Maven: org.testng:testng:6.3.1" level="project" />
diff --git a/overdue/killbill-overdue.iml b/overdue/killbill-overdue.iml
index c4e90b6..37db8e7 100644
--- a/overdue/killbill-overdue.iml
+++ b/overdue/killbill-overdue.iml
@@ -56,8 +56,10 @@
     <orderEntry type="library" name="Maven: javax.activation:activation:1.1" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-core:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: commons-beanutils:commons-beanutils:1.8.3" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-ehcache:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-guice:1.2.2" level="project" />
     <orderEntry type="library" scope="PROVIDED" name="Maven: com.google.inject.extensions:guice-multibindings:3.0" level="project" />
+    <orderEntry type="library" name="Maven: org.slf4j:jcl-over-slf4j:1.7.5" level="project" />
     <orderEntry type="module" module-name="killbill-catalog" scope="TEST" />
     <orderEntry type="module" module-name="killbill-util" scope="TEST" production-on-test="" />
     <orderEntry type="library" scope="TEST" name="Maven: com.ning.billing:killbill-util:test-jar:tests:0.4.1-SNAPSHOT" level="project" />
diff --git a/payment/killbill-payment.iml b/payment/killbill-payment.iml
index 3c61d5f..6062dc4 100644
--- a/payment/killbill-payment.iml
+++ b/payment/killbill-payment.iml
@@ -58,7 +58,9 @@
     <orderEntry type="library" name="Maven: javax.activation:activation:1.1" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-core:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: commons-beanutils:commons-beanutils:1.8.3" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-ehcache:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-guice:1.2.2" level="project" />
+    <orderEntry type="library" name="Maven: org.slf4j:jcl-over-slf4j:1.7.5" level="project" />
     <orderEntry type="module" module-name="killbill-invoice" scope="TEST" production-on-test="" />
     <orderEntry type="library" scope="TEST" name="Maven: com.ning.billing:killbill-invoice:test-jar:tests:0.4.1-SNAPSHOT" level="project" />
     <orderEntry type="module" module-name="killbill-junction" scope="TEST" production-on-test="" />
diff --git a/server/killbill-server.iml b/server/killbill-server.iml
index eb756ca..33ef06c 100644
--- a/server/killbill-server.iml
+++ b/server/killbill-server.iml
@@ -56,7 +56,9 @@
     <orderEntry type="library" name="Maven: javax.activation:activation:1.1" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-core:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: commons-beanutils:commons-beanutils:1.8.3" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-ehcache:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-guice:1.2.2" level="project" />
+    <orderEntry type="library" scope="RUNTIME" name="Maven: org.slf4j:jcl-over-slf4j:1.7.5" level="project" />
     <orderEntry type="module" module-name="killbill-beatrix" />
     <orderEntry type="module" module-name="killbill-catalog" />
     <orderEntry type="module" module-name="killbill-entitlement" />
@@ -107,7 +109,6 @@
     <orderEntry type="library" name="Maven: commons-lang:commons-lang:2.6" level="project" />
     <orderEntry type="library" name="Maven: com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:2.0.0" level="project" />
     <orderEntry type="library" name="Maven: com.fasterxml.jackson.module:jackson-module-jaxb-annotations:2.0.0" level="project" />
-    <orderEntry type="library" scope="RUNTIME" name="Maven: org.slf4j:jcl-over-slf4j:1.7.5" level="project" />
     <orderEntry type="library" name="Maven: org.slf4j:jul-to-slf4j:1.7.5" level="project" />
     <orderEntry type="library" name="Maven: com.ning.jetty:ning-service-skeleton-eventtracker:0.1.7" level="project" />
     <orderEntry type="library" name="Maven: com.ning.jetty:ning-service-skeleton-utils:0.1.7" level="project" />
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 ba05640..4ac7aa2 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
@@ -19,6 +19,7 @@ package com.ning.billing.server.listeners;
 import java.lang.management.ManagementFactory;
 
 import javax.management.MBeanServer;
+import javax.servlet.ServletContext;
 import javax.servlet.ServletContextEvent;
 
 import org.slf4j.Logger;
@@ -53,8 +54,8 @@ public class KillbillGuiceListener extends SetupServer {
     private BusService killbillBusService;
     private KillbillEventHandler killbilleventHandler;
 
-    protected Module getModule() {
-        return new KillbillServerModule();
+    protected Module getModule(final ServletContext servletContext) {
+        return new KillbillServerModule(servletContext);
     }
 
     private void registerMBeansForCache(final CacheManager cacheManager) {
@@ -74,7 +75,7 @@ public class KillbillGuiceListener extends SetupServer {
                 .addJMXExport(KillbillHealthcheck.class)
                 .addJMXExport(NotificationQueueService.class)
                 .addJMXExport(PersistentBus.class)
-                .addModule(getModule())
+                .addModule(getModule(event.getServletContext()))
                         // Don't filter all requests through Jersey, only the JAX-RS APIs (otherwise,
                         // things like static resources, favicon, etc. are 404'ed)
                 .setJerseyUriPattern("(" + JaxRsResourceBase.PREFIX + "|" + JaxRsResourceBase.PLUGINS_PATH + ")" + "/.*")
diff --git a/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java b/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java
index 85b9f47..7e35abb 100644
--- a/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java
+++ b/server/src/main/java/com/ning/billing/server/modules/KillbillServerModule.java
@@ -16,6 +16,7 @@
 
 package com.ning.billing.server.modules;
 
+import javax.servlet.ServletContext;
 import javax.sql.DataSource;
 
 import com.ning.billing.entitlement.glue.DefaultEntitlementModule;
@@ -62,6 +63,8 @@ import com.ning.billing.util.glue.ClockModule;
 import com.ning.billing.util.glue.CustomFieldModule;
 import com.ning.billing.util.glue.ExportModule;
 import com.ning.billing.util.glue.GlobalLockerModule;
+import com.ning.billing.util.glue.KillBillShiroAopModule;
+import com.ning.billing.util.glue.KillBillShiroModule;
 import com.ning.billing.util.glue.NonEntityDaoModule;
 import com.ning.billing.util.glue.NotificationQueueModule;
 import com.ning.billing.util.glue.RecordIdModule;
@@ -72,6 +75,12 @@ import com.google.inject.AbstractModule;
 
 public class KillbillServerModule extends AbstractModule {
 
+    protected final ServletContext servletContext;
+
+    public KillbillServerModule(final ServletContext servletContext) {
+        this.servletContext = servletContext;
+    }
+
     @Override
     protected void configure() {
         configureDao();
@@ -147,6 +156,8 @@ public class KillbillServerModule extends AbstractModule {
         install(new DefaultOSGIModule(configSource));
         install(new UsageModule(configSource));
         install(new RecordIdModule());
+        install(new KillBillShiroWebModule(servletContext));
+        install(new KillBillShiroAopModule());
         install(new SecurityModule());
 
         installClock();
diff --git a/server/src/main/java/com/ning/billing/server/modules/KillBillShiroWebModule.java b/server/src/main/java/com/ning/billing/server/modules/KillBillShiroWebModule.java
new file mode 100644
index 0000000..c482fff
--- /dev/null
+++ b/server/src/main/java/com/ning/billing/server/modules/KillBillShiroWebModule.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.server.modules;
+
+import javax.servlet.ServletContext;
+
+import org.apache.shiro.cache.CacheManager;
+import org.apache.shiro.guice.web.ShiroWebModule;
+import org.apache.shiro.session.mgt.SessionManager;
+import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
+
+import com.ning.billing.jaxrs.resources.JaxrsResource;
+import com.ning.billing.util.glue.EhCacheManagerProvider;
+import com.ning.billing.util.glue.IniRealmProvider;
+import com.ning.billing.util.glue.JDBCSessionDaoProvider;
+import com.ning.billing.util.security.shiro.dao.JDBCSessionDao;
+
+import com.google.inject.binder.AnnotatedBindingBuilder;
+
+public class KillBillShiroWebModule extends ShiroWebModule {
+
+    public static final String KILLBILL_RBAC_PROPERTY = "killbill.server.rbac";
+
+    public KillBillShiroWebModule(final ServletContext servletContext) {
+        super(servletContext);
+    }
+
+    @Override
+    protected void configureShiroWeb() {
+        bindRealm().toProvider(IniRealmProvider.class).asEagerSingleton();
+
+        // Magic provider to configure the cache manager
+        bind(CacheManager.class).toProvider(EhCacheManagerProvider.class).asEagerSingleton();
+
+        final boolean rbacEnabled = Boolean.parseBoolean(System.getProperty(KILLBILL_RBAC_PROPERTY, "true"));
+        if (rbacEnabled) {
+            addFilterChain(JaxrsResource.PREFIX + "/**", AUTHC_BASIC);
+        }
+    }
+
+    @Override
+    protected void bindSessionManager(final AnnotatedBindingBuilder<SessionManager> bind) {
+        // Bypass the servlet container completely for session management and delegate it to Shiro.
+        // The default session timeout is 30 minutes.
+        bind.to(DefaultWebSessionManager.class).asEagerSingleton();
+
+        // Magic provider to configure the session DAO
+        bind(JDBCSessionDao.class).toProvider(JDBCSessionDaoProvider.class).asEagerSingleton();
+    }
+}
diff --git a/server/src/main/webapp/WEB-INF/shiro.ini b/server/src/main/webapp/WEB-INF/shiro.ini
index 4eb4e39..61e61e4 100644
--- a/server/src/main/webapp/WEB-INF/shiro.ini
+++ b/server/src/main/webapp/WEB-INF/shiro.ini
@@ -1,6 +1,6 @@
 ###################################################################################
 #                                                                                 #
-#                   Copyright 2010-2012 Ning, Inc.                                #
+#                   Copyright 2010-2013 Ning, Inc.                                #
 #                                                                                 #
 #      Ning 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   #
@@ -16,13 +16,8 @@
 #                                                                                 #
 ###################################################################################
 
-[main]
-# Bypass the servlet container completely for session management and delegate
-# it to Shiro (to be portable across servlet containers)
-# The default session timeout is 30 minutes.
-sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
-# Use the configured native session manager
-securityManager.sessionManager = $sessionManager
+# [main]
+# See com.ning.billing.util.glue.KillBillShiroModule
 
 # Example on how to define an admin user
 #
diff --git a/server/src/main/webapp/WEB-INF/web.xml b/server/src/main/webapp/WEB-INF/web.xml
index 13d7694..8061627 100644
--- a/server/src/main/webapp/WEB-INF/web.xml
+++ b/server/src/main/webapp/WEB-INF/web.xml
@@ -30,7 +30,7 @@
         <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
     </filter>
     <filter-mapping>
-        <!-- The Shitor filter-mapping should come first -->
+        <!-- The Shiro filter-mapping should come first -->
         <filter-name>ShiroFilter</filter-name>
         <url-pattern>/*</url-pattern>
         <dispatcher>REQUEST</dispatcher>
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 97d1d74..38e19a6 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/KillbillClient.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/KillbillClient.java
@@ -176,8 +176,12 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
     //
 
     protected void loginAsAdmin() {
-        this.username = "tester";
-        this.password = "tester";
+        loginAs("tester", "tester");
+    }
+
+    protected void loginAs(final String username, final String password) {
+        this.username = username;
+        this.password = password;
     }
 
     protected void logout() {
@@ -1032,7 +1036,7 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
         return executeAndWait(builder, timeoutSec, false);
     }
 
-    private Response executeAndWait(final BoundRequestBuilder builder, final int timeoutSec, final boolean addContextHeader) {
+    protected Response executeAndWait(final BoundRequestBuilder builder, final int timeoutSec, final boolean addContextHeader) {
 
         if (addContextHeader) {
             builder.addHeader(JaxrsResource.HDR_CREATED_BY, createdBy);
@@ -1071,7 +1075,7 @@ public abstract class KillbillClient extends GuicyKillbillTestSuiteWithEmbeddedD
         return String.format("http://%s:%d%s", config.getServerHost(), config.getServerPort(), uri);
     }
 
-    private BoundRequestBuilder getBuilderWithHeaderAndQuery(final String verb, final String url, final Map<String, String> queryParams) {
+    protected BoundRequestBuilder getBuilderWithHeaderAndQuery(final String verb, final String url, final Map<String, String> queryParams) {
         BoundRequestBuilder builder = null;
         if (verb.equals("GET")) {
             builder = httpClient.prepareGet(url);
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 7aaf3c6..54c19de 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestJaxrsBase.java
@@ -19,16 +19,12 @@ package com.ning.billing.jaxrs;
 import java.io.IOException;
 import java.net.URL;
 import java.util.EventListener;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 
 import javax.inject.Inject;
 import javax.servlet.Servlet;
-
-import com.ning.billing.DBTestingHelper;
-import com.ning.billing.commons.embeddeddb.EmbeddedDB;
-import com.ning.billing.entitlement.glue.DefaultEntitlementModule;
+import javax.servlet.ServletContext;
 
 import org.apache.shiro.web.env.EnvironmentLoaderListener;
 import org.apache.shiro.web.servlet.ShiroFilter;
@@ -36,13 +32,13 @@ import org.eclipse.jetty.servlet.FilterHolder;
 import org.joda.time.LocalDate;
 import org.skife.config.ConfigSource;
 import org.skife.config.ConfigurationObjectFactory;
-import org.skife.jdbi.v2.DBI;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.AfterSuite;
 import org.testng.annotations.BeforeClass;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.BeforeSuite;
 
+import com.ning.billing.DBTestingHelper;
 import com.ning.billing.GuicyKillbillTestWithEmbeddedDBModule;
 import com.ning.billing.KillbillConfigSource;
 import com.ning.billing.account.glue.DefaultAccountModule;
@@ -50,7 +46,8 @@ import com.ning.billing.api.TestApiListener;
 import com.ning.billing.beatrix.glue.BeatrixModule;
 import com.ning.billing.bus.api.PersistentBus;
 import com.ning.billing.catalog.glue.CatalogModule;
-import com.ning.billing.subscription.glue.DefaultSubscriptionModule;
+import com.ning.billing.commons.embeddeddb.EmbeddedDB;
+import com.ning.billing.entitlement.glue.DefaultEntitlementModule;
 import com.ning.billing.invoice.api.InvoiceNotifier;
 import com.ning.billing.invoice.glue.DefaultInvoiceModule;
 import com.ning.billing.invoice.notification.NullInvoiceNotifier;
@@ -61,7 +58,9 @@ import com.ning.billing.overdue.glue.DefaultOverdueModule;
 import com.ning.billing.payment.glue.PaymentModule;
 import com.ning.billing.payment.provider.MockPaymentProviderPluginModule;
 import com.ning.billing.server.listeners.KillbillGuiceListener;
+import com.ning.billing.server.modules.KillBillShiroWebModule;
 import com.ning.billing.server.modules.KillbillServerModule;
+import com.ning.billing.subscription.glue.DefaultSubscriptionModule;
 import com.ning.billing.tenant.glue.TenantModule;
 import com.ning.billing.usage.glue.UsageModule;
 import com.ning.billing.util.cache.CacheControllerDispatcher;
@@ -75,6 +74,8 @@ import com.ning.billing.util.glue.CacheModule;
 import com.ning.billing.util.glue.CallContextModule;
 import com.ning.billing.util.glue.CustomFieldModule;
 import com.ning.billing.util.glue.ExportModule;
+import com.ning.billing.util.glue.KillBillShiroAopModule;
+import com.ning.billing.util.glue.KillBillShiroModule;
 import com.ning.billing.util.glue.NonEntityDaoModule;
 import com.ning.billing.util.glue.NotificationQueueModule;
 import com.ning.billing.util.glue.RecordIdModule;
@@ -129,17 +130,17 @@ public class TestJaxrsBase extends KillbillClient {
 
     public static class TestKillbillGuiceListener extends KillbillGuiceListener {
 
-        private final TestKillbillServerModule module;
+        private final EmbeddedDB helper;
 
 
         public TestKillbillGuiceListener(final EmbeddedDB helper) {
             super();
-            this.module = new TestKillbillServerModule(helper);
+            this.helper = helper;
         }
 
         @Override
-        protected Module getModule() {
-            return module;
+        protected Module getModule(final ServletContext servletContext) {
+            return new TestKillbillServerModule(helper, servletContext);
         }
 
     }
@@ -160,8 +161,8 @@ public class TestJaxrsBase extends KillbillClient {
 
         private final EmbeddedDB helper;
 
-        public TestKillbillServerModule(final EmbeddedDB helper) {
-            super();
+        public TestKillbillServerModule(final EmbeddedDB helper, final ServletContext servletContext) {
+            super(servletContext);
             this.helper = helper;
         }
 
@@ -227,6 +228,8 @@ public class TestJaxrsBase extends KillbillClient {
             install(new UsageModule(configSource));
             install(new RecordIdModule());
             installClock();
+            install(new KillBillShiroWebModule(servletContext));
+            install(new KillBillShiroAopModule());
             install(new SecurityModule());
         }
     }
@@ -297,8 +300,7 @@ public class TestJaxrsBase extends KillbillClient {
             @Override
             public Iterator<EventListener> iterator() {
                 // Note! This needs to be in sync with web.xml
-                return ImmutableList.<EventListener>of(listener,
-                                                       new EnvironmentLoaderListener()).iterator();
+                return ImmutableList.<EventListener>of(listener).iterator();
             }
         };
     }
diff --git a/server/src/test/java/com/ning/billing/jaxrs/TestSecurity.java b/server/src/test/java/com/ning/billing/jaxrs/TestSecurity.java
index 1c5e705..3c820d8 100644
--- a/server/src/test/java/com/ning/billing/jaxrs/TestSecurity.java
+++ b/server/src/test/java/com/ning/billing/jaxrs/TestSecurity.java
@@ -19,16 +19,23 @@ package com.ning.billing.jaxrs;
 import java.util.HashSet;
 import java.util.List;
 
+import javax.annotation.Nullable;
 import javax.ws.rs.core.Response.Status;
 
+import org.apache.shiro.web.servlet.ShiroHttpSession;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
 import com.ning.billing.jaxrs.resources.JaxrsResource;
 import com.ning.billing.security.Permission;
+import com.ning.http.client.AsyncHttpClient.BoundRequestBuilder;
+import com.ning.http.client.Cookie;
 import com.ning.http.client.Response;
 
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
 
 public class TestSecurity extends TestJaxrsBase {
 
@@ -49,4 +56,33 @@ public class TestSecurity extends TestJaxrsBase {
         Assert.assertEquals(stephanesPermissions.size(), 1);
         Assert.assertEquals(new HashSet<String>(stephanesPermissions), ImmutableSet.<String>of(Permission.PAYMENT_CAN_REFUND.toString()));
     }
+
+    @Test(groups = "slow")
+    public void testSession() throws Exception {
+        loginAs("pierre", "password");
+
+        final Response firstResponse = doGet(JaxrsResource.SECURITY_PATH + "/permissions", DEFAULT_EMPTY_QUERY, DEFAULT_HTTP_TIMEOUT_SEC);
+        Assert.assertEquals(firstResponse.getStatusCode(), Status.OK.getStatusCode());
+        Assert.assertEquals(((List) mapper.readValue(firstResponse.getResponseBody(), new TypeReference<List<String>>() {})).size(), 2);
+
+        // Retrieve the session id
+        final Cookie session = Iterables.find(firstResponse.getCookies(),
+                                              new Predicate<Cookie>() {
+                                                  @Override
+                                                  public boolean apply(@Nullable final Cookie cookie) {
+                                                      return ShiroHttpSession.DEFAULT_SESSION_ID_NAME.equals(cookie.getName());
+                                                  }
+                                              });
+
+        // Make sure we don't use the credentials anymore
+        logout();
+
+        // Re-issue the query with the cookie
+        final String url = String.format("http://%s:%d%s", config.getServerHost(), config.getServerPort(), JaxrsResource.SECURITY_PATH + "/permissions");
+        final BoundRequestBuilder builder = getBuilderWithHeaderAndQuery("GET", url, DEFAULT_EMPTY_QUERY);
+        builder.addCookie(session);
+        final Response secondResponse = executeAndWait(builder, DEFAULT_HTTP_TIMEOUT_SEC, false);
+        Assert.assertEquals(secondResponse.getStatusCode(), Status.OK.getStatusCode());
+        Assert.assertEquals(((List) mapper.readValue(firstResponse.getResponseBody(), new TypeReference<List<String>>() {})).size(), 2);
+    }
 }
diff --git a/server/src/test/resources/shiro.ini b/server/src/test/resources/shiro.ini
index ac4aa4c..4f9db89 100644
--- a/server/src/test/resources/shiro.ini
+++ b/server/src/test/resources/shiro.ini
@@ -1,6 +1,6 @@
 ###################################################################################
 #                                                                                 #
-#                   Copyright 2010-2012 Ning, Inc.                                #
+#                   Copyright 2010-2013 Ning, Inc.                                #
 #                                                                                 #
 #      Ning 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   #
@@ -16,14 +16,6 @@
 #                                                                                 #
 ###################################################################################
 
-[main]
-# Bypass the servlet container completely for session management and delegate
-# it to Shiro (to be portable across servlet containers)
-# The default session timeout is 30 minutes.
-sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
-# Use the configured native session manager
-securityManager.sessionManager = $sessionManager
-
 [users]
 tester = tester, admin
 pierre = password, creditor
diff --git a/subscription/killbill-subscription.iml b/subscription/killbill-subscription.iml
index 2b8c39a..ba3d032 100644
--- a/subscription/killbill-subscription.iml
+++ b/subscription/killbill-subscription.iml
@@ -57,8 +57,10 @@
     <orderEntry type="library" name="Maven: javax.activation:activation:1.1" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-core:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: commons-beanutils:commons-beanutils:1.8.3" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-ehcache:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-guice:1.2.2" level="project" />
     <orderEntry type="library" scope="PROVIDED" name="Maven: com.google.inject.extensions:guice-multibindings:3.0" level="project" />
+    <orderEntry type="library" name="Maven: org.slf4j:jcl-over-slf4j:1.7.5" level="project" />
     <orderEntry type="module" module-name="killbill-catalog" scope="TEST" />
     <orderEntry type="module" module-name="killbill-util" scope="TEST" production-on-test="" />
     <orderEntry type="library" scope="TEST" name="Maven: com.ning.billing:killbill-util:test-jar:tests:0.4.1-SNAPSHOT" level="project" />
diff --git a/tenant/killbill-tenant.iml b/tenant/killbill-tenant.iml
index f491bd3..a99b6b9 100644
--- a/tenant/killbill-tenant.iml
+++ b/tenant/killbill-tenant.iml
@@ -49,8 +49,10 @@
     <orderEntry type="library" name="Maven: javax.activation:activation:1.1" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-core:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: commons-beanutils:commons-beanutils:1.8.3" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-ehcache:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-guice:1.2.2" level="project" />
     <orderEntry type="library" scope="PROVIDED" name="Maven: com.google.inject.extensions:guice-multibindings:3.0" level="project" />
+    <orderEntry type="library" name="Maven: org.slf4j:jcl-over-slf4j:1.7.5" level="project" />
     <orderEntry type="module" module-name="killbill-util" scope="TEST" production-on-test="" />
     <orderEntry type="library" scope="TEST" name="Maven: com.ning.billing:killbill-util:test-jar:tests:0.4.1-SNAPSHOT" level="project" />
     <orderEntry type="library" scope="TEST" name="Maven: com.ning.billing.commons:killbill-clock:test-jar:tests:0.2.1" level="project" />
diff --git a/usage/killbill-usage.iml b/usage/killbill-usage.iml
index 6c7f311..f06294a 100644
--- a/usage/killbill-usage.iml
+++ b/usage/killbill-usage.iml
@@ -48,8 +48,10 @@
     <orderEntry type="library" name="Maven: javax.activation:activation:1.1" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-core:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: commons-beanutils:commons-beanutils:1.8.3" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-ehcache:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-guice:1.2.2" level="project" />
     <orderEntry type="library" scope="PROVIDED" name="Maven: com.google.inject.extensions:guice-multibindings:3.0" level="project" />
+    <orderEntry type="library" name="Maven: org.slf4j:jcl-over-slf4j:1.7.5" level="project" />
     <orderEntry type="module" module-name="killbill-util" scope="TEST" production-on-test="" />
     <orderEntry type="library" scope="TEST" name="Maven: com.ning.billing:killbill-util:test-jar:tests:0.4.1-SNAPSHOT" level="project" />
     <orderEntry type="library" scope="TEST" name="Maven: com.ning.billing.commons:killbill-clock:test-jar:tests:0.2.1" level="project" />
diff --git a/util/killbill-util.iml b/util/killbill-util.iml
index a3911a4..7718da9 100644
--- a/util/killbill-util.iml
+++ b/util/killbill-util.iml
@@ -61,8 +61,10 @@
     <orderEntry type="library" name="Maven: javax.activation:activation:1.1" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-core:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: commons-beanutils:commons-beanutils:1.8.3" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-ehcache:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-guice:1.2.2" level="project" />
     <orderEntry type="library" scope="TEST" name="Maven: org.mockito:mockito-all:1.9.0" level="project" />
+    <orderEntry type="library" name="Maven: org.slf4j:jcl-over-slf4j:1.7.5" level="project" />
     <orderEntry type="library" scope="TEST" name="Maven: org.slf4j:slf4j-simple:1.7.5" level="project" />
     <orderEntry type="library" scope="TEST" name="Maven: org.testng:testng:6.3.1" level="project" />
     <orderEntry type="library" scope="TEST" name="Maven: junit:junit:3.8.1" level="project" />

util/pom.xml 9(+9 -0)

diff --git a/util/pom.xml b/util/pom.xml
index 7116c83..49cd5d8 100644
--- a/util/pom.xml
+++ b/util/pom.xml
@@ -165,6 +165,10 @@
         </dependency>
         <dependency>
             <groupId>org.apache.shiro</groupId>
+            <artifactId>shiro-ehcache</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.shiro</groupId>
             <artifactId>shiro-guice</artifactId>
         </dependency>
         <dependency>
@@ -181,6 +185,11 @@
             <artifactId>config-magic</artifactId>
         </dependency>
         <dependency>
+            <!-- For Shiro -->
+            <groupId>org.slf4j</groupId>
+            <artifactId>jcl-over-slf4j</artifactId>
+        </dependency>
+        <dependency>
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-api</artifactId>
         </dependency>
diff --git a/util/src/main/java/com/ning/billing/util/glue/EhCacheManagerProvider.java b/util/src/main/java/com/ning/billing/util/glue/EhCacheManagerProvider.java
new file mode 100644
index 0000000..bb774d9
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/glue/EhCacheManagerProvider.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.util.glue;
+
+import javax.inject.Inject;
+import javax.inject.Provider;
+
+import org.apache.shiro.cache.ehcache.EhCacheManager;
+import org.apache.shiro.mgt.DefaultSecurityManager;
+import org.apache.shiro.mgt.SecurityManager;
+
+import net.sf.ehcache.CacheManager;
+
+public class EhCacheManagerProvider implements Provider<EhCacheManager> {
+
+    private final SecurityManager securityManager;
+    private final CacheManager ehCacheCacheManager;
+
+    @Inject
+    public EhCacheManagerProvider(final SecurityManager securityManager, final CacheManager ehCacheCacheManager) {
+        this.securityManager = securityManager;
+        this.ehCacheCacheManager = ehCacheCacheManager;
+    }
+
+    @Override
+    public EhCacheManager get() {
+        final EhCacheManager shiroEhCacheManager = new EhCacheManager();
+        // Same EhCache manager instance as the rest of the system
+        shiroEhCacheManager.setCacheManager(ehCacheCacheManager);
+
+        if (securityManager instanceof DefaultSecurityManager) {
+            ((DefaultSecurityManager) securityManager).setCacheManager(shiroEhCacheManager);
+        }
+
+        return shiroEhCacheManager;
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/glue/JDBCSessionDaoProvider.java b/util/src/main/java/com/ning/billing/util/glue/JDBCSessionDaoProvider.java
new file mode 100644
index 0000000..de5299a
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/glue/JDBCSessionDaoProvider.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.util.glue;
+
+import javax.inject.Inject;
+import javax.inject.Provider;
+
+import org.apache.shiro.session.mgt.DefaultSessionManager;
+import org.apache.shiro.session.mgt.SessionManager;
+import org.skife.jdbi.v2.IDBI;
+
+import com.ning.billing.util.security.shiro.dao.JDBCSessionDao;
+
+public class JDBCSessionDaoProvider implements Provider<JDBCSessionDao> {
+
+    private final SessionManager sessionManager;
+    private final IDBI dbi;
+
+    @Inject
+    public JDBCSessionDaoProvider(final IDBI dbi, final SessionManager sessionManager) {
+        this.sessionManager = sessionManager;
+        this.dbi = dbi;
+    }
+
+    @Override
+    public JDBCSessionDao get() {
+        final JDBCSessionDao jdbcSessionDao = new JDBCSessionDao(dbi);
+
+        if (sessionManager instanceof DefaultSessionManager) {
+            ((DefaultSessionManager) sessionManager).setSessionDAO(jdbcSessionDao);
+        }
+
+        return jdbcSessionDao;
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/glue/KillBillShiroAopModule.java b/util/src/main/java/com/ning/billing/util/glue/KillBillShiroAopModule.java
new file mode 100644
index 0000000..3f32935
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/glue/KillBillShiroAopModule.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.util.glue;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+
+import org.apache.shiro.aop.AnnotationMethodInterceptor;
+import org.apache.shiro.aop.AnnotationResolver;
+import org.apache.shiro.guice.aop.ShiroAopModule;
+
+import com.ning.billing.util.security.AnnotationHierarchicalResolver;
+import com.ning.billing.util.security.AopAllianceMethodInterceptorAdapter;
+import com.ning.billing.util.security.PermissionAnnotationHandler;
+import com.ning.billing.util.security.PermissionAnnotationMethodInterceptor;
+
+import com.google.inject.matcher.AbstractMatcher;
+import com.google.inject.matcher.Matchers;
+
+// Provides authentication via Shiro
+public class KillBillShiroAopModule extends ShiroAopModule {
+
+    private final AnnotationHierarchicalResolver resolver = new AnnotationHierarchicalResolver();
+
+    @Override
+    protected AnnotationResolver createAnnotationResolver() {
+        return resolver;
+    }
+
+    @Override
+    protected void configureInterceptors(final AnnotationResolver resolver) {
+        super.configureInterceptors(resolver);
+
+        final PermissionAnnotationHandler permissionAnnotationHandler = new PermissionAnnotationHandler();
+        // Inject the Security API
+        requestInjection(permissionAnnotationHandler);
+
+        final PermissionAnnotationMethodInterceptor methodInterceptor = new PermissionAnnotationMethodInterceptor(permissionAnnotationHandler, resolver);
+        bindShiroInterceptorWithHierarchy(methodInterceptor);
+    }
+
+    // Similar to bindShiroInterceptor but will look for annotations in the class hierarchy
+    protected final void bindShiroInterceptorWithHierarchy(final AnnotationMethodInterceptor methodInterceptor) {
+        bindInterceptor(Matchers.any(),
+                        new AbstractMatcher<Method>() {
+                            public boolean matches(final Method method) {
+                                final Class<? extends Annotation> annotation = methodInterceptor.getHandler().getAnnotationClass();
+                                return resolver.getAnnotationFromMethod(method, annotation) != null;
+                            }
+                        },
+                        new AopAllianceMethodInterceptorAdapter(methodInterceptor));
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/glue/KillBillShiroModule.java b/util/src/main/java/com/ning/billing/util/glue/KillBillShiroModule.java
new file mode 100644
index 0000000..f2874ce
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/glue/KillBillShiroModule.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.util.glue;
+
+import org.apache.shiro.cache.CacheManager;
+import org.apache.shiro.guice.ShiroModule;
+import org.apache.shiro.mgt.SecurityManager;
+import org.apache.shiro.session.mgt.DefaultSessionManager;
+import org.apache.shiro.session.mgt.SessionManager;
+
+import com.ning.billing.util.security.shiro.dao.JDBCSessionDao;
+
+import com.google.inject.binder.AnnotatedBindingBuilder;
+
+// For Kill Bill library only.
+// See com.ning.billing.server.modules.KillBillShiroWebModule for Kill Bill server.
+public class KillBillShiroModule extends ShiroModule {
+
+    protected void configureShiro() {
+        bindRealm().toProvider(IniRealmProvider.class).asEagerSingleton();
+    }
+
+    @Override
+    protected void bindSecurityManager(final AnnotatedBindingBuilder<? super SecurityManager> bind) {
+        super.bindSecurityManager(bind);
+
+        // Magic provider to configure the cache manager
+        bind(CacheManager.class).toProvider(EhCacheManagerProvider.class).asEagerSingleton();
+    }
+
+    @Override
+    protected void bindSessionManager(final AnnotatedBindingBuilder<SessionManager> bind) {
+        bind.to(DefaultSessionManager.class).asEagerSingleton();
+
+        // Magic provider to configure the session DAO
+        bind(JDBCSessionDao.class).toProvider(JDBCSessionDaoProvider.class).asEagerSingleton();
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/glue/SecurityModule.java b/util/src/main/java/com/ning/billing/util/glue/SecurityModule.java
index 0c60e27..a8ea01a 100644
--- a/util/src/main/java/com/ning/billing/util/glue/SecurityModule.java
+++ b/util/src/main/java/com/ning/billing/util/glue/SecurityModule.java
@@ -16,81 +16,46 @@
 
 package com.ning.billing.util.glue;
 
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-
-import org.apache.shiro.aop.AnnotationMethodInterceptor;
-import org.apache.shiro.aop.AnnotationResolver;
-import org.apache.shiro.guice.aop.ShiroAopModule;
 import org.skife.config.ConfigSource;
 import org.skife.config.ConfigurationObjectFactory;
 import org.skife.config.SimplePropertyConfigSource;
 
 import com.ning.billing.security.api.SecurityApi;
 import com.ning.billing.util.config.SecurityConfig;
-import com.ning.billing.util.security.AnnotationHierarchicalResolver;
-import com.ning.billing.util.security.AopAllianceMethodInterceptorAdapter;
-import com.ning.billing.util.security.PermissionAnnotationMethodInterceptor;
-
-import com.google.inject.matcher.AbstractMatcher;
-import com.google.inject.matcher.Matchers;
+import com.ning.billing.util.security.api.DefaultSecurityApi;
+import com.ning.billing.util.security.api.DefaultSecurityService;
+import com.ning.billing.util.security.api.SecurityService;
 
-public class SecurityModule extends ShiroAopModule {
+import com.google.inject.AbstractModule;
 
-    private final AnnotationHierarchicalResolver resolver = new AnnotationHierarchicalResolver();
+public class SecurityModule extends AbstractModule {
 
     private final ConfigSource configSource;
 
-    private SecurityConfig securityConfig;
-    private SecurityApi securityApi;
-
     public SecurityModule() {
         this(new SimplePropertyConfigSource(System.getProperties()));
     }
 
     public SecurityModule(final ConfigSource configSource) {
-        super();
         this.configSource = configSource;
     }
 
-    // LAME - the configure method is final in ShiroAopModule so we piggy back configureInterceptors
-    private void doConfigure() {
+    public void configure() {
         installConfig();
         installSecurityApi();
+        installSecurityService();
     }
 
     private void installConfig() {
-        securityConfig = new ConfigurationObjectFactory(configSource).build(SecurityConfig.class);
+        final SecurityConfig securityConfig = new ConfigurationObjectFactory(configSource).build(SecurityConfig.class);
         bind(SecurityConfig.class).toInstance(securityConfig);
     }
 
     private void installSecurityApi() {
-        securityApi = new SecurityApiProvider(securityConfig).get();
-        bind(SecurityApi.class).toInstance(securityApi);
-    }
-
-    @Override
-    protected AnnotationResolver createAnnotationResolver() {
-        return resolver;
-    }
-
-    @Override
-    protected void configureInterceptors(final AnnotationResolver resolver) {
-        // HACK
-        doConfigure();
-
-        super.configureInterceptors(resolver);
-        bindShiroInterceptorWithHierarchy(new PermissionAnnotationMethodInterceptor(securityApi, resolver));
+        bind(SecurityApi.class).to(DefaultSecurityApi.class).asEagerSingleton();
     }
 
-    // Similar to bindShiroInterceptor but will look for annotations in the class hierarchy
-    protected final void bindShiroInterceptorWithHierarchy(final AnnotationMethodInterceptor methodInterceptor) {
-        bindInterceptor(Matchers.any(),
-                        new AbstractMatcher<Method>() {
-                            public boolean matches(final Method method) {
-                                final Class<? extends Annotation> annotation = methodInterceptor.getHandler().getAnnotationClass();
-                                return resolver.getAnnotationFromMethod(method, annotation) != null;
-                            }
-                        }, new AopAllianceMethodInterceptorAdapter(methodInterceptor));
+    protected void installSecurityService() {
+        bind(SecurityService.class).to(DefaultSecurityService.class).asEagerSingleton();
     }
 }
diff --git a/util/src/main/java/com/ning/billing/util/security/api/DefaultSecurityService.java b/util/src/main/java/com/ning/billing/util/security/api/DefaultSecurityService.java
new file mode 100644
index 0000000..9b92a65
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/security/api/DefaultSecurityService.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.util.security.api;
+
+import javax.inject.Inject;
+
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.mgt.SecurityManager;
+
+import com.ning.billing.lifecycle.LifecycleHandlerType;
+import com.ning.billing.lifecycle.LifecycleHandlerType.LifecycleLevel;
+
+public class DefaultSecurityService implements SecurityService {
+
+    public static final String SECURITY_SERVICE_NAME = "security-service";
+
+    private final SecurityManager securityManager;
+
+    @Inject
+    public DefaultSecurityService(final SecurityManager securityManager) {
+        this.securityManager = securityManager;
+    }
+
+    @Override
+    public String getName() {
+        return SECURITY_SERVICE_NAME;
+    }
+
+    @LifecycleHandlerType(LifecycleHandlerType.LifecycleLevel.INIT_SERVICE)
+    public void initialize() {
+        SecurityUtils.setSecurityManager(securityManager);
+    }
+
+    @LifecycleHandlerType(LifecycleLevel.STOP_SERVICE)
+    public void stop() {
+        SecurityUtils.setSecurityManager(null);
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/security/PermissionAnnotationHandler.java b/util/src/main/java/com/ning/billing/util/security/PermissionAnnotationHandler.java
index 8869e40..88551ab 100644
--- a/util/src/main/java/com/ning/billing/util/security/PermissionAnnotationHandler.java
+++ b/util/src/main/java/com/ning/billing/util/security/PermissionAnnotationHandler.java
@@ -21,6 +21,8 @@ package com.ning.billing.util.security;
 
 import java.lang.annotation.Annotation;
 
+import javax.inject.Inject;
+
 import org.apache.shiro.authz.AuthorizationException;
 import org.apache.shiro.authz.aop.AuthorizingAnnotationHandler;
 
@@ -36,11 +38,12 @@ import com.google.common.collect.ImmutableList;
 public class PermissionAnnotationHandler extends AuthorizingAnnotationHandler {
 
     private final TenantContext context = new DefaultTenantContext(null);
-    private final SecurityApi securityApi;
 
-    public PermissionAnnotationHandler(final SecurityApi securityApi) {
+    @Inject
+    SecurityApi securityApi;
+
+    public PermissionAnnotationHandler() {
         super(RequiresPermissions.class);
-        this.securityApi = securityApi;
     }
 
     public void assertAuthorized(final Annotation annotation) throws AuthorizationException {
diff --git a/util/src/main/java/com/ning/billing/util/security/PermissionAnnotationMethodInterceptor.java b/util/src/main/java/com/ning/billing/util/security/PermissionAnnotationMethodInterceptor.java
index 11567da..c67e62c 100644
--- a/util/src/main/java/com/ning/billing/util/security/PermissionAnnotationMethodInterceptor.java
+++ b/util/src/main/java/com/ning/billing/util/security/PermissionAnnotationMethodInterceptor.java
@@ -17,13 +17,12 @@
 package com.ning.billing.util.security;
 
 import org.apache.shiro.aop.AnnotationResolver;
+import org.apache.shiro.authz.aop.AuthorizingAnnotationHandler;
 import org.apache.shiro.authz.aop.AuthorizingAnnotationMethodInterceptor;
 
-import com.ning.billing.security.api.SecurityApi;
-
 public class PermissionAnnotationMethodInterceptor extends AuthorizingAnnotationMethodInterceptor {
 
-    public PermissionAnnotationMethodInterceptor(final SecurityApi securityApi, final AnnotationResolver resolver) {
-        super(new PermissionAnnotationHandler(securityApi), resolver);
+    public PermissionAnnotationMethodInterceptor(final AuthorizingAnnotationHandler handler, final AnnotationResolver resolver) {
+        super(handler, resolver);
     }
 }
\ No newline at end of file
diff --git a/util/src/main/java/com/ning/billing/util/security/shiro/dao/JDBCSessionDao.java b/util/src/main/java/com/ning/billing/util/security/shiro/dao/JDBCSessionDao.java
new file mode 100644
index 0000000..3dbec52
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/security/shiro/dao/JDBCSessionDao.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.util.security.shiro.dao;
+
+import java.io.IOException;
+import java.io.Serializable;
+
+import javax.inject.Inject;
+
+import org.apache.shiro.session.Session;
+import org.apache.shiro.session.mgt.eis.CachingSessionDAO;
+import org.skife.jdbi.v2.DBI;
+import org.skife.jdbi.v2.IDBI;
+import org.skife.jdbi.v2.Transaction;
+import org.skife.jdbi.v2.TransactionStatus;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.ning.billing.commons.jdbi.mapper.LowerToCamelBeanMapperFactory;
+
+public class JDBCSessionDao extends CachingSessionDAO {
+
+    private static final Logger log = LoggerFactory.getLogger(JDBCSessionDao.class);
+
+    private JDBCSessionSqlDao jdbcSessionSqlDao;
+
+    @Inject
+    public JDBCSessionDao(final IDBI dbi) {
+        if (dbi instanceof DBI) {
+            // TODO PIERRE Move to DBIProvider, once it's in util
+            ((DBI) dbi).registerMapper(new LowerToCamelBeanMapperFactory(SessionModelDao.class));
+        }
+        this.jdbcSessionSqlDao = dbi.onDemand(JDBCSessionSqlDao.class);
+    }
+
+    @Override
+    protected void doUpdate(final Session session) {
+        jdbcSessionSqlDao.update(new SessionModelDao(session));
+    }
+
+    @Override
+    protected void doDelete(final Session session) {
+        jdbcSessionSqlDao.delete(new SessionModelDao(session));
+    }
+
+    @Override
+    protected Serializable doCreate(final Session session) {
+        final Serializable sessionId = jdbcSessionSqlDao.inTransaction(new Transaction<Long, JDBCSessionSqlDao>() {
+            @Override
+            public Long inTransaction(final JDBCSessionSqlDao transactional, final TransactionStatus status) throws Exception {
+                transactional.create(new SessionModelDao(session));
+                return transactional.getLastInsertId();
+            }
+        });
+        assignSessionId(session, sessionId);
+        return sessionId;
+    }
+
+    @Override
+    protected Session doReadSession(final Serializable sessionId) {
+        final SessionModelDao sessionModelDao = jdbcSessionSqlDao.read(sessionId);
+        if (sessionModelDao == null) {
+            return null;
+        }
+
+        try {
+            return sessionModelDao.toSimpleSession();
+        } catch (IOException e) {
+            log.warn("Corrupted cookie", e);
+            return null;
+        }
+    }
+}
diff --git a/util/src/main/java/com/ning/billing/util/security/shiro/dao/JDBCSessionSqlDao.java b/util/src/main/java/com/ning/billing/util/security/shiro/dao/JDBCSessionSqlDao.java
new file mode 100644
index 0000000..cdd8e0a
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/security/shiro/dao/JDBCSessionSqlDao.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.util.security.shiro.dao;
+
+import java.io.Serializable;
+
+import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.SqlQuery;
+import org.skife.jdbi.v2.sqlobject.SqlUpdate;
+import org.skife.jdbi.v2.sqlobject.mixins.Transactional;
+import org.skife.jdbi.v2.sqlobject.stringtemplate.UseStringTemplate3StatementLocator;
+
+import com.ning.billing.commons.jdbi.binder.SmartBindBean;
+
+@UseStringTemplate3StatementLocator
+public interface JDBCSessionSqlDao extends Transactional<JDBCSessionSqlDao> {
+
+    @SqlQuery
+    public SessionModelDao read(@Bind("recordId") final Serializable sessionId);
+
+    @SqlUpdate
+    public void create(@SmartBindBean final SessionModelDao sessionModelDao);
+
+    @SqlUpdate
+    public void update(@SmartBindBean final SessionModelDao sessionModelDao);
+
+    @SqlUpdate
+    public void delete(@SmartBindBean final SessionModelDao sessionModelDao);
+
+    @SqlQuery
+    public Long getLastInsertId();
+}
diff --git a/util/src/main/java/com/ning/billing/util/security/shiro/dao/SessionModelDao.java b/util/src/main/java/com/ning/billing/util/security/shiro/dao/SessionModelDao.java
new file mode 100644
index 0000000..30602b2
--- /dev/null
+++ b/util/src/main/java/com/ning/billing/util/security/shiro/dao/SessionModelDao.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.util.security.shiro.dao;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.shiro.io.DefaultSerializer;
+import org.apache.shiro.io.Serializer;
+import org.apache.shiro.session.Session;
+import org.apache.shiro.session.mgt.SimpleSession;
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+
+public class SessionModelDao {
+
+    private final Serializer<Map> serializer = new DefaultSerializer<Map>();
+
+    private Long recordId;
+    private DateTime startTimestamp;
+    private DateTime lastAccessTime;
+    private long timeout;
+    private String host;
+    private byte[] sessionData;
+
+    public SessionModelDao() { /* For the DAO mapper */ }
+
+    public SessionModelDao(final Session session) {
+        this.recordId = (Long) session.getId();
+        this.startTimestamp = new DateTime(session.getStartTimestamp(), DateTimeZone.UTC);
+        this.lastAccessTime = new DateTime(session.getLastAccessTime(), DateTimeZone.UTC);
+        this.timeout = session.getTimeout();
+        this.host = session.getHost();
+        try {
+            this.sessionData = serializeSessionData(session);
+        } catch (IOException e) {
+            this.sessionData = new byte[]{};
+        }
+    }
+
+    public Session toSimpleSession() throws IOException {
+        final SimpleSession simpleSession = new SimpleSession();
+        simpleSession.setId(recordId);
+        simpleSession.setStartTimestamp(startTimestamp.toDate());
+        simpleSession.setLastAccessTime(lastAccessTime.toDate());
+        simpleSession.setTimeout(timeout);
+        simpleSession.setHost(host);
+
+        final Map attributes = serializer.deserialize(sessionData);
+        //noinspection unchecked
+        simpleSession.setAttributes(attributes);
+
+        return simpleSession;
+    }
+
+    public Long getRecordId() {
+        return recordId;
+    }
+
+    public DateTime getStartTimestamp() {
+        return startTimestamp;
+    }
+
+    public DateTime getLastAccessTime() {
+        return lastAccessTime;
+    }
+
+    public long getTimeout() {
+        return timeout;
+    }
+
+    public String getHost() {
+        return host;
+    }
+
+    public byte[] getSessionData() {
+        return sessionData;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder("SessionModelDao{");
+        sb.append("recordId=").append(recordId);
+        sb.append(", startTimestamp=").append(startTimestamp);
+        sb.append(", lastAccessTime=").append(lastAccessTime);
+        sb.append(", timeout=").append(timeout);
+        sb.append(", host='").append(host).append('\'');
+        sb.append(", sessionData=").append(Arrays.toString(sessionData));
+        sb.append('}');
+        return sb.toString();
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        final SessionModelDao that = (SessionModelDao) o;
+
+        if (timeout != that.timeout) {
+            return false;
+        }
+        if (host != null ? !host.equals(that.host) : that.host != null) {
+            return false;
+        }
+        if (lastAccessTime != null ? !lastAccessTime.equals(that.lastAccessTime) : that.lastAccessTime != null) {
+            return false;
+        }
+        if (recordId != null ? !recordId.equals(that.recordId) : that.recordId != null) {
+            return false;
+        }
+        if (!Arrays.equals(sessionData, that.sessionData)) {
+            return false;
+        }
+        if (startTimestamp != null ? !startTimestamp.equals(that.startTimestamp) : that.startTimestamp != null) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = recordId != null ? recordId.hashCode() : 0;
+        result = 31 * result + (startTimestamp != null ? startTimestamp.hashCode() : 0);
+        result = 31 * result + (lastAccessTime != null ? lastAccessTime.hashCode() : 0);
+        result = 31 * result + (int) (timeout ^ (timeout >>> 32));
+        result = 31 * result + (host != null ? host.hashCode() : 0);
+        result = 31 * result + (sessionData != null ? Arrays.hashCode(sessionData) : 0);
+        return result;
+    }
+
+    private byte[] serializeSessionData(final Session session) throws IOException {
+        final Map<Object, Object> sessionAttributes = new HashMap<Object, Object>();
+        for (final Object key : session.getAttributeKeys()) {
+            sessionAttributes.put(key, session.getAttribute(key));
+        }
+
+        return serializer.serialize(sessionAttributes);
+    }
+}
diff --git a/util/src/main/resources/com/ning/billing/util/ddl.sql b/util/src/main/resources/com/ning/billing/util/ddl.sql
index d0b48cd..b586ec2 100644
--- a/util/src/main/resources/com/ning/billing/util/ddl.sql
+++ b/util/src/main/resources/com/ning/billing/util/ddl.sql
@@ -224,3 +224,13 @@ DROP TABLE IF EXISTS notifications;
       search_key2 int(11) unsigned default null,
       PRIMARY KEY(record_id)
   );
+
+create table sessions (
+  record_id int(11) unsigned not null auto_increment
+, start_timestamp datetime not null
+, last_access_time datetime default null
+, timeout int(11)
+, host varchar(100) default null
+, session_data mediumblob default null
+, primary key(record_id)
+);
\ No newline at end of file
diff --git a/util/src/main/resources/com/ning/billing/util/security/shiro/dao/JDBCSessionSqlDao.sql.stg b/util/src/main/resources/com/ning/billing/util/security/shiro/dao/JDBCSessionSqlDao.sql.stg
new file mode 100644
index 0000000..fe228d2
--- /dev/null
+++ b/util/src/main/resources/com/ning/billing/util/security/shiro/dao/JDBCSessionSqlDao.sql.stg
@@ -0,0 +1,51 @@
+group JDBCSessionSqlDao;
+
+read() ::= <<
+select
+  record_id
+, start_timestamp
+, last_access_time
+, timeout
+, host
+, session_data
+from sessions
+where record_id = :recordId
+;
+>>
+
+create() ::= <<
+insert into sessions (
+  start_timestamp
+, last_access_time
+, timeout
+, host
+, session_data
+) values (
+  :startTimestamp
+, :lastAccessTime
+, :timeout
+, :host
+, :sessionData
+);
+>>
+
+update() ::= <<
+update sessions set
+  start_timestamp = :startTimestamp
+, last_access_time = :lastAccessTime
+, timeout = :timeout
+, host = :host
+, session_data = :sessionData
+where record_id = :recordId
+;
+>>
+
+delete() ::= <<
+delete from sessions
+where record_id = :recordId
+;
+>>
+
+getLastInsertId() ::= <<
+select LAST_INSERT_ID();
+>>
diff --git a/util/src/test/java/com/ning/billing/util/glue/TestUtilModuleNoDB.java b/util/src/test/java/com/ning/billing/util/glue/TestUtilModuleNoDB.java
index 70b886f..a5b8594 100644
--- a/util/src/test/java/com/ning/billing/util/glue/TestUtilModuleNoDB.java
+++ b/util/src/test/java/com/ning/billing/util/glue/TestUtilModuleNoDB.java
@@ -16,7 +16,6 @@
 
 package com.ning.billing.util.glue;
 
-import org.apache.shiro.guice.aop.ShiroAopModule;
 import org.skife.config.ConfigSource;
 
 import com.ning.billing.GuicyKillbillTestNoDBModule;
@@ -52,6 +51,8 @@ public class TestUtilModuleNoDB extends TestUtilModule {
 
         installAuditMock();
 
+        install(new KillBillShiroModule());
+        install(new KillBillShiroAopModule());
         install(new SecurityModule());
     }
 }
diff --git a/util/src/test/java/com/ning/billing/util/security/shiro/dao/TestJDBCSessionDao.java b/util/src/test/java/com/ning/billing/util/security/shiro/dao/TestJDBCSessionDao.java
new file mode 100644
index 0000000..1b13ce7
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/util/security/shiro/dao/TestJDBCSessionDao.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.util.security.shiro.dao;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.UUID;
+
+import org.apache.shiro.session.Session;
+import org.apache.shiro.session.mgt.SimpleSession;
+import org.skife.jdbi.v2.DBI;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.ning.billing.util.UtilTestSuiteWithEmbeddedDB;
+
+public class TestJDBCSessionDao extends UtilTestSuiteWithEmbeddedDB {
+
+    @Test(groups = "slow")
+    public void testCRUD() throws Exception {
+        // Note! We are testing the do* methods here to bypass the caching layer
+        final JDBCSessionDao jdbcSessionDao = new JDBCSessionDao((DBI) dbi);
+
+        // Retrieve
+        final SimpleSession session = createSession();
+        Assert.assertNull(jdbcSessionDao.doReadSession(session.getId()));
+
+        // Create
+        final Serializable sessionId = jdbcSessionDao.doCreate(session);
+        final Session retrievedSession = jdbcSessionDao.doReadSession(sessionId);
+        Assert.assertEquals(retrievedSession, session);
+
+        // Update
+        final String newHost = UUID.randomUUID().toString();
+        Assert.assertNotEquals(retrievedSession.getHost(), newHost);
+        session.setHost(newHost);
+        jdbcSessionDao.doUpdate(session);
+        Assert.assertEquals(jdbcSessionDao.doReadSession(sessionId).getHost(), newHost);
+
+        // Delete
+        jdbcSessionDao.doDelete(session);
+        Assert.assertNull(jdbcSessionDao.doReadSession(session.getId()));
+    }
+
+    private SimpleSession createSession() {
+        final SimpleSession simpleSession = new SimpleSession();
+        simpleSession.setStartTimestamp(new Date(System.currentTimeMillis() - 5000));
+        simpleSession.setLastAccessTime(new Date(System.currentTimeMillis()));
+        simpleSession.setTimeout(493934L);
+        simpleSession.setHost(UUID.randomUUID().toString());
+        simpleSession.setAttribute(UUID.randomUUID().toString(), Short.MIN_VALUE);
+        simpleSession.setAttribute(UUID.randomUUID().toString(), Integer.MIN_VALUE);
+        simpleSession.setAttribute(UUID.randomUUID().toString(), Long.MIN_VALUE);
+        simpleSession.setAttribute(UUID.randomUUID().toString(), UUID.randomUUID().toString());
+        // Test with Serializable objects
+        simpleSession.setAttribute(UUID.randomUUID().toString(), UUID.randomUUID());
+        simpleSession.setAttribute(UUID.randomUUID().toString(), new Date(1242));
+        return simpleSession;
+    }
+}
diff --git a/util/src/test/java/com/ning/billing/util/security/shiro/dao/TestSessionModelDao.java b/util/src/test/java/com/ning/billing/util/security/shiro/dao/TestSessionModelDao.java
new file mode 100644
index 0000000..bf14642
--- /dev/null
+++ b/util/src/test/java/com/ning/billing/util/security/shiro/dao/TestSessionModelDao.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2010-2013 Ning, Inc.
+ *
+ * Ning 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 com.ning.billing.util.security.shiro.dao;
+
+import java.util.Date;
+import java.util.UUID;
+
+import org.apache.shiro.session.Session;
+import org.apache.shiro.session.mgt.SimpleSession;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.ning.billing.util.UtilTestSuiteNoDB;
+
+public class TestSessionModelDao extends UtilTestSuiteNoDB {
+
+    @Test(groups = "fast")
+    public void testRoundTrip() throws Exception {
+        final SimpleSession simpleSession = new SimpleSession();
+        simpleSession.setStartTimestamp(new Date(System.currentTimeMillis() - 5000));
+        simpleSession.setLastAccessTime(new Date(System.currentTimeMillis()));
+        simpleSession.setTimeout(493934L);
+        simpleSession.setHost(UUID.randomUUID().toString());
+        simpleSession.setAttribute(UUID.randomUUID(), Short.MIN_VALUE);
+        simpleSession.setAttribute(UUID.randomUUID(), Integer.MIN_VALUE);
+        simpleSession.setAttribute(UUID.randomUUID(), Long.MIN_VALUE);
+        simpleSession.setAttribute(UUID.randomUUID().toString(), UUID.randomUUID().toString());
+        // Test with Serializable objects
+        simpleSession.setAttribute(UUID.randomUUID().toString(), UUID.randomUUID());
+        simpleSession.setAttribute(UUID.randomUUID().toString(), new Date(1242));
+
+        final SessionModelDao sessionModelDao = new SessionModelDao(simpleSession);
+        Assert.assertEquals(sessionModelDao.getTimeout(), simpleSession.getTimeout());
+        Assert.assertEquals(sessionModelDao.getHost(), simpleSession.getHost());
+        Assert.assertTrue(sessionModelDao.getSessionData().length > 0);
+
+        final Session retrievedSession = sessionModelDao.toSimpleSession();
+        Assert.assertEquals(retrievedSession, simpleSession);
+    }
+}
diff --git a/util/src/test/java/com/ning/billing/util/security/TestPermissionAnnotationMethodInterceptor.java b/util/src/test/java/com/ning/billing/util/security/TestPermissionAnnotationMethodInterceptor.java
index fd9247b..2330078 100644
--- a/util/src/test/java/com/ning/billing/util/security/TestPermissionAnnotationMethodInterceptor.java
+++ b/util/src/test/java/com/ning/billing/util/security/TestPermissionAnnotationMethodInterceptor.java
@@ -18,29 +18,25 @@ package com.ning.billing.util.security;
 
 import javax.inject.Singleton;
 
-import org.apache.shiro.SecurityUtils;
-import org.apache.shiro.authc.AuthenticationToken;
-import org.apache.shiro.authc.UsernamePasswordToken;
 import org.apache.shiro.authz.AuthorizationException;
 import org.apache.shiro.authz.UnauthenticatedException;
-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.mockito.Mockito;
+import org.skife.jdbi.v2.IDBI;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
 import com.ning.billing.security.Permission;
 import com.ning.billing.security.RequiresPermissions;
 import com.ning.billing.util.UtilTestSuiteNoDB;
+import com.ning.billing.util.glue.KillBillShiroAopModule;
+import com.ning.billing.util.glue.KillBillShiroModule;
 import com.ning.billing.util.glue.SecurityModule;
 
-import com.google.inject.Binder;
+import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
-import com.google.inject.Module;
 import com.google.inject.Stage;
+import net.sf.ehcache.CacheManager;
 
 public class TestPermissionAnnotationMethodInterceptor extends UtilTestSuiteNoDB {
 
@@ -75,7 +71,18 @@ public class TestPermissionAnnotationMethodInterceptor extends UtilTestSuiteNoDB
 
         // Now, verify the interception works
         configureShiro();
-        final Injector injector = Guice.createInjector(Stage.PRODUCTION, new SecurityModule());
+        // Shutdown the cache manager to avoid duplicate exceptions
+        CacheManager.getInstance().shutdown();
+        final Injector injector = Guice.createInjector(Stage.PRODUCTION,
+                                                       new KillBillShiroModule(),
+                                                       new KillBillShiroAopModule(),
+                                                       new SecurityModule(),
+                                                       new AbstractModule() {
+                                                           @Override
+                                                           protected void configure() {
+                                                               bind(IDBI.class).toInstance(Mockito.mock(IDBI.class));
+                                                           }
+                                                       });
         final AopTester aopedTester = injector.getInstance(AopTester.class);
         verifyAopedTester(aopedTester);
     }
@@ -92,12 +99,17 @@ public class TestPermissionAnnotationMethodInterceptor extends UtilTestSuiteNoDB
 
         // Now, verify the interception works
         configureShiro();
+        // Shutdown the cache manager to avoid duplicate exceptions
+        CacheManager.getInstance().shutdown();
         final Injector injector = Guice.createInjector(Stage.PRODUCTION,
+                                                       new KillBillShiroModule(),
+                                                       new KillBillShiroAopModule(),
                                                        new SecurityModule(),
-                                                       new Module() {
+                                                       new AbstractModule() {
                                                            @Override
-                                                           public void configure(final Binder binder) {
-                                                               binder.bind(IAopTester.class).to(AopTesterImpl.class).asEagerSingleton();
+                                                           public void configure() {
+                                                               bind(IDBI.class).toInstance(Mockito.mock(IDBI.class));
+                                                               bind(IAopTester.class).to(AopTesterImpl.class).asEagerSingleton();
                                                            }
                                                        });
         final IAopTester aopedTester = injector.getInstance(IAopTester.class);