killbill-memoizeit

security: only create sessions via the /1.0/kb/security/permissions

10/23/2018 5:56:51 AM

Details

diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillBillSessionStorageEvaluator.java b/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillBillSessionStorageEvaluator.java
new file mode 100644
index 0000000..cce4626
--- /dev/null
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillBillSessionStorageEvaluator.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.server.modules;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.shiro.mgt.SessionStorageEvaluator;
+import org.apache.shiro.subject.Subject;
+import org.apache.shiro.web.util.RequestPairSource;
+import org.killbill.billing.jaxrs.resources.JaxrsResource;
+
+public class KillBillSessionStorageEvaluator implements SessionStorageEvaluator {
+
+    @Override
+    public boolean isSessionStorageEnabled(final Subject subject) {
+        if (subject.getSession(false) != null) {
+            // Use what already exists
+            return true;
+        }
+
+        return isSessionCreationEnabled(subject);
+    }
+
+    private boolean isSessionCreationEnabled(final Subject requestPairSource) {
+        if (requestPairSource instanceof RequestPairSource) {
+            final RequestPairSource source = (RequestPairSource) requestPairSource;
+            return isSessionCreationEnabled(source.getServletRequest());
+        }
+        return false; // By default
+    }
+
+    private boolean isSessionCreationEnabled(final ServletRequest request) {
+        if (request != null) {
+            // Only create new sessions via the /1.0/kb/security/permissions endpoint, as this is what is used today
+            // by Kaui to initiate the session.
+            // If we have another use-case one day, we could think about introducing a proper 'login' endpoint...
+            return isPermissionsLookupCall(request);
+        }
+        return false; // By default
+    }
+
+    private boolean isPermissionsLookupCall(final ServletRequest request) {
+        if (request instanceof HttpServletRequest) {
+            final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
+            final String path = httpServletRequest.getPathInfo();
+            return (JaxrsResource.SECURITY_PATH + "/permissions").equals(path);
+        }
+        return false;
+    }
+}
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillBillShiroWebModule.java b/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillBillShiroWebModule.java
index 90b2144..16ce62d 100644
--- a/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillBillShiroWebModule.java
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillBillShiroWebModule.java
@@ -31,8 +31,8 @@ import org.apache.shiro.authc.pam.ModularRealmAuthenticatorWith540;
 import org.apache.shiro.authz.ModularRealmAuthorizer;
 import org.apache.shiro.cache.CacheManager;
 import org.apache.shiro.guice.web.ShiroWebModuleWith435;
+import org.apache.shiro.mgt.SubjectDAO;
 import org.apache.shiro.realm.Realm;
-import org.apache.shiro.session.mgt.DefaultSessionManager;
 import org.apache.shiro.session.mgt.SessionManager;
 import org.apache.shiro.session.mgt.eis.SessionDAO;
 import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
@@ -41,6 +41,7 @@ import org.apache.shiro.web.mgt.WebSecurityManager;
 import org.apache.shiro.web.util.WebUtils;
 import org.killbill.billing.jaxrs.resources.JaxrsResource;
 import org.killbill.billing.server.security.FirstSuccessfulStrategyWith540;
+import org.killbill.billing.server.security.KillBillWebSessionManager;
 import org.killbill.billing.server.security.KillbillJdbcTenantRealm;
 import org.killbill.billing.util.config.definition.RbacConfig;
 import org.killbill.billing.util.config.definition.RedisCacheConfig;
