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 {