killbill-uncached
Changes
account/killbill-account.iml 2(+2 -0)
beatrix/killbill-beatrix.iml 2(+2 -0)
catalog/killbill-catalog.iml 2(+2 -0)
entitlement/killbill-entitlement.iml 2(+2 -0)
invoice/killbill-invoice.iml 2(+2 -0)
jaxrs/killbill-jaxrs.iml 2(+2 -0)
junction/killbill-junction.iml 2(+2 -0)
osgi/killbill-osgi.iml 2(+2 -0)
overdue/killbill-overdue.iml 2(+2 -0)
payment/killbill-payment.iml 2(+2 -0)
server/killbill-server.iml 3(+2 -1)
server/src/main/webapp/WEB-INF/shiro.ini 11(+3 -8)
server/src/test/resources/shiro.ini 10(+1 -9)
tenant/killbill-tenant.iml 2(+2 -0)
usage/killbill-usage.iml 2(+2 -0)
util/killbill-util.iml 2(+2 -0)
util/pom.xml 9(+9 -0)
util/src/main/java/com/ning/billing/util/security/PermissionAnnotationMethodInterceptor.java 7(+3 -4)
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
account/killbill-account.iml 2(+2 -0)
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" />
beatrix/killbill-beatrix.iml 2(+2 -0)
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" />
catalog/killbill-catalog.iml 2(+2 -0)
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" />
entitlement/killbill-entitlement.iml 2(+2 -0)
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" />
invoice/killbill-invoice.iml 2(+2 -0)
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="" />
jaxrs/killbill-jaxrs.iml 2(+2 -0)
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" />
junction/killbill-junction.iml 2(+2 -0)
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" />
osgi/killbill-osgi.iml 2(+2 -0)
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" />
overdue/killbill-overdue.iml 2(+2 -0)
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" />
payment/killbill-payment.iml 2(+2 -0)
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="" />
server/killbill-server.iml 3(+2 -1)
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();
+ }
+}
server/src/main/webapp/WEB-INF/shiro.ini 11(+3 -8)
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);
+ }
}
server/src/test/resources/shiro.ini 10(+1 -9)
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" />
tenant/killbill-tenant.iml 2(+2 -0)
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" />
usage/killbill-usage.iml 2(+2 -0)
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" />
util/killbill-util.iml 2(+2 -0)
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);