@@ -131,7 +132,9 @@ public class KillBillShiroWebModule extends ShiroWebModuleWith435 {
     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(DefaultSessionManager.class).asEagerSingleton();
+        bind.to(KillBillWebSessionManager.class).asEagerSingleton();
+
+        bind(SubjectDAO.class).toProvider(KillBillWebSubjectDAOProvider.class).asEagerSingleton();
 
         // Magic provider to configure the session DAO
         bind(SessionDAO.class).toProvider(SessionDAOProvider.class).asEagerSingleton();
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillBillWebSubjectDAOProvider.java b/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillBillWebSubjectDAOProvider.java
new file mode 100644
index 0000000..f6a986e
--- /dev/null
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/modules/KillBillWebSubjectDAOProvider.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.server.modules;
+
+import org.apache.shiro.mgt.SubjectDAO;
+import org.killbill.billing.util.glue.KillBillSubjectDAO;
+
+import com.google.inject.Provider;
+
+public class KillBillWebSubjectDAOProvider implements Provider<SubjectDAO> {
+
+    @Override
+    public SubjectDAO get() {
+        final KillBillSubjectDAO killBillSubjectDAO = new KillBillSubjectDAO();
+        killBillSubjectDAO.setSessionStorageEvaluator(new KillBillSessionStorageEvaluator());
+        return killBillSubjectDAO;
+    }
+}
diff --git a/util/src/main/java/org/killbill/billing/util/glue/EhcacheShiroManagerProvider.java b/util/src/main/java/org/killbill/billing/util/glue/EhcacheShiroManagerProvider.java
index 72f355a..0d83057 100644
--- a/util/src/main/java/org/killbill/billing/util/glue/EhcacheShiroManagerProvider.java
+++ b/util/src/main/java/org/killbill/billing/util/glue/EhcacheShiroManagerProvider.java
@@ -28,6 +28,7 @@ import org.apache.shiro.cache.Cache;
 import org.apache.shiro.cache.CacheException;
 import org.apache.shiro.mgt.DefaultSecurityManager;
 import org.apache.shiro.mgt.SecurityManager;
+import org.apache.shiro.mgt.SubjectDAO;
 import org.ehcache.integrations.shiro.EhcacheShiro;
 import org.ehcache.integrations.shiro.EhcacheShiroManager;
 import org.killbill.billing.util.config.definition.EhCacheConfig;
@@ -39,16 +40,19 @@ import com.codahale.metrics.MetricRegistry;
 public class EhcacheShiroManagerProvider extends EhCacheProviderBase implements Provider<EhcacheShiroManager> {
 
     private final SecurityManager securityManager;
+    private final SubjectDAO subjectDAO;
     private final CacheManager eh107CacheManager;
     private final org.ehcache.CacheManager ehcacheCacheManager;
 
     @Inject
     public EhcacheShiroManagerProvider(final SecurityManager securityManager,
+                                       final SubjectDAO subjectDAO,
                                        final CacheManager eh107CacheManager,
                                        final MetricRegistry metricRegistry,
                                        final EhCacheConfig cacheConfig) {
         super(metricRegistry, cacheConfig);
         this.securityManager = securityManager;
+        this.subjectDAO = subjectDAO;
         this.eh107CacheManager = eh107CacheManager;
         this.ehcacheCacheManager = getEhcacheManager();
     }
@@ -63,7 +67,7 @@ public class EhcacheShiroManagerProvider extends EhCacheProviderBase implements 
             // For RBAC only (see also KillbillJdbcTenantRealmProvider)
             final DefaultSecurityManager securityManager = (DefaultSecurityManager) this.securityManager;
             securityManager.setCacheManager(shiroEhCacheManager);
-            securityManager.setSubjectDAO(new KillBillSubjectDAO());
+            securityManager.setSubjectDAO(subjectDAO);
         }
 
         return shiroEhCacheManager;
diff --git a/util/src/main/java/org/killbill/billing/util/glue/KillBillShiroModule.java b/util/src/main/java/org/killbill/billing/util/glue/KillBillShiroModule.java
index 420a565..2f9a3e0 100644
--- a/util/src/main/java/org/killbill/billing/util/glue/KillBillShiroModule.java
+++ b/util/src/main/java/org/killbill/billing/util/glue/KillBillShiroModule.java
@@ -21,6 +21,7 @@ package org.killbill.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.mgt.SubjectDAO;
 import org.apache.shiro.realm.text.IniRealm;
 import org.apache.shiro.session.mgt.DefaultSessionManager;
 import org.apache.shiro.session.mgt.SessionManager;
@@ -132,6 +133,8 @@ public class KillBillShiroModule extends ShiroModule {
     protected void bindSessionManager(final AnnotatedBindingBuilder<SessionManager> bind) {
         bind.to(DefaultSessionManager.class).asEagerSingleton();
 
+        bind(SubjectDAO.class).toProvider(KillBillSubjectDAOProvider.class).asEagerSingleton();
+
         // Magic provider to configure the session DAO
         bind(SessionDAO.class).toProvider(SessionDAOProvider.class).asEagerSingleton();
     }
diff --git a/util/src/main/java/org/killbill/billing/util/glue/KillBillSubjectDAOProvider.java b/util/src/main/java/org/killbill/billing/util/glue/KillBillSubjectDAOProvider.java
new file mode 100644
index 0000000..7efa569
--- /dev/null
+++ b/util/src/main/java/org/killbill/billing/util/glue/KillBillSubjectDAOProvider.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2014-2018 Groupon, Inc
+ * Copyright 2014-2018 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.util.glue;
+
+import org.apache.shiro.mgt.SessionStorageEvaluator;
+import org.apache.shiro.mgt.SubjectDAO;
+import org.apache.shiro.subject.Subject;
+
+import com.google.inject.Provider;
+
+// See org.killbill.billing.server.modules.KillBillWebSubjectDAOProvider for the web version
+public class KillBillSubjectDAOProvider implements Provider<SubjectDAO> {
+
+    @Override
+    public SubjectDAO get() {
+        final KillBillSubjectDAO killBillSubjectDAO = new KillBillSubjectDAO();
+        killBillSubjectDAO.setSessionStorageEvaluator(new SessionStorageEvaluator() {
+            @Override
+            public boolean isSessionStorageEnabled(final Subject subject) {
+                // Use what already exists
+                return subject.getSession(false) != null;
+            }
+        });
+        return killBillSubjectDAO;
+    }
+}
diff --git a/util/src/main/java/org/killbill/billing/util/glue/RedisShiroManagerProvider.java b/util/src/main/java/org/killbill/billing/util/glue/RedisShiroManagerProvider.java
index bcfa133..e992feb 100644
--- a/util/src/main/java/org/killbill/billing/util/glue/RedisShiroManagerProvider.java
+++ b/util/src/main/java/org/killbill/billing/util/glue/RedisShiroManagerProvider.java
@@ -23,6 +23,7 @@ import javax.inject.Provider;
 
 import org.apache.shiro.mgt.DefaultSecurityManager;
 import org.apache.shiro.mgt.SecurityManager;
+import org.apache.shiro.mgt.SubjectDAO;
 import org.redisson.api.RedissonClient;
 
 import com.codahale.metrics.MetricRegistry;
@@ -32,17 +33,20 @@ import static org.killbill.billing.util.glue.CacheModule.REDIS_CACHE_CLIENT;
 
 public class RedisShiroManagerProvider implements Provider<RedisShiroManager> {
 
-    private final CacheManager eh107CacheManager;
     private final SecurityManager securityManager;
+    private final SubjectDAO subjectDAO;
+    private final CacheManager eh107CacheManager;
     private final MetricRegistry metricRegistry;
     private final RedissonClient redissonClient;
 
     @Inject
     public RedisShiroManagerProvider(final SecurityManager securityManager,
+                                     final SubjectDAO subjectDAO,
                                      final CacheManager eh107CacheManager,
                                      final MetricRegistry metricRegistry,
                                      @Named(REDIS_CACHE_CLIENT) final RedissonClient redissonClient) {
         this.securityManager = securityManager;
+        this.subjectDAO = subjectDAO;
         this.eh107CacheManager = eh107CacheManager;
         this.metricRegistry = metricRegistry;
         this.redissonClient = redissonClient;
@@ -57,7 +61,7 @@ public class RedisShiroManagerProvider implements Provider<RedisShiroManager> {
             // For RBAC only (see also KillbillJdbcTenantRealmProvider)
             final DefaultSecurityManager securityManager = (DefaultSecurityManager) this.securityManager;
             securityManager.setCacheManager(shiroRedisManager);
-            securityManager.setSubjectDAO(new KillBillSubjectDAO());
+            securityManager.setSubjectDAO(subjectDAO);
         }
 
         return shiroRedisManager;