killbill-memoizeit

jaxrs, profile: Implement code in swagger handler to correctly

2/27/2018 9:44:10 PM

Details

diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
index ebeca57..44c2a8f 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/AccountResource.java
@@ -141,6 +141,8 @@ import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiResponse;
 import io.swagger.annotations.ApiResponses;
+import io.swagger.annotations.Authorization;
+import io.swagger.annotations.BasicAuthDefinition;
 
 import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/KillBillApiDefinition.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/KillBillApiDefinition.java
index dd5d7d5..e0d18c8 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/KillBillApiDefinition.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/KillBillApiDefinition.java
@@ -17,11 +17,13 @@
 
 package org.killbill.billing.jaxrs.resources;
 
-
 import io.swagger.annotations.SwaggerDefinition;
 import io.swagger.jaxrs.config.ReaderListener;
+import io.swagger.models.Operation;
+import io.swagger.models.Path;
 import io.swagger.models.Swagger;
 import io.swagger.models.auth.BasicAuthDefinition;
+import io.swagger.models.parameters.HeaderParameter;
 
 @SwaggerDefinition
 public class KillBillApiDefinition implements ReaderListener {
@@ -30,13 +32,86 @@ public class KillBillApiDefinition implements ReaderListener {
 
     @Override
     public void beforeScan(final io.swagger.jaxrs.Reader reader, final Swagger swagger) {
-
+        BasicAuthDefinition basicAuthDefinition = new BasicAuthDefinition();
+        swagger.addSecurityDefinition(BASIC_AUTH_SCHEME, basicAuthDefinition);
     }
 
     @Override
     public void afterScan(final io.swagger.jaxrs.Reader reader, final Swagger swagger) {
-        BasicAuthDefinition basicAuthDefinition = new BasicAuthDefinition();
-        swagger.addSecurityDefinition(BASIC_AUTH_SCHEME, basicAuthDefinition);
+
+        final HeaderParameter apiKeyParam = new HeaderParameter();
+        apiKeyParam.setName("X-Killbill-ApiKey");
+        apiKeyParam.setType("string");
+        apiKeyParam.setRequired(true);
+
+        final HeaderParameter apiSecretParam = new HeaderParameter();
+        apiSecretParam.setName("X-Killbill-ApiSecret");
+        apiSecretParam.setType("string");
+        apiSecretParam.setRequired(true);
+
+        for (final String pathName : swagger.getPaths().keySet()) {
+            final Path path = swagger.getPaths().get(pathName);
+            applyExtraSchemaOperation(path.getGet(), pathName, "GET", apiKeyParam, apiSecretParam);
+            applyExtraSchemaOperation(path.getPost(), pathName, "POST", apiKeyParam, apiSecretParam);
+            applyExtraSchemaOperation(path.getPut(), pathName, "PUT", apiKeyParam, apiSecretParam);
+            applyExtraSchemaOperation(path.getDelete(), pathName, "DELETE", apiKeyParam, apiSecretParam);
+            applyExtraSchemaOperation(path.getOptions(), pathName, "OPTIONS", apiKeyParam, apiSecretParam);
+        }
+    }
+
+    private void applyExtraSchemaOperation(final Operation op, final String pathName, final String httpMethod, final HeaderParameter apiKeyParam, final HeaderParameter apiSecretParam) {
+        if (op != null) {
+            op.addSecurity(BASIC_AUTH_SCHEME, null);
+            if (requiresTenantInformation(pathName, httpMethod)) {
+                op.addParameter(apiKeyParam);
+                op.addParameter(apiSecretParam);
+            }
+        }
+    }
+
+    public static boolean requiresTenantInformation(final String path, final String httpMethod) {
+        boolean shouldSkipTenantInfoForRequests = (
+                // Chicken - egg problem
+                isTenantCreationRequest(path, httpMethod) ||
+                // Retrieve user permissions should not require tenant info since this is cross tenants
+                isPermissionRequest(path) ||
+                // Node request are cross tenant
+                isNodeInfoRequest(path) ||
+                // See KillBillShiroWebModule#CorsBasicHttpAuthenticationFilter
+                isOptionsRequest(httpMethod) ||
+                // Shift the responsibility to the plugin
+                isPluginRequest(path) ||
+                // Static resources (welcome screen, Swagger, etc.)
+                isNotKbNorPluginResourceRequest(path, httpMethod));
+        return !shouldSkipTenantInfoForRequests;
+    }
+
+    private static boolean isPermissionRequest(final String path) {
+        return path != null && path.startsWith(JaxrsResource.SECURITY_PATH);
+    }
+
+    private static boolean isTenantCreationRequest(final String path, final String httpMethod) {
+        return JaxrsResource.TENANTS_PATH.equals(path) && "POST".equalsIgnoreCase(httpMethod);
+    }
+
+    private static boolean isNodeInfoRequest(final String path) {
+        return JaxrsResource.NODES_INFO_PATH.equals(path);
+    }
+
+    private static boolean isOptionsRequest(final String httpMethod) {
+        return "OPTIONS".equalsIgnoreCase(httpMethod);
+    }
+
+    private static boolean isNotKbNorPluginResourceRequest(final String path, final String httpMethod) {
+        return !isPluginRequest(path) && !isKbApiRequest(path) && "GET".equalsIgnoreCase(httpMethod);
+    }
+
+    private static boolean isKbApiRequest(final String path) {
+        return path != null && path.startsWith(JaxrsResource.PREFIX);
+    }
+
+    private static boolean isPluginRequest(final String path) {
+        return path != null && path.startsWith(JaxrsResource.PLUGINS_PATH);
     }
 
 }
diff --git a/profiles/killbill/src/main/java/org/killbill/billing/server/security/TenantFilter.java b/profiles/killbill/src/main/java/org/killbill/billing/server/security/TenantFilter.java
index 7b460c0..50b1138 100644
--- a/profiles/killbill/src/main/java/org/killbill/billing/server/security/TenantFilter.java
+++ b/profiles/killbill/src/main/java/org/killbill/billing/server/security/TenantFilter.java
@@ -37,6 +37,7 @@ import org.apache.shiro.authc.UsernamePasswordToken;
 import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
 import org.apache.shiro.realm.Realm;
 import org.killbill.billing.jaxrs.resources.JaxrsResource;
+import org.killbill.billing.jaxrs.resources.KillBillApiDefinition;
 import org.killbill.billing.jaxrs.util.Context;
 import org.killbill.billing.server.listeners.KillbillGuiceListener;
 import org.killbill.billing.tenant.api.Tenant;
@@ -128,66 +129,23 @@ public class TenantFilter implements Filter {
 
     private boolean shouldContinueIfTenantInformationIsWrongOrMissing(final ServletRequest request) {
         boolean shouldContinue = false;
-
         if (request instanceof HttpServletRequest) {
             final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
             final String path = httpServletRequest.getPathInfo();
             final String httpMethod = httpServletRequest.getMethod();
-            if (    // Chicken - egg problem
-                    isTenantCreationRequest(path, httpMethod) ||
-                    // Retrieve user permissions should not require tenant info since this is cross tenants
-                    isPermissionRequest(path) ||
-                    // Node request are cross tenant
-                    isNodeInfoRequest(path) ||
-                    // Metrics servlets
-                    isMetricsRequest(path, httpMethod) ||
-                    // See KillBillShiroWebModule#CorsBasicHttpAuthenticationFilter
-                    isOptionsRequest(httpMethod) ||
-                    // Shift the responsibility to the plugin
-                    isPluginRequest(path) ||
-                    // Static resources (welcome screen, Swagger, etc.)
-                    isNotKbNorPluginResourceRequest(path, httpMethod)
-                    ) {
-                shouldContinue = true;
-            }
+            shouldContinue = shouldContinueIfTenantInformationIsWrongOrMissing(path, httpMethod);
         }
-
         return shouldContinue;
     }
 
-
-
-    private boolean isPermissionRequest(final String path) {
-        return path != null && path.startsWith(JaxrsResource.SECURITY_PATH);
-    }
-
-    private boolean isTenantCreationRequest(final String path, final String httpMethod) {
-        return JaxrsResource.TENANTS_PATH.equals(path) && "POST".equals(httpMethod);
-    }
-
-    private boolean isNodeInfoRequest(final String path) {
-        return JaxrsResource.NODES_INFO_PATH.equals(path);
+    private static boolean isMetricsRequest(final String path, final String httpMethod) {
+        return KillbillGuiceListener.METRICS_SERVLETS_PATHS.contains(path) && "GET".equalsIgnoreCase(httpMethod);
     }
 
-    private boolean isMetricsRequest(final String path, final String httpMethod) {
-        return KillbillGuiceListener.METRICS_SERVLETS_PATHS.contains(path) && "GET".equals(httpMethod);
-    }
-
-    private boolean isOptionsRequest(final String httpMethod) {
-        return "OPTIONS".equals(httpMethod);
-    }
-
-
-    private boolean isNotKbNorPluginResourceRequest(final String path, final String httpMethod) {
-        return !isPluginRequest(path) && !isKbApiRequest(path) && "GET".equals(httpMethod);
-    }
-
-    private boolean isKbApiRequest(final String path) {
-        return path != null && path.startsWith(JaxrsResource.PREFIX);
-    }
 
-    private boolean isPluginRequest(final String path) {
-        return path != null && path.startsWith(JaxrsResource.PLUGINS_PATH);
+    public static boolean shouldContinueIfTenantInformationIsWrongOrMissing(final String path, final String httpMethod) {
+        final boolean requiresTenantInfo = KillBillApiDefinition.requiresTenantInformation(path, httpMethod);
+        return isMetricsRequest(path, httpMethod) || !requiresTenantInfo;
     }
 
     private void sendAuthError(final ServletResponse response, final String errorMessage) throws IOException {