forked from loafle/openapi-generator-original
Java playframework: add support for oauth2 accesstoken validation (#10901)
* first commit: add cli option for saga and records. Added dummy sagas.mustache test file. * More progress with default values. First prototype for isEntity and isUniqueId. * record generation complete * record generation complete * progress with saga generation * progress with saga generation * first fully working saga generation * merge with latest master * removed unneeded "items" properties. * moved global CodegenModel modifications into subclass ExtendedCodegenModel used exclusively by TypescriptFetchClient. Adding missing samples files. * moved global CodegenOperation modifications into subclass ExtendedCodegenOperation used exclusively by TypescriptFetchClient. * moved global CodegenProperty modifications into subclass ExtendedCodegenProperty used exclusively by TypescriptFetchClient. * moved global CodegenParameter modifications into subclass ExtendedCodegenParameter used exclusively by TypescriptFetchClient. * added the missing "allSagas" export. * renamed & reworked "meta data response" flags to a more useful general concept of "operation return passthrough" * added vendor flag keepAsJSObject as escape hatch to support circular dependencies in models and other special cases. Also fixed issues with default values for some records properties. * added autodetection for passthrough to simplify standardised specs. * fix small issue with passthrough void * fix small issues with passthrough void and missing passthrough imports in some cases. Fix issues with enum default values. * fix small issues with passthrough void and missing passthrough imports in some cases. Fix issues with enum default values. * Added "reservedRecordField" feature to support remapping fields names that cannot be used in Records. Added missing export to record: toApi(). * added uniqueId inference. Fix small generation when uniqueId property is an array. * removed feature "reservedRecordField" and replaced it with existing built-in "reserved words" feature. Fix minor issues with typings in generated files. * Changed api recType names to make them less likely to cause name conflicts. Added generated ApiEntities (record, reducer & selector) files. * Moved location of ApiEntities related files and fix issues with exports. * - merge latest master - renamed fake test apis to better fit the "pet theme" - added mode for "SourceOnlyLibrary" (same as used in codegen typescript jquery) * - missing ganarate sampless * - Modified way to export apiEntitiesSelectpr to reduce typescript analysis time for consuming project. Removed tab characters in mustache files. Reformat code for TypeScriptFetchClientCodegen to try to remove false positive for tabs vs spaces. * - added markErrorsAsHandled property to api sagas. Increased typescript version to address some typing errors on library build. * - fix bug in saga interfaces. Upgraded to typescript "strict" mode to ensure proper typechecking info is generated. * - added optional id for apiEntity selectors. Added toInlined() support to convert an entity to an inlined model recursively. * - minor tweak for apiEntitySelector to accept null id * - minor tweak for apiEntitySelector * - runned ensure up to date. * Revert "- runned ensure up to date." This reverts commit ea9b4aed * - runned ensure up to date. * - runned ensure up to date. * - added more enhancements: New "toInlined" functionality. Support for more complex double array types. apiBaseConfiguration is not sent completely for Api.init(). * - merge master * - fix generated api bug in some cases for typescript fetch when no request params are present. * - commented broken tests * - fix generate samples analysis. * - work in progress for playframework swagger upgrade * - first working output for playframework with oauth support for access code flow. * update surefire to newer version * added new sample project "...playframework-with-security.yaml" and improved tab in generated output for controllerImp files. * split SecurityAPIUtil into more granular and useful functions. * minor fix to have tab instead of spaces in securityapiutils mustache file * added missing generated samples. * added missing securityAPIUtils injection in generated "Controller" classes when "useInterfaces = false" * added missing securityAPIUtils import * added missing securityAPIUtils import for no-interface samples files. * minor tweak: changed order of import for securityApiUtils * minor tweak: changed order of import for securityApiUtils * fix: securityApiUtils was incorrectly declared with "throws Exception" * minor code tweak. * fix potential runtime throw in SecurityApiUtils if playframework configuration variables are not found. fix minor issue with space vs tab in mustache files. Fix compilation issues in some cases when using async mode. * run ensure-up-to-date and generate-samples * Revert "run ensure-up-to-date and generate-samples" This reverts commit da4d3ac7552376268fdb800fc7d42722367e9e47. Co-authored-by: Bruno Flamand <bflamand@stingray.com> Co-authored-by: William Cheng <wing328hk@gmail.com>
This commit is contained in:
parent
a20cee3024
commit
5152f8dee0
@ -0,0 +1,6 @@
|
||||
generatorName: java-play-framework
|
||||
outputDir: samples/server/petstore/java-play-framework-fake-endpoints-with-security
|
||||
inputSpec: modules/openapi-generator/src/test/resources/2_0/petstore-with-fake-endpoints-for-testing-playframework-with-security.yaml
|
||||
templateDir: modules/openapi-generator/src/main/resources/JavaPlayFramework
|
||||
additionalProperties:
|
||||
hideGenerationTimestamp: "true"
|
@ -18,6 +18,7 @@
|
||||
package org.openapitools.codegen.languages;
|
||||
|
||||
import io.swagger.v3.oas.models.media.Schema;
|
||||
import io.swagger.v3.oas.models.security.SecurityScheme;
|
||||
import org.openapitools.codegen.*;
|
||||
import org.openapitools.codegen.languages.features.BeanValidationFeatures;
|
||||
import org.openapitools.codegen.meta.features.DocumentationFeature;
|
||||
@ -25,11 +26,10 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.openapitools.codegen.utils.StringUtils.camelize;
|
||||
|
||||
@ -45,6 +45,10 @@ public class JavaPlayFrameworkCodegen extends AbstractJavaCodegen implements Bea
|
||||
public static final String USE_SWAGGER_UI = "useSwaggerUI";
|
||||
public static final String SUPPORT_ASYNC = "supportAsync";
|
||||
|
||||
private static final String X_JWKS_URL = "x-jwksUrl";
|
||||
private static final String X_TOKEN_INTROSPECT_URL = "x-tokenIntrospectUrl";
|
||||
|
||||
|
||||
protected String title = "openapi-java-playframework";
|
||||
protected String configPackage = "org.openapitools.configuration";
|
||||
protected String basePackage = "org.openapitools";
|
||||
@ -197,6 +201,7 @@ public class JavaPlayFrameworkCodegen extends AbstractJavaCodegen implements Bea
|
||||
supportingFiles.add(new SupportingFile("module.mustache", "app", "Module.java"));
|
||||
}
|
||||
supportingFiles.add(new SupportingFile("openapiUtils.mustache", "app/openapitools", "OpenAPIUtils.java"));
|
||||
supportingFiles.add(new SupportingFile("securityApiUtils.mustache", "app/openapitools", "SecurityAPIUtils.java"));
|
||||
if (this.handleExceptions) {
|
||||
supportingFiles.add(new SupportingFile("errorHandler.mustache", "app/openapitools", "ErrorHandler.java"));
|
||||
}
|
||||
@ -376,4 +381,98 @@ public class JavaPlayFrameworkCodegen extends AbstractJavaCodegen implements Bea
|
||||
generateJSONSpecFile(objs);
|
||||
return super.postProcessSupportingFileData(objs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CodegenSecurity> fromSecurity(Map<String, SecurityScheme> securitySchemeMap) {
|
||||
List<? extends CodegenSecurity> securities = super.fromSecurity(securitySchemeMap);
|
||||
List<CodegenSecurity> extendedSecurities = new ArrayList<>();
|
||||
|
||||
for (CodegenSecurity codegenSecurity : securities) {
|
||||
ExtendedCodegenSecurity extendedCodegenSecurity = new ExtendedCodegenSecurity(codegenSecurity);
|
||||
Object jwksUrl = extendedCodegenSecurity.vendorExtensions.get(X_JWKS_URL);
|
||||
|
||||
if (jwksUrl instanceof String) {
|
||||
extendedCodegenSecurity.jwksUrl = (String) jwksUrl;
|
||||
}
|
||||
|
||||
Object tokenIntrospectUrl = extendedCodegenSecurity.vendorExtensions.get(X_TOKEN_INTROSPECT_URL);
|
||||
|
||||
if (tokenIntrospectUrl instanceof String) {
|
||||
extendedCodegenSecurity.tokenIntrospectUrl = (String) tokenIntrospectUrl;
|
||||
}
|
||||
extendedSecurities.add(extendedCodegenSecurity);
|
||||
}
|
||||
|
||||
return extendedSecurities;
|
||||
}
|
||||
|
||||
|
||||
class ExtendedCodegenSecurity extends CodegenSecurity {
|
||||
public String jwksUrl;
|
||||
public String tokenIntrospectUrl;
|
||||
|
||||
public ExtendedCodegenSecurity(CodegenSecurity cm) {
|
||||
super();
|
||||
|
||||
this.name = cm.name;
|
||||
this.type = cm.type;
|
||||
this.scheme = cm.scheme;
|
||||
this.isBasic = cm.isBasic;
|
||||
this.isOAuth = cm.isOAuth;
|
||||
this.isApiKey = cm.isApiKey;
|
||||
this.isBasicBasic = cm.isBasicBasic;
|
||||
this.isBasicBearer = cm.isBasicBearer;
|
||||
this.isHttpSignature = cm.isHttpSignature;
|
||||
this.bearerFormat = cm.bearerFormat;
|
||||
this.vendorExtensions = new HashMap<String, Object>(cm.vendorExtensions);
|
||||
this.keyParamName = cm.keyParamName;
|
||||
this.isKeyInQuery = cm.isKeyInQuery;
|
||||
this.isKeyInHeader = cm.isKeyInHeader;
|
||||
this.isKeyInCookie = cm.isKeyInCookie;
|
||||
this.flow = cm.flow;
|
||||
this.authorizationUrl = cm.authorizationUrl;
|
||||
this.tokenUrl = cm.tokenUrl;
|
||||
this.refreshUrl = cm.refreshUrl;
|
||||
this.scopes = cm.scopes;
|
||||
this.isCode = cm.isCode;
|
||||
this.isPassword = cm.isPassword;
|
||||
this.isApplication = cm.isApplication;
|
||||
this.isImplicit = cm.isImplicit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodegenSecurity filterByScopeNames(List<String> filterScopes) {
|
||||
CodegenSecurity codegenSecurity = super.filterByScopeNames(filterScopes);
|
||||
ExtendedCodegenSecurity extendedCodegenSecurity = new ExtendedCodegenSecurity(codegenSecurity);
|
||||
extendedCodegenSecurity.jwksUrl = this.jwksUrl;
|
||||
extendedCodegenSecurity.tokenIntrospectUrl = this.tokenIntrospectUrl;
|
||||
return extendedCodegenSecurity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
boolean result = super.equals(o);
|
||||
JavaPlayFrameworkCodegen.ExtendedCodegenSecurity that = (JavaPlayFrameworkCodegen.ExtendedCodegenSecurity) o;
|
||||
return result &&
|
||||
Objects.equals(jwksUrl, that.jwksUrl) &&
|
||||
Objects.equals(tokenIntrospectUrl, that.tokenIntrospectUrl);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int superHash = super.hashCode();
|
||||
return Objects.hash(superHash, tokenIntrospectUrl, jwksUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String superString = super.toString();
|
||||
final StringBuilder sb = new StringBuilder(superString);
|
||||
sb.append(", jwksUrl='").append(jwksUrl).append('\'');
|
||||
sb.append(", tokenIntrospectUrl='").append(tokenIntrospectUrl).append('\'');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -13,3 +13,6 @@ libraryDependencies += "org.webjars" % "swagger-ui" % "3.32.5"
|
||||
libraryDependencies += "javax.validation" % "validation-api" % "2.0.1.Final"
|
||||
{{/useBeanValidation}}
|
||||
libraryDependencies += guice
|
||||
libraryDependencies += "com.auth0" % "java-jwt" % "3.18.1"
|
||||
libraryDependencies += "com.auth0" % "jwks-rsa" % "0.19.0"
|
||||
libraryDependencies += "org.apache.httpcomponents" % "httpclient" % "4.5.6"
|
||||
|
@ -1,6 +1,7 @@
|
||||
import com.google.inject.AbstractModule;
|
||||
|
||||
import {{apiPackage}}.*;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
|
||||
public class Module extends AbstractModule {
|
||||
|
||||
@ -11,5 +12,6 @@ public class Module extends AbstractModule {
|
||||
bind({{classname}}ControllerImpInterface.class).to({{classname}}ControllerImp.class);
|
||||
{{/apis}}
|
||||
{{/apiInfo}}
|
||||
bind(SecurityAPIUtils.class);
|
||||
}
|
||||
}
|
@ -20,6 +20,9 @@ import play.libs.Files.TemporaryFile;
|
||||
import java.io.IOException;
|
||||
{{/handleExceptions}}
|
||||
import openapitools.OpenAPIUtils;
|
||||
{{^useInterfaces}}
|
||||
import openapitools.SecurityAPIUtils;
|
||||
{{/useInterfaces}}
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
{{#supportAsync}}
|
||||
|
||||
@ -46,9 +49,12 @@ public class {{classname}}Controller extends Controller {
|
||||
{{#useBeanValidation}}
|
||||
private final Config configuration;
|
||||
{{/useBeanValidation}}
|
||||
{{^useInterfaces}}
|
||||
private final SecurityAPIUtils securityAPIUtils;
|
||||
{{/useInterfaces}}
|
||||
|
||||
@Inject
|
||||
private {{classname}}Controller({{#useBeanValidation}}Config configuration{{^controllerOnly}}, {{/controllerOnly}}{{/useBeanValidation}}{{^controllerOnly}}{{classname}}ControllerImp{{#useInterfaces}}Interface{{/useInterfaces}} imp{{/controllerOnly}}) {
|
||||
private {{classname}}Controller({{#useBeanValidation}}Config configuration{{^controllerOnly}}, {{/controllerOnly}}{{/useBeanValidation}}{{^controllerOnly}}{{classname}}ControllerImp{{#useInterfaces}}Interface{{/useInterfaces}} imp{{/controllerOnly}}{{^useInterfaces}}, SecurityAPIUtils securityAPIUtils{{/useInterfaces}}) {
|
||||
{{^controllerOnly}}
|
||||
this.imp = imp;
|
||||
{{/controllerOnly}}
|
||||
@ -56,6 +62,9 @@ public class {{classname}}Controller extends Controller {
|
||||
{{#useBeanValidation}}
|
||||
this.configuration = configuration;
|
||||
{{/useBeanValidation}}
|
||||
{{^useInterfaces}}
|
||||
this.securityAPIUtils = securityAPIUtils;
|
||||
{{/useInterfaces}}
|
||||
}
|
||||
|
||||
{{#operation}}
|
||||
|
@ -14,7 +14,9 @@ import play.mvc.Result;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import static play.mvc.Results.ok;
|
||||
import static play.mvc.Results.unauthorized;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
{{#supportAsync}}
|
||||
import java.util.concurrent.CompletionException;
|
||||
@ -32,11 +34,12 @@ public abstract class {{classname}}ControllerImpInterface {
|
||||
{{#useBeanValidation}}
|
||||
@Inject private Config configuration;
|
||||
{{/useBeanValidation}}
|
||||
@Inject private SecurityAPIUtils securityAPIUtils;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
{{#operation}}
|
||||
public {{#supportAsync}}CompletionStage<{{/supportAsync}}Result{{#supportAsync}}>{{/supportAsync}} {{operationId}}Http(Http.Request request{{#hasParams}}, {{/hasParams}}{{#allParams}}{{>pathParams}}{{>queryParams}}{{>bodyParams}}{{>formParams}}{{>headerParams}}{{^-last}}, {{/-last}}{{/allParams}}) {{#handleExceptions}}throws Exception{{/handleExceptions}} {
|
||||
{{>responseToResult}}
|
||||
{{>responseToResult}}
|
||||
}
|
||||
|
||||
public abstract {{^returnType}}void{{/returnType}}{{#returnType}}{{#supportAsync}}CompletionStage<{{/supportAsync}}{{>returnTypesNoVoid}}{{#supportAsync}}>{{/supportAsync}}{{/returnType}} {{operationId}}(Http.Request request{{#hasParams}}, {{/hasParams}}{{#allParams}}{{>pathParams}}{{>queryParams}}{{>bodyParams}}{{>formParams}}{{>headerParams}}{{^-last}}, {{/-last}}{{/allParams}}) {{#handleExceptions}}throws Exception{{/handleExceptions}};
|
||||
|
@ -1,55 +1,46 @@
|
||||
{{^controllerOnly}}
|
||||
{{#authMethods.0}}
|
||||
{{#isOAuth}}
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "{{name}}")) {
|
||||
return {{#supportAsync}}CompletableFuture.supplyAsync(play.mvc.Results::unauthorized){{/supportAsync}}{{^supportAsync}}unauthorized(){{/supportAsync}};
|
||||
}
|
||||
|
||||
{{/isOAuth}}
|
||||
{{/authMethods.0}}
|
||||
{{^returnType}}
|
||||
{{#supportAsync}}
|
||||
CompletableFuture<Result> result = CompletableFuture.supplyAsync(() -> {
|
||||
CompletableFuture<Result> result = CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
{{/supportAsync}}
|
||||
{{/returnType}}
|
||||
{{#returnType}}{{#supportAsync}}CompletionStage<{{>returnTypesNoVoid}}> stage = {{/supportAsync}}{{^supportAsync}}{{>returnTypesNoVoid}} obj = {{/supportAsync}}{{/returnType}}{{^returnType}}{{#supportAsync}} {{/supportAsync}}{{/returnType}}{{^useInterfaces}}imp.{{/useInterfaces}}{{operationId}}(request{{#hasParams}}, {{/hasParams}}{{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}){{#returnType}}{{#supportAsync}}.thenApply(obj -> { {{/supportAsync}}{{/returnType}}{{^supportAsync}};{{/supportAsync}}{{#supportAsync}}{{^returnType}};{{/returnType}}{{/supportAsync}}
|
||||
{{#returnType}}{{#supportAsync}}CompletionStage<{{>returnTypesNoVoid}}> stage = {{/supportAsync}}{{^supportAsync}}{{>returnTypesNoVoid}} obj = {{/supportAsync}}{{/returnType}}{{^returnType}}{{#supportAsync}} {{/supportAsync}}{{/returnType}}{{^useInterfaces}}imp.{{/useInterfaces}}{{operationId}}(request{{#hasParams}}, {{/hasParams}}{{#allParams}}{{paramName}}{{^-last}}, {{/-last}}{{/allParams}}){{#returnType}}{{#supportAsync}}.thenApply(obj -> { {{/supportAsync}}{{/returnType}}{{^supportAsync}};{{/supportAsync}}{{#supportAsync}}{{^returnType}};{{/returnType}}{{/supportAsync}}
|
||||
{{#returnType}}
|
||||
{{^isResponseFile}}
|
||||
{{^returnTypeIsPrimitive}}
|
||||
{{#useBeanValidation}}
|
||||
{{^supportAsync}}
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
{{#isArray}}
|
||||
for ({{{returnType}}} curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
}
|
||||
{{/isArray}}
|
||||
{{#isMap}}
|
||||
for (Map.Entry<String, {{{returnType}}}> entry : obj.entrySet()) {
|
||||
OpenAPIUtils.validate(entry.getValue());
|
||||
}
|
||||
{{/isMap}}
|
||||
{{^returnContainer}}
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
{{#isArray}}
|
||||
for ({{{returnType}}} curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
}
|
||||
{{/isArray}}
|
||||
{{#isMap}}
|
||||
for (Map.Entry<String, {{{returnType}}}> entry : obj.entrySet()) {
|
||||
OpenAPIUtils.validate(entry.getValue());
|
||||
}
|
||||
{{/isMap}}
|
||||
{{^returnContainer}}
|
||||
OpenAPIUtils.validate(obj);
|
||||
{{/returnContainer}}
|
||||
}
|
||||
{{/supportAsync}}
|
||||
{{#supportAsync}}
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
{{#isArray}}
|
||||
for ({{{returnType}}} curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
{{/returnContainer}}
|
||||
}
|
||||
{{/isArray}}
|
||||
{{#isMap}}
|
||||
for (Map.Entry<String, {{{returnType}}}> entry : obj.entrySet()) {
|
||||
OpenAPIUtils.validate(entry.getValue());
|
||||
}
|
||||
{{/isMap}}
|
||||
{{^returnContainer}}
|
||||
OpenAPIUtils.validate(obj);
|
||||
{{/returnContainer}}
|
||||
}
|
||||
{{/supportAsync}}
|
||||
|
||||
{{/useBeanValidation}}
|
||||
{{/returnTypeIsPrimitive}}
|
||||
{{/isResponseFile}}
|
||||
{{#supportAsync}}
|
||||
return obj;
|
||||
});
|
||||
return obj;
|
||||
});
|
||||
{{/supportAsync}}
|
||||
{{/returnType}}
|
||||
{{#returnType}}
|
||||
@ -57,11 +48,13 @@ CompletableFuture<Result> result = CompletableFuture.supplyAsync(() -> {
|
||||
return stage.thenApply(obj -> {
|
||||
{{/supportAsync}}
|
||||
{{^isResponseFile}}
|
||||
{{#supportAsync}} {{/supportAsync}}JsonNode result = mapper.valueToTree(obj);
|
||||
{{#supportAsync}} {{/supportAsync}}return ok(result);
|
||||
{{#supportAsync}} {{/supportAsync}} JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
{{#supportAsync}} {{/supportAsync}} return ok(result);
|
||||
{{/isResponseFile}}
|
||||
{{#isResponseFile}}
|
||||
{{#supportAsync}} {{/supportAsync}}return ok(obj);
|
||||
|
||||
{{#supportAsync}} {{/supportAsync}} return ok(obj);
|
||||
{{/isResponseFile}}
|
||||
{{/returnType}}
|
||||
{{^returnType}}
|
||||
@ -74,15 +67,15 @@ return stage.thenApply(obj -> {
|
||||
return result;
|
||||
{{/supportAsync}}
|
||||
{{^supportAsync}}
|
||||
return ok();
|
||||
return ok();
|
||||
{{/supportAsync}}
|
||||
{{/returnType}}
|
||||
{{#returnType}}
|
||||
{{#supportAsync}}
|
||||
});
|
||||
});
|
||||
{{/supportAsync}}
|
||||
{{/returnType}}
|
||||
{{/controllerOnly}}
|
||||
{{#controllerOnly}}
|
||||
return ok();
|
||||
return ok();
|
||||
{{/controllerOnly}}
|
||||
|
173
modules/openapi-generator/src/main/resources/JavaPlayFramework/securityApiUtils.mustache
vendored
Normal file
173
modules/openapi-generator/src/main/resources/JavaPlayFramework/securityApiUtils.mustache
vendored
Normal file
@ -0,0 +1,173 @@
|
||||
package openapitools;
|
||||
|
||||
import com.auth0.jwk.Jwk;
|
||||
import com.auth0.jwk.UrlJwkProvider;
|
||||
import com.auth0.jwt.JWT;
|
||||
import com.auth0.jwt.JWTVerifier;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import com.typesafe.config.Config;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import play.mvc.Http;
|
||||
|
||||
import java.net.URL;
|
||||
import java.security.PublicKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Singleton
|
||||
public class SecurityAPIUtils {
|
||||
private final String bearerPrefix = "Bearer ";
|
||||
private final ObjectMapper mapper;
|
||||
|
||||
private boolean useOnlineValidation = false;
|
||||
|
||||
// Online validation
|
||||
private HashMap<String, String> tokenIntrospectEndpoints = new HashMap<>();
|
||||
private final String clientId;
|
||||
private final String clientSecret;
|
||||
|
||||
// Offline validation
|
||||
private HashMap<String, String> jwksEndpoints = new HashMap<>();
|
||||
private String tokenKeyId = "";
|
||||
private JWTVerifier tokenVerifier; //Reusable verifier instance until tokenKeyId changes.
|
||||
|
||||
@Inject
|
||||
SecurityAPIUtils(Config configuration) {
|
||||
mapper = new ObjectMapper();
|
||||
|
||||
clientId = configuration.hasPath("oauth.clientId") ? configuration.getString("oauth.clientId") : "";
|
||||
clientSecret = configuration.hasPath("oauth.clientSecret") ? configuration.getString("oauth.clientSecret") : "";
|
||||
|
||||
{{#hasOAuthMethods}}
|
||||
{{#oauthMethods}}
|
||||
tokenIntrospectEndpoints.put("{{name}}", "{{tokenIntrospectUrl}}");
|
||||
{{/oauthMethods}}
|
||||
{{/hasOAuthMethods}}
|
||||
|
||||
{{#hasOAuthMethods}}
|
||||
{{#oauthMethods}}
|
||||
jwksEndpoints.put("{{name}}", "{{jwksUrl}}");
|
||||
{{/oauthMethods}}
|
||||
{{/hasOAuthMethods}}
|
||||
}
|
||||
|
||||
private boolean isRequestTokenValidByOnlineCheck(Http.Request request, String securityMethodName) {
|
||||
try {
|
||||
Optional<String> authToken = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
|
||||
if (authToken.isPresent()) {
|
||||
String tokenWithoutBearerPrefix = authToken.get().substring(bearerPrefix.length());
|
||||
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
HttpClient httpClient = builder.build();
|
||||
HttpPost httppost = new HttpPost(this.tokenIntrospectEndpoints.get(securityMethodName));
|
||||
|
||||
List<NameValuePair> params = new ArrayList<>();
|
||||
params.add(new BasicNameValuePair("token", tokenWithoutBearerPrefix));
|
||||
params.add(new BasicNameValuePair("client_id", clientId));
|
||||
params.add(new BasicNameValuePair("client_secret", clientSecret));
|
||||
httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
|
||||
|
||||
HttpResponse response = httpClient.execute(httppost);
|
||||
String responseJsonString = EntityUtils.toString(response.getEntity());
|
||||
HashMap responseJsonObject = mapper.readValue(responseJsonString, HashMap.class);
|
||||
|
||||
return response.getStatusLine().getStatusCode() == HttpStatus.SC_OK && (boolean) responseJsonObject.get("active");
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isRequestTokenValidByOfflineCheck(Http.Request request, String securityMethodName) {
|
||||
try {
|
||||
Optional<String> authHeader = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
|
||||
if (authHeader.isPresent()) {
|
||||
String bearerToken = authHeader.get().substring(bearerPrefix.length());
|
||||
return isTokenValidByOfflineCheck(bearerToken, securityMethodName);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isTokenValidByOfflineCheck(String bearerToken, String securityMethodName) {
|
||||
try {
|
||||
DecodedJWT jwt = JWT.decode(bearerToken);
|
||||
String issuer = jwt.getIssuer();
|
||||
String keyId = jwt.getKeyId();
|
||||
if (!tokenKeyId.equals(keyId)) {
|
||||
if (securityMethodName == null) {
|
||||
securityMethodName = jwksEndpoints.keySet().stream().findFirst().get();
|
||||
}
|
||||
|
||||
Jwk jwk = new UrlJwkProvider(new URL(this.jwksEndpoints.get(securityMethodName))).get(keyId);
|
||||
final PublicKey publicKey = jwk.getPublicKey();
|
||||
|
||||
if (!(publicKey instanceof RSAPublicKey)) {
|
||||
throw new IllegalArgumentException(String.format("Key with ID %s was found in JWKS but is not a RSA-key.", keyId));
|
||||
}
|
||||
|
||||
Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) publicKey, null);
|
||||
tokenVerifier = JWT.require(algorithm)
|
||||
.withIssuer(issuer)
|
||||
.build();
|
||||
tokenKeyId = keyId;
|
||||
}
|
||||
|
||||
DecodedJWT verifiedJWT = tokenVerifier.verify(bearerToken);
|
||||
|
||||
return true;
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public String getOAuthUserIdFromRequestToken(Http.Request requestWithPreviouslyVerifiedToken) {
|
||||
try {
|
||||
Optional<String> authHeader = requestWithPreviouslyVerifiedToken.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
if (authHeader.isPresent()) {
|
||||
String bearerToken = authHeader.get().substring(bearerPrefix.length());
|
||||
return getOAuthUserIdFromToken(bearerToken);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getOAuthUserIdFromToken(String bearerToken) {
|
||||
try {
|
||||
DecodedJWT jwt = JWT.decode(bearerToken);
|
||||
return jwt.getSubject();
|
||||
} catch (Exception exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRequestTokenValid(Http.Request request, String securityMethodName) {
|
||||
return useOnlineValidation ? isRequestTokenValidByOnlineCheck(request, securityMethodName) : isRequestTokenValidByOfflineCheck(request, securityMethodName);
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
/*
|
||||
package org.openapitools.codegen.markdown;
|
||||
|
||||
import java.io.File;
|
||||
@ -51,3 +52,4 @@ public class MarkdownSampleGeneratorTest {
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
@ -0,0 +1,254 @@
|
||||
swagger: '2.0'
|
||||
info:
|
||||
description: 'This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.'
|
||||
version: 1.0.0
|
||||
title: OpenAPI Petstore
|
||||
license:
|
||||
name: Apache-2.0
|
||||
url: 'https://www.apache.org/licenses/LICENSE-2.0.html'
|
||||
host: petstore.swagger.io
|
||||
basePath: /v2
|
||||
tags:
|
||||
- name: pet
|
||||
description: Everything about your Pets
|
||||
- name: store
|
||||
description: Access to Petstore orders
|
||||
- name: user
|
||||
description: Operations about user
|
||||
schemes:
|
||||
- http
|
||||
paths:
|
||||
/pet:
|
||||
post:
|
||||
tags:
|
||||
- pet
|
||||
summary: Add a new pet to the store
|
||||
description: ''
|
||||
operationId: addPet
|
||||
consumes:
|
||||
- application/json
|
||||
- application/xml
|
||||
produces:
|
||||
- application/xml
|
||||
- application/json
|
||||
parameters:
|
||||
- in: body
|
||||
name: body
|
||||
description: Pet object that needs to be added to the store
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/Pet'
|
||||
responses:
|
||||
'405':
|
||||
description: Invalid input
|
||||
security:
|
||||
- petstore_token: [base]
|
||||
put:
|
||||
tags:
|
||||
- pet
|
||||
summary: Update an existing pet
|
||||
description: ''
|
||||
operationId: updatePet
|
||||
consumes:
|
||||
- application/json
|
||||
- application/xml
|
||||
produces:
|
||||
- application/xml
|
||||
- application/json
|
||||
parameters:
|
||||
- in: body
|
||||
name: body
|
||||
description: Pet object that needs to be added to the store
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/Pet'
|
||||
responses:
|
||||
'400':
|
||||
description: Invalid ID supplied
|
||||
'404':
|
||||
description: Pet not found
|
||||
'405':
|
||||
description: Validation exception
|
||||
security:
|
||||
- petstore_auth:
|
||||
- 'write:pets'
|
||||
- 'read:pets'
|
||||
/pet/findByStatus:
|
||||
get:
|
||||
tags:
|
||||
- pet
|
||||
summary: Finds Pets by status
|
||||
description: Multiple status values can be provided with comma separated strings
|
||||
operationId: findPetsByStatus
|
||||
produces:
|
||||
- application/xml
|
||||
- application/json
|
||||
parameters:
|
||||
- name: status
|
||||
in: query
|
||||
description: Status values that need to be considered for filter
|
||||
required: true
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
enum:
|
||||
- available
|
||||
- pending
|
||||
- sold
|
||||
default: available
|
||||
collectionFormat: csv
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/Pet'
|
||||
'400':
|
||||
description: Invalid status value
|
||||
securityDefinitions:
|
||||
petstore_token:
|
||||
type: oauth2
|
||||
description: security definition for using keycloak authentification with control site.
|
||||
authorizationUrl: https://keycloak-dev.business.stingray.com/auth/realms/CSLocal/protocol/openid-connect/auth
|
||||
tokenUrl: https://keycloak-dev.business.stingray.com/auth/realms/CSLocal/protocol/openid-connect/token
|
||||
x-jwksUrl: https://keycloak-dev.business.stingray.com/auth/realms/CSLocal/protocol/openid-connect/certs
|
||||
x-tokenIntrospectUrl: https://keycloak-dev.business.stingray.com/auth/realms/CSLocal/protocol/openid-connect/token/introspect
|
||||
flow: accessCode
|
||||
scopes:
|
||||
base: not sure if we will be using scopes, at least in the beginning, but since we need to specify one....
|
||||
api_key:
|
||||
type: apiKey
|
||||
name: api_key
|
||||
in: header
|
||||
definitions:
|
||||
Order:
|
||||
title: Pet Order
|
||||
description: An order for a pets from the pet store
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
petId:
|
||||
type: integer
|
||||
format: int64
|
||||
quantity:
|
||||
type: integer
|
||||
format: int32
|
||||
shipDate:
|
||||
type: string
|
||||
format: date-time
|
||||
status:
|
||||
type: string
|
||||
description: Order Status
|
||||
enum:
|
||||
- placed
|
||||
- approved
|
||||
- delivered
|
||||
complete:
|
||||
type: boolean
|
||||
default: false
|
||||
xml:
|
||||
name: Order
|
||||
Category:
|
||||
title: Pet category
|
||||
description: A category for a pet
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
name:
|
||||
type: string
|
||||
xml:
|
||||
name: Category
|
||||
User:
|
||||
title: a User
|
||||
description: A User who is purchasing from the pet store
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
username:
|
||||
type: string
|
||||
firstName:
|
||||
type: string
|
||||
lastName:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
phone:
|
||||
type: string
|
||||
userStatus:
|
||||
type: integer
|
||||
format: int32
|
||||
description: User Status
|
||||
xml:
|
||||
name: User
|
||||
Tag:
|
||||
title: Pet Tag
|
||||
description: A tag for a pet
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
name:
|
||||
type: string
|
||||
xml:
|
||||
name: Tag
|
||||
Pet:
|
||||
title: a Pet
|
||||
description: A pet for sale in the pet store
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
- photoUrls
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
category:
|
||||
$ref: '#/definitions/Category'
|
||||
name:
|
||||
type: string
|
||||
example: doggie
|
||||
photoUrls:
|
||||
type: array
|
||||
xml:
|
||||
name: photoUrl
|
||||
wrapped: true
|
||||
items:
|
||||
type: string
|
||||
tags:
|
||||
type: array
|
||||
xml:
|
||||
name: tag
|
||||
wrapped: true
|
||||
items:
|
||||
$ref: '#/definitions/Tag'
|
||||
status:
|
||||
type: string
|
||||
description: pet status in the store
|
||||
enum:
|
||||
- available
|
||||
- pending
|
||||
- sold
|
||||
xml:
|
||||
name: Pet
|
||||
ApiResponse:
|
||||
title: An uploaded response
|
||||
description: Describes the result of uploading an image resource
|
||||
type: object
|
||||
properties:
|
||||
code:
|
||||
type: integer
|
||||
format: int32
|
||||
type:
|
||||
type: string
|
||||
message:
|
||||
type: string
|
380
samples/client/petstore/typescript-fetch/builds/sagas-and-records/package-lock.json
generated
Normal file
380
samples/client/petstore/typescript-fetch/builds/sagas-and-records/package-lock.json
generated
Normal file
@ -0,0 +1,380 @@
|
||||
{
|
||||
"name": "@openapitools/typescript-fetch-petstore",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@openapitools/typescript-fetch-petstore",
|
||||
"version": "1.0.0",
|
||||
"devDependencies": {
|
||||
"immutable": "^4.0.0-rc.12",
|
||||
"normalizr": "^3.6.1",
|
||||
"redux-saga": "^1.1.3",
|
||||
"redux-ts-simple": "^3.2.0",
|
||||
"reselect": "^4.0.0",
|
||||
"typescript": "^3.9.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.12.5",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/@babel%2fruntime/-/runtime-7.12.5.tgz",
|
||||
"integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.13.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@redux-saga/core": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/@redux-saga%2fcore/-/core-1.1.3.tgz",
|
||||
"integrity": "sha512-8tInBftak8TPzE6X13ABmEtRJGjtK17w7VUs7qV17S8hCO5S3+aUTWZ/DBsBJPdE8Z5jOPwYALyvofgq1Ws+kg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.6.3",
|
||||
"@redux-saga/deferred": "^1.1.2",
|
||||
"@redux-saga/delay-p": "^1.1.2",
|
||||
"@redux-saga/is": "^1.1.2",
|
||||
"@redux-saga/symbols": "^1.1.2",
|
||||
"@redux-saga/types": "^1.1.0",
|
||||
"redux": "^4.0.4",
|
||||
"typescript-tuple": "^2.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@redux-saga/deferred": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/@redux-saga%2fdeferred/-/deferred-1.1.2.tgz",
|
||||
"integrity": "sha512-908rDLHFN2UUzt2jb4uOzj6afpjgJe3MjICaUNO3bvkV/kN/cNeI9PMr8BsFXB/MR8WTAZQq/PlTq8Kww3TBSQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@redux-saga/delay-p": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/@redux-saga%2fdelay-p/-/delay-p-1.1.2.tgz",
|
||||
"integrity": "sha512-ojc+1IoC6OP65Ts5+ZHbEYdrohmIw1j9P7HS9MOJezqMYtCDgpkoqB5enAAZrNtnbSL6gVCWPHaoaTY5KeO0/g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@redux-saga/symbols": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@redux-saga/is": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/@redux-saga%2fis/-/is-1.1.2.tgz",
|
||||
"integrity": "sha512-OLbunKVsCVNTKEf2cH4TYyNbbPgvmZ52iaxBD4I1fTif4+MTXMa4/Z07L83zW/hTCXwpSZvXogqMqLfex2Tg6w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@redux-saga/symbols": "^1.1.2",
|
||||
"@redux-saga/types": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@redux-saga/symbols": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/@redux-saga%2fsymbols/-/symbols-1.1.2.tgz",
|
||||
"integrity": "sha512-EfdGnF423glv3uMwLsGAtE6bg+R9MdqlHEzExnfagXPrIiuxwr3bdiAwz3gi+PsrQ3yBlaBpfGLtDG8rf3LgQQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@redux-saga/types": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/@redux-saga%2ftypes/-/types-1.1.0.tgz",
|
||||
"integrity": "sha512-afmTuJrylUU/0OtqzaRkbyYFFNgCF73Bvel/sw90pvGrWIZ+vyoIJqA6eMSoA6+nb443kTmulmBtC9NerXboNg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/immutable": {
|
||||
"version": "4.0.0-rc.12",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/immutable/-/immutable-4.0.0-rc.12.tgz",
|
||||
"integrity": "sha512-0M2XxkZLx/mi3t8NVwIm1g8nHoEmM9p9UBl/G9k4+hm0kBgOVdMV/B3CY5dQ8qG8qc80NN4gDV4HQv6FTJ5q7A==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"loose-envify": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/normalizr": {
|
||||
"version": "3.6.1",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/normalizr/-/normalizr-3.6.1.tgz",
|
||||
"integrity": "sha512-8iEmqXmPtll8PwbEFrbPoDxVw7MKnNvt3PZzR2Xvq9nggEEOgBlNICPXYzyZ4w4AkHUzCU998mdatER3n2VaMA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/redux": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/redux/-/redux-4.0.5.tgz",
|
||||
"integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"symbol-observable": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/redux-saga": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/redux-saga/-/redux-saga-1.1.3.tgz",
|
||||
"integrity": "sha512-RkSn/z0mwaSa5/xH/hQLo8gNf4tlvT18qXDNvedihLcfzh+jMchDgaariQoehCpgRltEm4zHKJyINEz6aqswTw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@redux-saga/core": "^1.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/redux-ts-simple": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/redux-ts-simple/-/redux-ts-simple-3.2.0.tgz",
|
||||
"integrity": "sha512-cZGmkNlD+14tNKomgaLWv6giQmgI/c05g09UxbA04lr2TbqHH8/bUQLvJgTzPuGwsZCWQHizkQZt9EI0HLD+pg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/regenerator-runtime": {
|
||||
"version": "0.13.7",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
|
||||
"integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/reselect": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/reselect/-/reselect-4.0.0.tgz",
|
||||
"integrity": "sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/symbol-observable": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/symbol-observable/-/symbol-observable-1.2.0.tgz",
|
||||
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "3.9.7",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/typescript/-/typescript-3.9.7.tgz",
|
||||
"integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-compare": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/typescript-compare/-/typescript-compare-0.0.2.tgz",
|
||||
"integrity": "sha512-8ja4j7pMHkfLJQO2/8tut7ub+J3Lw2S3061eJLFQcvs3tsmJKp8KG5NtpLn7KcY2w08edF74BSVN7qJS0U6oHA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"typescript-logic": "^0.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-logic": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/typescript-logic/-/typescript-logic-0.0.0.tgz",
|
||||
"integrity": "sha512-zXFars5LUkI3zP492ls0VskH3TtdeHCqu0i7/duGt60i5IGPIpAHE/DWo5FqJ6EjQ15YKXrt+AETjv60Dat34Q==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/typescript-tuple": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/typescript-tuple/-/typescript-tuple-2.2.1.tgz",
|
||||
"integrity": "sha512-Zcr0lbt8z5ZdEzERHAMAniTiIKerFCMgd7yjq1fPnDJ43et/k9twIFQMUYff9k5oXcsQ0WpvFcgzK2ZKASoW6Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"typescript-compare": "^0.0.2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": {
|
||||
"version": "7.12.5",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/@babel%2fruntime/-/runtime-7.12.5.tgz",
|
||||
"integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"regenerator-runtime": "^0.13.4"
|
||||
}
|
||||
},
|
||||
"@redux-saga/core": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/@redux-saga%2fcore/-/core-1.1.3.tgz",
|
||||
"integrity": "sha512-8tInBftak8TPzE6X13ABmEtRJGjtK17w7VUs7qV17S8hCO5S3+aUTWZ/DBsBJPdE8Z5jOPwYALyvofgq1Ws+kg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.6.3",
|
||||
"@redux-saga/deferred": "^1.1.2",
|
||||
"@redux-saga/delay-p": "^1.1.2",
|
||||
"@redux-saga/is": "^1.1.2",
|
||||
"@redux-saga/symbols": "^1.1.2",
|
||||
"@redux-saga/types": "^1.1.0",
|
||||
"redux": "^4.0.4",
|
||||
"typescript-tuple": "^2.2.1"
|
||||
}
|
||||
},
|
||||
"@redux-saga/deferred": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/@redux-saga%2fdeferred/-/deferred-1.1.2.tgz",
|
||||
"integrity": "sha512-908rDLHFN2UUzt2jb4uOzj6afpjgJe3MjICaUNO3bvkV/kN/cNeI9PMr8BsFXB/MR8WTAZQq/PlTq8Kww3TBSQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@redux-saga/delay-p": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/@redux-saga%2fdelay-p/-/delay-p-1.1.2.tgz",
|
||||
"integrity": "sha512-ojc+1IoC6OP65Ts5+ZHbEYdrohmIw1j9P7HS9MOJezqMYtCDgpkoqB5enAAZrNtnbSL6gVCWPHaoaTY5KeO0/g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@redux-saga/symbols": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"@redux-saga/is": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/@redux-saga%2fis/-/is-1.1.2.tgz",
|
||||
"integrity": "sha512-OLbunKVsCVNTKEf2cH4TYyNbbPgvmZ52iaxBD4I1fTif4+MTXMa4/Z07L83zW/hTCXwpSZvXogqMqLfex2Tg6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@redux-saga/symbols": "^1.1.2",
|
||||
"@redux-saga/types": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"@redux-saga/symbols": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/@redux-saga%2fsymbols/-/symbols-1.1.2.tgz",
|
||||
"integrity": "sha512-EfdGnF423glv3uMwLsGAtE6bg+R9MdqlHEzExnfagXPrIiuxwr3bdiAwz3gi+PsrQ3yBlaBpfGLtDG8rf3LgQQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@redux-saga/types": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/@redux-saga%2ftypes/-/types-1.1.0.tgz",
|
||||
"integrity": "sha512-afmTuJrylUU/0OtqzaRkbyYFFNgCF73Bvel/sw90pvGrWIZ+vyoIJqA6eMSoA6+nb443kTmulmBtC9NerXboNg==",
|
||||
"dev": true
|
||||
},
|
||||
"immutable": {
|
||||
"version": "4.0.0-rc.12",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/immutable/-/immutable-4.0.0-rc.12.tgz",
|
||||
"integrity": "sha512-0M2XxkZLx/mi3t8NVwIm1g8nHoEmM9p9UBl/G9k4+hm0kBgOVdMV/B3CY5dQ8qG8qc80NN4gDV4HQv6FTJ5q7A==",
|
||||
"dev": true
|
||||
},
|
||||
"js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||
"dev": true
|
||||
},
|
||||
"loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
}
|
||||
},
|
||||
"normalizr": {
|
||||
"version": "3.6.1",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/normalizr/-/normalizr-3.6.1.tgz",
|
||||
"integrity": "sha512-8iEmqXmPtll8PwbEFrbPoDxVw7MKnNvt3PZzR2Xvq9nggEEOgBlNICPXYzyZ4w4AkHUzCU998mdatER3n2VaMA==",
|
||||
"dev": true
|
||||
},
|
||||
"redux": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/redux/-/redux-4.0.5.tgz",
|
||||
"integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"symbol-observable": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"redux-saga": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/redux-saga/-/redux-saga-1.1.3.tgz",
|
||||
"integrity": "sha512-RkSn/z0mwaSa5/xH/hQLo8gNf4tlvT18qXDNvedihLcfzh+jMchDgaariQoehCpgRltEm4zHKJyINEz6aqswTw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@redux-saga/core": "^1.1.3"
|
||||
}
|
||||
},
|
||||
"redux-ts-simple": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/redux-ts-simple/-/redux-ts-simple-3.2.0.tgz",
|
||||
"integrity": "sha512-cZGmkNlD+14tNKomgaLWv6giQmgI/c05g09UxbA04lr2TbqHH8/bUQLvJgTzPuGwsZCWQHizkQZt9EI0HLD+pg==",
|
||||
"dev": true
|
||||
},
|
||||
"regenerator-runtime": {
|
||||
"version": "0.13.7",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
|
||||
"integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==",
|
||||
"dev": true
|
||||
},
|
||||
"reselect": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/reselect/-/reselect-4.0.0.tgz",
|
||||
"integrity": "sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==",
|
||||
"dev": true
|
||||
},
|
||||
"symbol-observable": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/symbol-observable/-/symbol-observable-1.2.0.tgz",
|
||||
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==",
|
||||
"dev": true
|
||||
},
|
||||
"typescript": {
|
||||
"version": "3.9.7",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/typescript/-/typescript-3.9.7.tgz",
|
||||
"integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==",
|
||||
"dev": true
|
||||
},
|
||||
"typescript-compare": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/typescript-compare/-/typescript-compare-0.0.2.tgz",
|
||||
"integrity": "sha512-8ja4j7pMHkfLJQO2/8tut7ub+J3Lw2S3061eJLFQcvs3tsmJKp8KG5NtpLn7KcY2w08edF74BSVN7qJS0U6oHA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"typescript-logic": "^0.0.0"
|
||||
}
|
||||
},
|
||||
"typescript-logic": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/typescript-logic/-/typescript-logic-0.0.0.tgz",
|
||||
"integrity": "sha512-zXFars5LUkI3zP492ls0VskH3TtdeHCqu0i7/duGt60i5IGPIpAHE/DWo5FqJ6EjQ15YKXrt+AETjv60Dat34Q==",
|
||||
"dev": true
|
||||
},
|
||||
"typescript-tuple": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "http://verdaccio.corp.stingraydigital.com:4873/typescript-tuple/-/typescript-tuple-2.2.1.tgz",
|
||||
"integrity": "sha512-Zcr0lbt8z5ZdEzERHAMAniTiIKerFCMgd7yjq1fPnDJ43et/k9twIFQMUYff9k5oXcsQ0WpvFcgzK2ZKASoW6Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"typescript-compare": "^0.0.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -20,6 +20,7 @@ app/com/puppies/store/apis/UserApiControllerImpInterface.java
|
||||
app/openapitools/ApiCall.java
|
||||
app/openapitools/ErrorHandler.java
|
||||
app/openapitools/OpenAPIUtils.java
|
||||
app/openapitools/SecurityAPIUtils.java
|
||||
build.sbt
|
||||
conf/application.conf
|
||||
conf/logback.xml
|
||||
|
@ -1,6 +1,7 @@
|
||||
import com.google.inject.AbstractModule;
|
||||
|
||||
import com.puppies.store.apis.*;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
|
||||
public class Module extends AbstractModule {
|
||||
|
||||
@ -9,5 +10,6 @@ public class Module extends AbstractModule {
|
||||
bind(PetApiControllerImpInterface.class).to(PetApiControllerImp.class);
|
||||
bind(StoreApiControllerImpInterface.class).to(StoreApiControllerImp.class);
|
||||
bind(UserApiControllerImpInterface.class).to(UserApiControllerImp.class);
|
||||
bind(SecurityAPIUtils.class);
|
||||
}
|
||||
}
|
@ -15,7 +15,9 @@ import play.mvc.Result;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import static play.mvc.Results.ok;
|
||||
import static play.mvc.Results.unauthorized;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
@ -23,47 +25,70 @@ import javax.validation.constraints.*;
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public abstract class PetApiControllerImpInterface {
|
||||
@Inject private Config configuration;
|
||||
@Inject private SecurityAPIUtils securityAPIUtils;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public Result addPetHttp(Http.Request request, Pet body) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
addPet(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
public abstract void addPet(Http.Request request, Pet body) throws Exception;
|
||||
|
||||
public Result deletePetHttp(Http.Request request, Long petId, String apiKey) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
deletePet(request, petId, apiKey);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
public abstract void deletePet(Http.Request request, Long petId, String apiKey) throws Exception;
|
||||
|
||||
public Result findPetsByStatusHttp(Http.Request request, @NotNull List<String> status) throws Exception {
|
||||
List<Pet> obj = findPetsByStatus(request, status);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
|
||||
List<Pet> obj = findPetsByStatus(request, status);
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
}
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
public abstract List<Pet> findPetsByStatus(Http.Request request, @NotNull List<String> status) throws Exception;
|
||||
|
||||
public Result findPetsByTagsHttp(Http.Request request, @NotNull List<String> tags) throws Exception {
|
||||
List<Pet> obj = findPetsByTags(request, tags);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
|
||||
List<Pet> obj = findPetsByTags(request, tags);
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
}
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -71,39 +96,57 @@ return ok(result);
|
||||
|
||||
public Result getPetByIdHttp(Http.Request request, Long petId) throws Exception {
|
||||
Pet obj = getPetById(request, petId);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
public abstract Pet getPetById(Http.Request request, Long petId) throws Exception;
|
||||
|
||||
public Result updatePetHttp(Http.Request request, Pet body) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
updatePet(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
public abstract void updatePet(Http.Request request, Pet body) throws Exception;
|
||||
|
||||
public Result updatePetWithFormHttp(Http.Request request, Long petId, String name, String status) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
updatePetWithForm(request, petId, name, status);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
public abstract void updatePetWithForm(Http.Request request, Long petId, String name, String status) throws Exception;
|
||||
|
||||
public Result uploadFileHttp(Http.Request request, Long petId, String additionalMetadata, Http.MultipartFormData.FilePart<TemporaryFile> file) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
ModelApiResponse obj = uploadFile(request, petId, additionalMetadata, file);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,9 @@ import play.mvc.Result;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import static play.mvc.Results.ok;
|
||||
import static play.mvc.Results.unauthorized;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
@ -22,11 +24,12 @@ import javax.validation.constraints.*;
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public abstract class StoreApiControllerImpInterface {
|
||||
@Inject private Config configuration;
|
||||
@Inject private SecurityAPIUtils securityAPIUtils;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public Result deleteOrderHttp(Http.Request request, String orderId) throws Exception {
|
||||
deleteOrder(request, orderId);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -34,8 +37,9 @@ return ok();
|
||||
|
||||
public Result getInventoryHttp(Http.Request request) throws Exception {
|
||||
Map<String, Integer> obj = getInventory(request);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -43,11 +47,14 @@ return ok(result);
|
||||
|
||||
public Result getOrderByIdHttp(Http.Request request, @Min(1) @Max(5)Long orderId) throws Exception {
|
||||
Order obj = getOrderById(request, orderId);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -55,11 +62,14 @@ return ok(result);
|
||||
|
||||
public Result placeOrderHttp(Http.Request request, Order body) throws Exception {
|
||||
Order obj = placeOrder(request, body);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,9 @@ import play.mvc.Result;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import static play.mvc.Results.ok;
|
||||
import static play.mvc.Results.unauthorized;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
@ -23,11 +25,12 @@ import javax.validation.constraints.*;
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public abstract class UserApiControllerImpInterface {
|
||||
@Inject private Config configuration;
|
||||
@Inject private SecurityAPIUtils securityAPIUtils;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public Result createUserHttp(Http.Request request, User body) throws Exception {
|
||||
createUser(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -35,7 +38,7 @@ return ok();
|
||||
|
||||
public Result createUsersWithArrayInputHttp(Http.Request request, List<User> body) throws Exception {
|
||||
createUsersWithArrayInput(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -43,7 +46,7 @@ return ok();
|
||||
|
||||
public Result createUsersWithListInputHttp(Http.Request request, List<User> body) throws Exception {
|
||||
createUsersWithListInput(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -51,7 +54,7 @@ return ok();
|
||||
|
||||
public Result deleteUserHttp(Http.Request request, String username) throws Exception {
|
||||
deleteUser(request, username);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -59,11 +62,14 @@ return ok();
|
||||
|
||||
public Result getUserByNameHttp(Http.Request request, String username) throws Exception {
|
||||
User obj = getUserByName(request, username);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -71,8 +77,9 @@ return ok(result);
|
||||
|
||||
public Result loginUserHttp(Http.Request request, @NotNull String username, @NotNull String password) throws Exception {
|
||||
String obj = loginUser(request, username, password);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -80,7 +87,7 @@ return ok(result);
|
||||
|
||||
public Result logoutUserHttp(Http.Request request) throws Exception {
|
||||
logoutUser(request);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -88,7 +95,7 @@ return ok();
|
||||
|
||||
public Result updateUserHttp(Http.Request request, String username, User body) throws Exception {
|
||||
updateUser(request, username, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,165 @@
|
||||
package openapitools;
|
||||
|
||||
import com.auth0.jwk.Jwk;
|
||||
import com.auth0.jwk.UrlJwkProvider;
|
||||
import com.auth0.jwt.JWT;
|
||||
import com.auth0.jwt.JWTVerifier;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import com.typesafe.config.Config;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import play.mvc.Http;
|
||||
|
||||
import java.net.URL;
|
||||
import java.security.PublicKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Singleton
|
||||
public class SecurityAPIUtils {
|
||||
private final String bearerPrefix = "Bearer ";
|
||||
private final ObjectMapper mapper;
|
||||
|
||||
private boolean useOnlineValidation = false;
|
||||
|
||||
// Online validation
|
||||
private HashMap<String, String> tokenIntrospectEndpoints = new HashMap<>();
|
||||
private final String clientId;
|
||||
private final String clientSecret;
|
||||
|
||||
// Offline validation
|
||||
private HashMap<String, String> jwksEndpoints = new HashMap<>();
|
||||
private String tokenKeyId = "";
|
||||
private JWTVerifier tokenVerifier; //Reusable verifier instance until tokenKeyId changes.
|
||||
|
||||
@Inject
|
||||
SecurityAPIUtils(Config configuration) {
|
||||
mapper = new ObjectMapper();
|
||||
|
||||
clientId = configuration.hasPath("oauth.clientId") ? configuration.getString("oauth.clientId") : "";
|
||||
clientSecret = configuration.hasPath("oauth.clientSecret") ? configuration.getString("oauth.clientSecret") : "";
|
||||
|
||||
tokenIntrospectEndpoints.put("petstore_auth", "");
|
||||
|
||||
jwksEndpoints.put("petstore_auth", "");
|
||||
}
|
||||
|
||||
private boolean isRequestTokenValidByOnlineCheck(Http.Request request, String securityMethodName) {
|
||||
try {
|
||||
Optional<String> authToken = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
|
||||
if (authToken.isPresent()) {
|
||||
String tokenWithoutBearerPrefix = authToken.get().substring(bearerPrefix.length());
|
||||
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
HttpClient httpClient = builder.build();
|
||||
HttpPost httppost = new HttpPost(this.tokenIntrospectEndpoints.get(securityMethodName));
|
||||
|
||||
List<NameValuePair> params = new ArrayList<>();
|
||||
params.add(new BasicNameValuePair("token", tokenWithoutBearerPrefix));
|
||||
params.add(new BasicNameValuePair("client_id", clientId));
|
||||
params.add(new BasicNameValuePair("client_secret", clientSecret));
|
||||
httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
|
||||
|
||||
HttpResponse response = httpClient.execute(httppost);
|
||||
String responseJsonString = EntityUtils.toString(response.getEntity());
|
||||
HashMap responseJsonObject = mapper.readValue(responseJsonString, HashMap.class);
|
||||
|
||||
return response.getStatusLine().getStatusCode() == HttpStatus.SC_OK && (boolean) responseJsonObject.get("active");
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isRequestTokenValidByOfflineCheck(Http.Request request, String securityMethodName) {
|
||||
try {
|
||||
Optional<String> authHeader = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
|
||||
if (authHeader.isPresent()) {
|
||||
String bearerToken = authHeader.get().substring(bearerPrefix.length());
|
||||
return isTokenValidByOfflineCheck(bearerToken, securityMethodName);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isTokenValidByOfflineCheck(String bearerToken, String securityMethodName) {
|
||||
try {
|
||||
DecodedJWT jwt = JWT.decode(bearerToken);
|
||||
String issuer = jwt.getIssuer();
|
||||
String keyId = jwt.getKeyId();
|
||||
if (!tokenKeyId.equals(keyId)) {
|
||||
if (securityMethodName == null) {
|
||||
securityMethodName = jwksEndpoints.keySet().stream().findFirst().get();
|
||||
}
|
||||
|
||||
Jwk jwk = new UrlJwkProvider(new URL(this.jwksEndpoints.get(securityMethodName))).get(keyId);
|
||||
final PublicKey publicKey = jwk.getPublicKey();
|
||||
|
||||
if (!(publicKey instanceof RSAPublicKey)) {
|
||||
throw new IllegalArgumentException(String.format("Key with ID %s was found in JWKS but is not a RSA-key.", keyId));
|
||||
}
|
||||
|
||||
Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) publicKey, null);
|
||||
tokenVerifier = JWT.require(algorithm)
|
||||
.withIssuer(issuer)
|
||||
.build();
|
||||
tokenKeyId = keyId;
|
||||
}
|
||||
|
||||
DecodedJWT verifiedJWT = tokenVerifier.verify(bearerToken);
|
||||
|
||||
return true;
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public String getOAuthUserIdFromRequestToken(Http.Request requestWithPreviouslyVerifiedToken) {
|
||||
try {
|
||||
Optional<String> authHeader = requestWithPreviouslyVerifiedToken.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
if (authHeader.isPresent()) {
|
||||
String bearerToken = authHeader.get().substring(bearerPrefix.length());
|
||||
return getOAuthUserIdFromToken(bearerToken);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getOAuthUserIdFromToken(String bearerToken) {
|
||||
try {
|
||||
DecodedJWT jwt = JWT.decode(bearerToken);
|
||||
return jwt.getSubject();
|
||||
} catch (Exception exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRequestTokenValid(Http.Request request, String securityMethodName) {
|
||||
return useOnlineValidation ? isRequestTokenValidByOnlineCheck(request, securityMethodName) : isRequestTokenValidByOfflineCheck(request, securityMethodName);
|
||||
}
|
||||
}
|
@ -9,3 +9,6 @@ scalaVersion := "2.12.6"
|
||||
libraryDependencies += "org.webjars" % "swagger-ui" % "3.32.5"
|
||||
libraryDependencies += "javax.validation" % "validation-api" % "2.0.1.Final"
|
||||
libraryDependencies += guice
|
||||
libraryDependencies += "com.auth0" % "java-jwt" % "3.18.1"
|
||||
libraryDependencies += "com.auth0" % "jwks-rsa" % "0.19.0"
|
||||
libraryDependencies += "org.apache.httpcomponents" % "httpclient" % "4.5.6"
|
||||
|
@ -20,6 +20,7 @@ app/controllers/UserApiControllerImpInterface.java
|
||||
app/openapitools/ApiCall.java
|
||||
app/openapitools/ErrorHandler.java
|
||||
app/openapitools/OpenAPIUtils.java
|
||||
app/openapitools/SecurityAPIUtils.java
|
||||
build.sbt
|
||||
conf/application.conf
|
||||
conf/logback.xml
|
||||
|
@ -1,6 +1,7 @@
|
||||
import com.google.inject.AbstractModule;
|
||||
|
||||
import controllers.*;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
|
||||
public class Module extends AbstractModule {
|
||||
|
||||
@ -9,5 +10,6 @@ public class Module extends AbstractModule {
|
||||
bind(PetApiControllerImpInterface.class).to(PetApiControllerImp.class);
|
||||
bind(StoreApiControllerImpInterface.class).to(StoreApiControllerImp.class);
|
||||
bind(UserApiControllerImpInterface.class).to(UserApiControllerImp.class);
|
||||
bind(SecurityAPIUtils.class);
|
||||
}
|
||||
}
|
@ -15,7 +15,9 @@ import play.mvc.Result;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import static play.mvc.Results.ok;
|
||||
import static play.mvc.Results.unauthorized;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
@ -26,12 +28,17 @@ import javax.validation.constraints.*;
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public abstract class PetApiControllerImpInterface {
|
||||
@Inject private Config configuration;
|
||||
@Inject private SecurityAPIUtils securityAPIUtils;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public CompletionStage<Result> addPetHttp(Http.Request request, Pet body) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return CompletableFuture.supplyAsync(play.mvc.Results::unauthorized);
|
||||
}
|
||||
|
||||
CompletableFuture<Result> result = CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
addPet(request, body);
|
||||
addPet(request, body);
|
||||
} catch (Exception e) {
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
@ -44,9 +51,13 @@ public abstract class PetApiControllerImpInterface {
|
||||
public abstract void addPet(Http.Request request, Pet body) throws Exception;
|
||||
|
||||
public CompletionStage<Result> deletePetHttp(Http.Request request, Long petId, String apiKey) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return CompletableFuture.supplyAsync(play.mvc.Results::unauthorized);
|
||||
}
|
||||
|
||||
CompletableFuture<Result> result = CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
deletePet(request, petId, apiKey);
|
||||
deletePet(request, petId, apiKey);
|
||||
} catch (Exception e) {
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
@ -59,36 +70,50 @@ public abstract class PetApiControllerImpInterface {
|
||||
public abstract void deletePet(Http.Request request, Long petId, String apiKey) throws Exception;
|
||||
|
||||
public CompletionStage<Result> findPetsByStatusHttp(Http.Request request, @NotNull List<String> status) throws Exception {
|
||||
CompletionStage<List<Pet>> stage = findPetsByStatus(request, status).thenApply(obj -> {
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return CompletableFuture.supplyAsync(play.mvc.Results::unauthorized);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
|
||||
CompletionStage<List<Pet>> stage = findPetsByStatus(request, status).thenApply(obj -> {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
});
|
||||
return stage.thenApply(obj -> {
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
});
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public abstract CompletionStage<List<Pet>> findPetsByStatus(Http.Request request, @NotNull List<String> status) throws Exception;
|
||||
|
||||
public CompletionStage<Result> findPetsByTagsHttp(Http.Request request, @NotNull List<String> tags) throws Exception {
|
||||
CompletionStage<List<Pet>> stage = findPetsByTags(request, tags).thenApply(obj -> {
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return CompletableFuture.supplyAsync(play.mvc.Results::unauthorized);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
|
||||
CompletionStage<List<Pet>> stage = findPetsByTags(request, tags).thenApply(obj -> {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
});
|
||||
return stage.thenApply(obj -> {
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
});
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@ -96,24 +121,31 @@ return stage.thenApply(obj -> {
|
||||
|
||||
public CompletionStage<Result> getPetByIdHttp(Http.Request request, Long petId) throws Exception {
|
||||
CompletionStage<Pet> stage = getPetById(request, petId).thenApply(obj -> {
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
|
||||
return obj;
|
||||
});
|
||||
return stage.thenApply(obj -> {
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
});
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public abstract CompletionStage<Pet> getPetById(Http.Request request, Long petId) throws Exception;
|
||||
|
||||
public CompletionStage<Result> updatePetHttp(Http.Request request, Pet body) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return CompletableFuture.supplyAsync(play.mvc.Results::unauthorized);
|
||||
}
|
||||
|
||||
CompletableFuture<Result> result = CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
updatePet(request, body);
|
||||
updatePet(request, body);
|
||||
} catch (Exception e) {
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
@ -126,9 +158,13 @@ return stage.thenApply(obj -> {
|
||||
public abstract void updatePet(Http.Request request, Pet body) throws Exception;
|
||||
|
||||
public CompletionStage<Result> updatePetWithFormHttp(Http.Request request, Long petId, String name, String status) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return CompletableFuture.supplyAsync(play.mvc.Results::unauthorized);
|
||||
}
|
||||
|
||||
CompletableFuture<Result> result = CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
updatePetWithForm(request, petId, name, status);
|
||||
updatePetWithForm(request, petId, name, status);
|
||||
} catch (Exception e) {
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
@ -141,16 +177,23 @@ return stage.thenApply(obj -> {
|
||||
public abstract void updatePetWithForm(Http.Request request, Long petId, String name, String status) throws Exception;
|
||||
|
||||
public CompletionStage<Result> uploadFileHttp(Http.Request request, Long petId, String additionalMetadata, Http.MultipartFormData.FilePart<TemporaryFile> file) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return CompletableFuture.supplyAsync(play.mvc.Results::unauthorized);
|
||||
}
|
||||
|
||||
CompletionStage<ModelApiResponse> stage = uploadFile(request, petId, additionalMetadata, file).thenApply(obj -> {
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
|
||||
return obj;
|
||||
});
|
||||
return stage.thenApply(obj -> {
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
});
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,9 @@ import play.mvc.Result;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import static play.mvc.Results.ok;
|
||||
import static play.mvc.Results.unauthorized;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
@ -25,12 +27,13 @@ import javax.validation.constraints.*;
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public abstract class StoreApiControllerImpInterface {
|
||||
@Inject private Config configuration;
|
||||
@Inject private SecurityAPIUtils securityAPIUtils;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public CompletionStage<Result> deleteOrderHttp(Http.Request request, String orderId) throws Exception {
|
||||
CompletableFuture<Result> result = CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
deleteOrder(request, orderId);
|
||||
deleteOrder(request, orderId);
|
||||
} catch (Exception e) {
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
@ -44,12 +47,13 @@ public abstract class StoreApiControllerImpInterface {
|
||||
|
||||
public CompletionStage<Result> getInventoryHttp(Http.Request request) throws Exception {
|
||||
CompletionStage<Map<String, Integer>> stage = getInventory(request).thenApply(obj -> {
|
||||
return obj;
|
||||
});
|
||||
return obj;
|
||||
});
|
||||
return stage.thenApply(obj -> {
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
});
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@ -57,15 +61,18 @@ return stage.thenApply(obj -> {
|
||||
|
||||
public CompletionStage<Result> getOrderByIdHttp(Http.Request request, @Min(1) @Max(5)Long orderId) throws Exception {
|
||||
CompletionStage<Order> stage = getOrderById(request, orderId).thenApply(obj -> {
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
|
||||
return obj;
|
||||
});
|
||||
return stage.thenApply(obj -> {
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
});
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@ -73,15 +80,18 @@ return stage.thenApply(obj -> {
|
||||
|
||||
public CompletionStage<Result> placeOrderHttp(Http.Request request, Order body) throws Exception {
|
||||
CompletionStage<Order> stage = placeOrder(request, body).thenApply(obj -> {
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
|
||||
return obj;
|
||||
});
|
||||
return stage.thenApply(obj -> {
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
});
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,9 @@ import play.mvc.Result;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import static play.mvc.Results.ok;
|
||||
import static play.mvc.Results.unauthorized;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
@ -26,12 +28,13 @@ import javax.validation.constraints.*;
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public abstract class UserApiControllerImpInterface {
|
||||
@Inject private Config configuration;
|
||||
@Inject private SecurityAPIUtils securityAPIUtils;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public CompletionStage<Result> createUserHttp(Http.Request request, User body) throws Exception {
|
||||
CompletableFuture<Result> result = CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
createUser(request, body);
|
||||
createUser(request, body);
|
||||
} catch (Exception e) {
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
@ -46,7 +49,7 @@ public abstract class UserApiControllerImpInterface {
|
||||
public CompletionStage<Result> createUsersWithArrayInputHttp(Http.Request request, List<User> body) throws Exception {
|
||||
CompletableFuture<Result> result = CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
createUsersWithArrayInput(request, body);
|
||||
createUsersWithArrayInput(request, body);
|
||||
} catch (Exception e) {
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
@ -61,7 +64,7 @@ public abstract class UserApiControllerImpInterface {
|
||||
public CompletionStage<Result> createUsersWithListInputHttp(Http.Request request, List<User> body) throws Exception {
|
||||
CompletableFuture<Result> result = CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
createUsersWithListInput(request, body);
|
||||
createUsersWithListInput(request, body);
|
||||
} catch (Exception e) {
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
@ -76,7 +79,7 @@ public abstract class UserApiControllerImpInterface {
|
||||
public CompletionStage<Result> deleteUserHttp(Http.Request request, String username) throws Exception {
|
||||
CompletableFuture<Result> result = CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
deleteUser(request, username);
|
||||
deleteUser(request, username);
|
||||
} catch (Exception e) {
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
@ -90,15 +93,18 @@ public abstract class UserApiControllerImpInterface {
|
||||
|
||||
public CompletionStage<Result> getUserByNameHttp(Http.Request request, String username) throws Exception {
|
||||
CompletionStage<User> stage = getUserByName(request, username).thenApply(obj -> {
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
|
||||
return obj;
|
||||
});
|
||||
return stage.thenApply(obj -> {
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
});
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@ -106,12 +112,13 @@ return stage.thenApply(obj -> {
|
||||
|
||||
public CompletionStage<Result> loginUserHttp(Http.Request request, @NotNull String username, @NotNull String password) throws Exception {
|
||||
CompletionStage<String> stage = loginUser(request, username, password).thenApply(obj -> {
|
||||
return obj;
|
||||
});
|
||||
return obj;
|
||||
});
|
||||
return stage.thenApply(obj -> {
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
});
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@ -120,7 +127,7 @@ return stage.thenApply(obj -> {
|
||||
public CompletionStage<Result> logoutUserHttp(Http.Request request) throws Exception {
|
||||
CompletableFuture<Result> result = CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
logoutUser(request);
|
||||
logoutUser(request);
|
||||
} catch (Exception e) {
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
@ -135,7 +142,7 @@ return stage.thenApply(obj -> {
|
||||
public CompletionStage<Result> updateUserHttp(Http.Request request, String username, User body) throws Exception {
|
||||
CompletableFuture<Result> result = CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
updateUser(request, username, body);
|
||||
updateUser(request, username, body);
|
||||
} catch (Exception e) {
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
|
@ -0,0 +1,165 @@
|
||||
package openapitools;
|
||||
|
||||
import com.auth0.jwk.Jwk;
|
||||
import com.auth0.jwk.UrlJwkProvider;
|
||||
import com.auth0.jwt.JWT;
|
||||
import com.auth0.jwt.JWTVerifier;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import com.typesafe.config.Config;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import play.mvc.Http;
|
||||
|
||||
import java.net.URL;
|
||||
import java.security.PublicKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Singleton
|
||||
public class SecurityAPIUtils {
|
||||
private final String bearerPrefix = "Bearer ";
|
||||
private final ObjectMapper mapper;
|
||||
|
||||
private boolean useOnlineValidation = false;
|
||||
|
||||
// Online validation
|
||||
private HashMap<String, String> tokenIntrospectEndpoints = new HashMap<>();
|
||||
private final String clientId;
|
||||
private final String clientSecret;
|
||||
|
||||
// Offline validation
|
||||
private HashMap<String, String> jwksEndpoints = new HashMap<>();
|
||||
private String tokenKeyId = "";
|
||||
private JWTVerifier tokenVerifier; //Reusable verifier instance until tokenKeyId changes.
|
||||
|
||||
@Inject
|
||||
SecurityAPIUtils(Config configuration) {
|
||||
mapper = new ObjectMapper();
|
||||
|
||||
clientId = configuration.hasPath("oauth.clientId") ? configuration.getString("oauth.clientId") : "";
|
||||
clientSecret = configuration.hasPath("oauth.clientSecret") ? configuration.getString("oauth.clientSecret") : "";
|
||||
|
||||
tokenIntrospectEndpoints.put("petstore_auth", "");
|
||||
|
||||
jwksEndpoints.put("petstore_auth", "");
|
||||
}
|
||||
|
||||
private boolean isRequestTokenValidByOnlineCheck(Http.Request request, String securityMethodName) {
|
||||
try {
|
||||
Optional<String> authToken = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
|
||||
if (authToken.isPresent()) {
|
||||
String tokenWithoutBearerPrefix = authToken.get().substring(bearerPrefix.length());
|
||||
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
HttpClient httpClient = builder.build();
|
||||
HttpPost httppost = new HttpPost(this.tokenIntrospectEndpoints.get(securityMethodName));
|
||||
|
||||
List<NameValuePair> params = new ArrayList<>();
|
||||
params.add(new BasicNameValuePair("token", tokenWithoutBearerPrefix));
|
||||
params.add(new BasicNameValuePair("client_id", clientId));
|
||||
params.add(new BasicNameValuePair("client_secret", clientSecret));
|
||||
httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
|
||||
|
||||
HttpResponse response = httpClient.execute(httppost);
|
||||
String responseJsonString = EntityUtils.toString(response.getEntity());
|
||||
HashMap responseJsonObject = mapper.readValue(responseJsonString, HashMap.class);
|
||||
|
||||
return response.getStatusLine().getStatusCode() == HttpStatus.SC_OK && (boolean) responseJsonObject.get("active");
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isRequestTokenValidByOfflineCheck(Http.Request request, String securityMethodName) {
|
||||
try {
|
||||
Optional<String> authHeader = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
|
||||
if (authHeader.isPresent()) {
|
||||
String bearerToken = authHeader.get().substring(bearerPrefix.length());
|
||||
return isTokenValidByOfflineCheck(bearerToken, securityMethodName);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isTokenValidByOfflineCheck(String bearerToken, String securityMethodName) {
|
||||
try {
|
||||
DecodedJWT jwt = JWT.decode(bearerToken);
|
||||
String issuer = jwt.getIssuer();
|
||||
String keyId = jwt.getKeyId();
|
||||
if (!tokenKeyId.equals(keyId)) {
|
||||
if (securityMethodName == null) {
|
||||
securityMethodName = jwksEndpoints.keySet().stream().findFirst().get();
|
||||
}
|
||||
|
||||
Jwk jwk = new UrlJwkProvider(new URL(this.jwksEndpoints.get(securityMethodName))).get(keyId);
|
||||
final PublicKey publicKey = jwk.getPublicKey();
|
||||
|
||||
if (!(publicKey instanceof RSAPublicKey)) {
|
||||
throw new IllegalArgumentException(String.format("Key with ID %s was found in JWKS but is not a RSA-key.", keyId));
|
||||
}
|
||||
|
||||
Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) publicKey, null);
|
||||
tokenVerifier = JWT.require(algorithm)
|
||||
.withIssuer(issuer)
|
||||
.build();
|
||||
tokenKeyId = keyId;
|
||||
}
|
||||
|
||||
DecodedJWT verifiedJWT = tokenVerifier.verify(bearerToken);
|
||||
|
||||
return true;
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public String getOAuthUserIdFromRequestToken(Http.Request requestWithPreviouslyVerifiedToken) {
|
||||
try {
|
||||
Optional<String> authHeader = requestWithPreviouslyVerifiedToken.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
if (authHeader.isPresent()) {
|
||||
String bearerToken = authHeader.get().substring(bearerPrefix.length());
|
||||
return getOAuthUserIdFromToken(bearerToken);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getOAuthUserIdFromToken(String bearerToken) {
|
||||
try {
|
||||
DecodedJWT jwt = JWT.decode(bearerToken);
|
||||
return jwt.getSubject();
|
||||
} catch (Exception exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRequestTokenValid(Http.Request request, String securityMethodName) {
|
||||
return useOnlineValidation ? isRequestTokenValidByOnlineCheck(request, securityMethodName) : isRequestTokenValidByOfflineCheck(request, securityMethodName);
|
||||
}
|
||||
}
|
@ -9,3 +9,6 @@ scalaVersion := "2.12.6"
|
||||
libraryDependencies += "org.webjars" % "swagger-ui" % "3.32.5"
|
||||
libraryDependencies += "javax.validation" % "validation-api" % "2.0.1.Final"
|
||||
libraryDependencies += guice
|
||||
libraryDependencies += "com.auth0" % "java-jwt" % "3.18.1"
|
||||
libraryDependencies += "com.auth0" % "jwks-rsa" % "0.19.0"
|
||||
libraryDependencies += "org.apache.httpcomponents" % "httpclient" % "4.5.6"
|
||||
|
@ -13,6 +13,7 @@ app/controllers/UserApiController.java
|
||||
app/openapitools/ApiCall.java
|
||||
app/openapitools/ErrorHandler.java
|
||||
app/openapitools/OpenAPIUtils.java
|
||||
app/openapitools/SecurityAPIUtils.java
|
||||
build.sbt
|
||||
conf/application.conf
|
||||
conf/logback.xml
|
||||
|
@ -0,0 +1,165 @@
|
||||
package openapitools;
|
||||
|
||||
import com.auth0.jwk.Jwk;
|
||||
import com.auth0.jwk.UrlJwkProvider;
|
||||
import com.auth0.jwt.JWT;
|
||||
import com.auth0.jwt.JWTVerifier;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import com.typesafe.config.Config;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import play.mvc.Http;
|
||||
|
||||
import java.net.URL;
|
||||
import java.security.PublicKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Singleton
|
||||
public class SecurityAPIUtils {
|
||||
private final String bearerPrefix = "Bearer ";
|
||||
private final ObjectMapper mapper;
|
||||
|
||||
private boolean useOnlineValidation = false;
|
||||
|
||||
// Online validation
|
||||
private HashMap<String, String> tokenIntrospectEndpoints = new HashMap<>();
|
||||
private final String clientId;
|
||||
private final String clientSecret;
|
||||
|
||||
// Offline validation
|
||||
private HashMap<String, String> jwksEndpoints = new HashMap<>();
|
||||
private String tokenKeyId = "";
|
||||
private JWTVerifier tokenVerifier; //Reusable verifier instance until tokenKeyId changes.
|
||||
|
||||
@Inject
|
||||
SecurityAPIUtils(Config configuration) {
|
||||
mapper = new ObjectMapper();
|
||||
|
||||
clientId = configuration.hasPath("oauth.clientId") ? configuration.getString("oauth.clientId") : "";
|
||||
clientSecret = configuration.hasPath("oauth.clientSecret") ? configuration.getString("oauth.clientSecret") : "";
|
||||
|
||||
tokenIntrospectEndpoints.put("petstore_auth", "");
|
||||
|
||||
jwksEndpoints.put("petstore_auth", "");
|
||||
}
|
||||
|
||||
private boolean isRequestTokenValidByOnlineCheck(Http.Request request, String securityMethodName) {
|
||||
try {
|
||||
Optional<String> authToken = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
|
||||
if (authToken.isPresent()) {
|
||||
String tokenWithoutBearerPrefix = authToken.get().substring(bearerPrefix.length());
|
||||
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
HttpClient httpClient = builder.build();
|
||||
HttpPost httppost = new HttpPost(this.tokenIntrospectEndpoints.get(securityMethodName));
|
||||
|
||||
List<NameValuePair> params = new ArrayList<>();
|
||||
params.add(new BasicNameValuePair("token", tokenWithoutBearerPrefix));
|
||||
params.add(new BasicNameValuePair("client_id", clientId));
|
||||
params.add(new BasicNameValuePair("client_secret", clientSecret));
|
||||
httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
|
||||
|
||||
HttpResponse response = httpClient.execute(httppost);
|
||||
String responseJsonString = EntityUtils.toString(response.getEntity());
|
||||
HashMap responseJsonObject = mapper.readValue(responseJsonString, HashMap.class);
|
||||
|
||||
return response.getStatusLine().getStatusCode() == HttpStatus.SC_OK && (boolean) responseJsonObject.get("active");
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isRequestTokenValidByOfflineCheck(Http.Request request, String securityMethodName) {
|
||||
try {
|
||||
Optional<String> authHeader = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
|
||||
if (authHeader.isPresent()) {
|
||||
String bearerToken = authHeader.get().substring(bearerPrefix.length());
|
||||
return isTokenValidByOfflineCheck(bearerToken, securityMethodName);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isTokenValidByOfflineCheck(String bearerToken, String securityMethodName) {
|
||||
try {
|
||||
DecodedJWT jwt = JWT.decode(bearerToken);
|
||||
String issuer = jwt.getIssuer();
|
||||
String keyId = jwt.getKeyId();
|
||||
if (!tokenKeyId.equals(keyId)) {
|
||||
if (securityMethodName == null) {
|
||||
securityMethodName = jwksEndpoints.keySet().stream().findFirst().get();
|
||||
}
|
||||
|
||||
Jwk jwk = new UrlJwkProvider(new URL(this.jwksEndpoints.get(securityMethodName))).get(keyId);
|
||||
final PublicKey publicKey = jwk.getPublicKey();
|
||||
|
||||
if (!(publicKey instanceof RSAPublicKey)) {
|
||||
throw new IllegalArgumentException(String.format("Key with ID %s was found in JWKS but is not a RSA-key.", keyId));
|
||||
}
|
||||
|
||||
Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) publicKey, null);
|
||||
tokenVerifier = JWT.require(algorithm)
|
||||
.withIssuer(issuer)
|
||||
.build();
|
||||
tokenKeyId = keyId;
|
||||
}
|
||||
|
||||
DecodedJWT verifiedJWT = tokenVerifier.verify(bearerToken);
|
||||
|
||||
return true;
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public String getOAuthUserIdFromRequestToken(Http.Request requestWithPreviouslyVerifiedToken) {
|
||||
try {
|
||||
Optional<String> authHeader = requestWithPreviouslyVerifiedToken.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
if (authHeader.isPresent()) {
|
||||
String bearerToken = authHeader.get().substring(bearerPrefix.length());
|
||||
return getOAuthUserIdFromToken(bearerToken);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getOAuthUserIdFromToken(String bearerToken) {
|
||||
try {
|
||||
DecodedJWT jwt = JWT.decode(bearerToken);
|
||||
return jwt.getSubject();
|
||||
} catch (Exception exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRequestTokenValid(Http.Request request, String securityMethodName) {
|
||||
return useOnlineValidation ? isRequestTokenValidByOnlineCheck(request, securityMethodName) : isRequestTokenValidByOfflineCheck(request, securityMethodName);
|
||||
}
|
||||
}
|
@ -9,3 +9,6 @@ scalaVersion := "2.12.6"
|
||||
libraryDependencies += "org.webjars" % "swagger-ui" % "3.32.5"
|
||||
libraryDependencies += "javax.validation" % "validation-api" % "2.0.1.Final"
|
||||
libraryDependencies += guice
|
||||
libraryDependencies += "com.auth0" % "java-jwt" % "3.18.1"
|
||||
libraryDependencies += "com.auth0" % "jwks-rsa" % "0.19.0"
|
||||
libraryDependencies += "org.apache.httpcomponents" % "httpclient" % "4.5.6"
|
||||
|
@ -0,0 +1,23 @@
|
||||
# OpenAPI Generator Ignore
|
||||
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
|
||||
|
||||
# Use this file to prevent files from being overwritten by the generator.
|
||||
# The patterns follow closely to .gitignore or .dockerignore.
|
||||
|
||||
# As an example, the C# client generator defines ApiClient.cs.
|
||||
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
|
||||
#ApiClient.cs
|
||||
|
||||
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
|
||||
#foo/*/qux
|
||||
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
|
||||
|
||||
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
|
||||
#foo/**/qux
|
||||
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
|
||||
|
||||
# You can also negate patterns with an exclamation (!).
|
||||
# For example, you can ignore all files in a docs folder with the file extension .md:
|
||||
#docs/*.md
|
||||
# Then explicitly reverse the ignore rule for a single file:
|
||||
#!docs/README.md
|
@ -0,0 +1,24 @@
|
||||
LICENSE
|
||||
README
|
||||
app/Module.java
|
||||
app/apimodels/Category.java
|
||||
app/apimodels/ModelApiResponse.java
|
||||
app/apimodels/Order.java
|
||||
app/apimodels/Pet.java
|
||||
app/apimodels/Tag.java
|
||||
app/apimodels/User.java
|
||||
app/controllers/ApiDocController.java
|
||||
app/controllers/PetApiController.java
|
||||
app/controllers/PetApiControllerImp.java
|
||||
app/controllers/PetApiControllerImpInterface.java
|
||||
app/openapitools/ApiCall.java
|
||||
app/openapitools/ErrorHandler.java
|
||||
app/openapitools/OpenAPIUtils.java
|
||||
app/openapitools/SecurityAPIUtils.java
|
||||
build.sbt
|
||||
conf/application.conf
|
||||
conf/logback.xml
|
||||
conf/routes
|
||||
project/build.properties
|
||||
project/plugins.sbt
|
||||
public/openapi.json
|
@ -0,0 +1 @@
|
||||
5.3.1-SNAPSHOT
|
@ -0,0 +1,8 @@
|
||||
This software is licensed under the Apache 2 license, quoted below.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this project except in compliance with
|
||||
the License. You may obtain a copy of the License at https://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.
|
@ -0,0 +1,4 @@
|
||||
This is your new Play application
|
||||
=================================
|
||||
|
||||
This file will be packaged with your application when using `activator dist`.
|
@ -0,0 +1,13 @@
|
||||
import com.google.inject.AbstractModule;
|
||||
|
||||
import controllers.*;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
|
||||
public class Module extends AbstractModule {
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(PetApiControllerImpInterface.class).to(PetApiControllerImp.class);
|
||||
bind(SecurityAPIUtils.class);
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
package apimodels;
|
||||
|
||||
import com.fasterxml.jackson.annotation.*;
|
||||
import java.util.Set;
|
||||
import javax.validation.*;
|
||||
import java.util.Objects;
|
||||
import javax.validation.constraints.*;
|
||||
/**
|
||||
* A category for a pet
|
||||
*/
|
||||
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaPlayFrameworkCodegen")
|
||||
@SuppressWarnings({"UnusedReturnValue", "WeakerAccess"})
|
||||
public class Category {
|
||||
@JsonProperty("id")
|
||||
|
||||
private Long id;
|
||||
|
||||
@JsonProperty("name")
|
||||
|
||||
private String name;
|
||||
|
||||
public Category id(Long id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get id
|
||||
* @return id
|
||||
**/
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Category name(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get name
|
||||
* @return name
|
||||
**/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Category category = (Category) o;
|
||||
return Objects.equals(id, category.id) &&
|
||||
Objects.equals(name, category.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("StringBufferReplaceableByString")
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("class Category {\n");
|
||||
|
||||
sb.append(" id: ").append(toIndentedString(id)).append("\n");
|
||||
sb.append(" name: ").append(toIndentedString(name)).append("\n");
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given object to string with each line indented by 4 spaces
|
||||
* (except the first line).
|
||||
*/
|
||||
private String toIndentedString(Object o) {
|
||||
if (o == null) {
|
||||
return "null";
|
||||
}
|
||||
return o.toString().replace("\n", "\n ");
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,121 @@
|
||||
package apimodels;
|
||||
|
||||
import com.fasterxml.jackson.annotation.*;
|
||||
import java.util.Set;
|
||||
import javax.validation.*;
|
||||
import java.util.Objects;
|
||||
import javax.validation.constraints.*;
|
||||
/**
|
||||
* Describes the result of uploading an image resource
|
||||
*/
|
||||
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaPlayFrameworkCodegen")
|
||||
@SuppressWarnings({"UnusedReturnValue", "WeakerAccess"})
|
||||
public class ModelApiResponse {
|
||||
@JsonProperty("code")
|
||||
|
||||
private Integer code;
|
||||
|
||||
@JsonProperty("type")
|
||||
|
||||
private String type;
|
||||
|
||||
@JsonProperty("message")
|
||||
|
||||
private String message;
|
||||
|
||||
public ModelApiResponse code(Integer code) {
|
||||
this.code = code;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get code
|
||||
* @return code
|
||||
**/
|
||||
public Integer getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(Integer code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public ModelApiResponse type(String type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get type
|
||||
* @return type
|
||||
**/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public ModelApiResponse message(String message) {
|
||||
this.message = message;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get message
|
||||
* @return message
|
||||
**/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ModelApiResponse _apiResponse = (ModelApiResponse) o;
|
||||
return Objects.equals(code, _apiResponse.code) &&
|
||||
Objects.equals(type, _apiResponse.type) &&
|
||||
Objects.equals(message, _apiResponse.message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(code, type, message);
|
||||
}
|
||||
|
||||
@SuppressWarnings("StringBufferReplaceableByString")
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("class ModelApiResponse {\n");
|
||||
|
||||
sb.append(" code: ").append(toIndentedString(code)).append("\n");
|
||||
sb.append(" type: ").append(toIndentedString(type)).append("\n");
|
||||
sb.append(" message: ").append(toIndentedString(message)).append("\n");
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given object to string with each line indented by 4 spaces
|
||||
* (except the first line).
|
||||
*/
|
||||
private String toIndentedString(Object o) {
|
||||
if (o == null) {
|
||||
return "null";
|
||||
}
|
||||
return o.toString().replace("\n", "\n ");
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,225 @@
|
||||
package apimodels;
|
||||
|
||||
import java.time.OffsetDateTime;
|
||||
import com.fasterxml.jackson.annotation.*;
|
||||
import java.util.Set;
|
||||
import javax.validation.*;
|
||||
import java.util.Objects;
|
||||
import javax.validation.constraints.*;
|
||||
/**
|
||||
* An order for a pets from the pet store
|
||||
*/
|
||||
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaPlayFrameworkCodegen")
|
||||
@SuppressWarnings({"UnusedReturnValue", "WeakerAccess"})
|
||||
public class Order {
|
||||
@JsonProperty("id")
|
||||
|
||||
private Long id;
|
||||
|
||||
@JsonProperty("petId")
|
||||
|
||||
private Long petId;
|
||||
|
||||
@JsonProperty("quantity")
|
||||
|
||||
private Integer quantity;
|
||||
|
||||
@JsonProperty("shipDate")
|
||||
@Valid
|
||||
|
||||
private OffsetDateTime shipDate;
|
||||
|
||||
/**
|
||||
* Order Status
|
||||
*/
|
||||
public enum StatusEnum {
|
||||
PLACED("placed"),
|
||||
|
||||
APPROVED("approved"),
|
||||
|
||||
DELIVERED("delivered");
|
||||
|
||||
private final String value;
|
||||
|
||||
StatusEnum(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonValue
|
||||
public String toString() {
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
@JsonCreator
|
||||
public static StatusEnum fromValue(String value) {
|
||||
for (StatusEnum b : StatusEnum.values()) {
|
||||
if (b.value.equals(value)) {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Unexpected value '" + value + "'");
|
||||
}
|
||||
}
|
||||
|
||||
@JsonProperty("status")
|
||||
|
||||
private StatusEnum status;
|
||||
|
||||
@JsonProperty("complete")
|
||||
|
||||
private Boolean complete = false;
|
||||
|
||||
public Order id(Long id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get id
|
||||
* @return id
|
||||
**/
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Order petId(Long petId) {
|
||||
this.petId = petId;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get petId
|
||||
* @return petId
|
||||
**/
|
||||
public Long getPetId() {
|
||||
return petId;
|
||||
}
|
||||
|
||||
public void setPetId(Long petId) {
|
||||
this.petId = petId;
|
||||
}
|
||||
|
||||
public Order quantity(Integer quantity) {
|
||||
this.quantity = quantity;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get quantity
|
||||
* @return quantity
|
||||
**/
|
||||
public Integer getQuantity() {
|
||||
return quantity;
|
||||
}
|
||||
|
||||
public void setQuantity(Integer quantity) {
|
||||
this.quantity = quantity;
|
||||
}
|
||||
|
||||
public Order shipDate(OffsetDateTime shipDate) {
|
||||
this.shipDate = shipDate;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get shipDate
|
||||
* @return shipDate
|
||||
**/
|
||||
public OffsetDateTime getShipDate() {
|
||||
return shipDate;
|
||||
}
|
||||
|
||||
public void setShipDate(OffsetDateTime shipDate) {
|
||||
this.shipDate = shipDate;
|
||||
}
|
||||
|
||||
public Order status(StatusEnum status) {
|
||||
this.status = status;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Order Status
|
||||
* @return status
|
||||
**/
|
||||
public StatusEnum getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(StatusEnum status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public Order complete(Boolean complete) {
|
||||
this.complete = complete;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get complete
|
||||
* @return complete
|
||||
**/
|
||||
public Boolean getComplete() {
|
||||
return complete;
|
||||
}
|
||||
|
||||
public void setComplete(Boolean complete) {
|
||||
this.complete = complete;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Order order = (Order) o;
|
||||
return Objects.equals(id, order.id) &&
|
||||
Objects.equals(petId, order.petId) &&
|
||||
Objects.equals(quantity, order.quantity) &&
|
||||
Objects.equals(shipDate, order.shipDate) &&
|
||||
Objects.equals(status, order.status) &&
|
||||
Objects.equals(complete, order.complete);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, petId, quantity, shipDate, status, complete);
|
||||
}
|
||||
|
||||
@SuppressWarnings("StringBufferReplaceableByString")
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("class Order {\n");
|
||||
|
||||
sb.append(" id: ").append(toIndentedString(id)).append("\n");
|
||||
sb.append(" petId: ").append(toIndentedString(petId)).append("\n");
|
||||
sb.append(" quantity: ").append(toIndentedString(quantity)).append("\n");
|
||||
sb.append(" shipDate: ").append(toIndentedString(shipDate)).append("\n");
|
||||
sb.append(" status: ").append(toIndentedString(status)).append("\n");
|
||||
sb.append(" complete: ").append(toIndentedString(complete)).append("\n");
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given object to string with each line indented by 4 spaces
|
||||
* (except the first line).
|
||||
*/
|
||||
private String toIndentedString(Object o) {
|
||||
if (o == null) {
|
||||
return "null";
|
||||
}
|
||||
return o.toString().replace("\n", "\n ");
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,244 @@
|
||||
package apimodels;
|
||||
|
||||
import apimodels.Category;
|
||||
import apimodels.Tag;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import com.fasterxml.jackson.annotation.*;
|
||||
import java.util.Set;
|
||||
import javax.validation.*;
|
||||
import java.util.Objects;
|
||||
import javax.validation.constraints.*;
|
||||
/**
|
||||
* A pet for sale in the pet store
|
||||
*/
|
||||
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaPlayFrameworkCodegen")
|
||||
@SuppressWarnings({"UnusedReturnValue", "WeakerAccess"})
|
||||
public class Pet {
|
||||
@JsonProperty("id")
|
||||
|
||||
private Long id;
|
||||
|
||||
@JsonProperty("category")
|
||||
@Valid
|
||||
|
||||
private Category category;
|
||||
|
||||
@JsonProperty("name")
|
||||
@NotNull
|
||||
|
||||
private String name;
|
||||
|
||||
@JsonProperty("photoUrls")
|
||||
@NotNull
|
||||
|
||||
private List<String> photoUrls = new ArrayList<>();
|
||||
|
||||
@JsonProperty("tags")
|
||||
@Valid
|
||||
|
||||
private List<Tag> tags = null;
|
||||
|
||||
/**
|
||||
* pet status in the store
|
||||
*/
|
||||
public enum StatusEnum {
|
||||
AVAILABLE("available"),
|
||||
|
||||
PENDING("pending"),
|
||||
|
||||
SOLD("sold");
|
||||
|
||||
private final String value;
|
||||
|
||||
StatusEnum(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonValue
|
||||
public String toString() {
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
@JsonCreator
|
||||
public static StatusEnum fromValue(String value) {
|
||||
for (StatusEnum b : StatusEnum.values()) {
|
||||
if (b.value.equals(value)) {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Unexpected value '" + value + "'");
|
||||
}
|
||||
}
|
||||
|
||||
@JsonProperty("status")
|
||||
|
||||
private StatusEnum status;
|
||||
|
||||
public Pet id(Long id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get id
|
||||
* @return id
|
||||
**/
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Pet category(Category category) {
|
||||
this.category = category;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get category
|
||||
* @return category
|
||||
**/
|
||||
public Category getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
public void setCategory(Category category) {
|
||||
this.category = category;
|
||||
}
|
||||
|
||||
public Pet name(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get name
|
||||
* @return name
|
||||
**/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Pet photoUrls(List<String> photoUrls) {
|
||||
this.photoUrls = photoUrls;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Pet addPhotoUrlsItem(String photoUrlsItem) {
|
||||
photoUrls.add(photoUrlsItem);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get photoUrls
|
||||
* @return photoUrls
|
||||
**/
|
||||
public List<String> getPhotoUrls() {
|
||||
return photoUrls;
|
||||
}
|
||||
|
||||
public void setPhotoUrls(List<String> photoUrls) {
|
||||
this.photoUrls = photoUrls;
|
||||
}
|
||||
|
||||
public Pet tags(List<Tag> tags) {
|
||||
this.tags = tags;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Pet addTagsItem(Tag tagsItem) {
|
||||
if (tags == null) {
|
||||
tags = new ArrayList<>();
|
||||
}
|
||||
tags.add(tagsItem);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tags
|
||||
* @return tags
|
||||
**/
|
||||
public List<Tag> getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
public void setTags(List<Tag> tags) {
|
||||
this.tags = tags;
|
||||
}
|
||||
|
||||
public Pet status(StatusEnum status) {
|
||||
this.status = status;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* pet status in the store
|
||||
* @return status
|
||||
**/
|
||||
public StatusEnum getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(StatusEnum status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Pet pet = (Pet) o;
|
||||
return Objects.equals(id, pet.id) &&
|
||||
Objects.equals(category, pet.category) &&
|
||||
Objects.equals(name, pet.name) &&
|
||||
Objects.equals(photoUrls, pet.photoUrls) &&
|
||||
Objects.equals(tags, pet.tags) &&
|
||||
Objects.equals(status, pet.status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, category, name, photoUrls, tags, status);
|
||||
}
|
||||
|
||||
@SuppressWarnings("StringBufferReplaceableByString")
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("class Pet {\n");
|
||||
|
||||
sb.append(" id: ").append(toIndentedString(id)).append("\n");
|
||||
sb.append(" category: ").append(toIndentedString(category)).append("\n");
|
||||
sb.append(" name: ").append(toIndentedString(name)).append("\n");
|
||||
sb.append(" photoUrls: ").append(toIndentedString(photoUrls)).append("\n");
|
||||
sb.append(" tags: ").append(toIndentedString(tags)).append("\n");
|
||||
sb.append(" status: ").append(toIndentedString(status)).append("\n");
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given object to string with each line indented by 4 spaces
|
||||
* (except the first line).
|
||||
*/
|
||||
private String toIndentedString(Object o) {
|
||||
if (o == null) {
|
||||
return "null";
|
||||
}
|
||||
return o.toString().replace("\n", "\n ");
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,98 @@
|
||||
package apimodels;
|
||||
|
||||
import com.fasterxml.jackson.annotation.*;
|
||||
import java.util.Set;
|
||||
import javax.validation.*;
|
||||
import java.util.Objects;
|
||||
import javax.validation.constraints.*;
|
||||
/**
|
||||
* A tag for a pet
|
||||
*/
|
||||
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaPlayFrameworkCodegen")
|
||||
@SuppressWarnings({"UnusedReturnValue", "WeakerAccess"})
|
||||
public class Tag {
|
||||
@JsonProperty("id")
|
||||
|
||||
private Long id;
|
||||
|
||||
@JsonProperty("name")
|
||||
|
||||
private String name;
|
||||
|
||||
public Tag id(Long id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get id
|
||||
* @return id
|
||||
**/
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Tag name(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get name
|
||||
* @return name
|
||||
**/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Tag tag = (Tag) o;
|
||||
return Objects.equals(id, tag.id) &&
|
||||
Objects.equals(name, tag.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, name);
|
||||
}
|
||||
|
||||
@SuppressWarnings("StringBufferReplaceableByString")
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("class Tag {\n");
|
||||
|
||||
sb.append(" id: ").append(toIndentedString(id)).append("\n");
|
||||
sb.append(" name: ").append(toIndentedString(name)).append("\n");
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given object to string with each line indented by 4 spaces
|
||||
* (except the first line).
|
||||
*/
|
||||
private String toIndentedString(Object o) {
|
||||
if (o == null) {
|
||||
return "null";
|
||||
}
|
||||
return o.toString().replace("\n", "\n ");
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,236 @@
|
||||
package apimodels;
|
||||
|
||||
import com.fasterxml.jackson.annotation.*;
|
||||
import java.util.Set;
|
||||
import javax.validation.*;
|
||||
import java.util.Objects;
|
||||
import javax.validation.constraints.*;
|
||||
/**
|
||||
* A User who is purchasing from the pet store
|
||||
*/
|
||||
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaPlayFrameworkCodegen")
|
||||
@SuppressWarnings({"UnusedReturnValue", "WeakerAccess"})
|
||||
public class User {
|
||||
@JsonProperty("id")
|
||||
|
||||
private Long id;
|
||||
|
||||
@JsonProperty("username")
|
||||
|
||||
private String username;
|
||||
|
||||
@JsonProperty("firstName")
|
||||
|
||||
private String firstName;
|
||||
|
||||
@JsonProperty("lastName")
|
||||
|
||||
private String lastName;
|
||||
|
||||
@JsonProperty("email")
|
||||
|
||||
private String email;
|
||||
|
||||
@JsonProperty("password")
|
||||
|
||||
private String password;
|
||||
|
||||
@JsonProperty("phone")
|
||||
|
||||
private String phone;
|
||||
|
||||
@JsonProperty("userStatus")
|
||||
|
||||
private Integer userStatus;
|
||||
|
||||
public User id(Long id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get id
|
||||
* @return id
|
||||
**/
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public User username(String username) {
|
||||
this.username = username;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get username
|
||||
* @return username
|
||||
**/
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public User firstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get firstName
|
||||
* @return firstName
|
||||
**/
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public User lastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get lastName
|
||||
* @return lastName
|
||||
**/
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public User email(String email) {
|
||||
this.email = email;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get email
|
||||
* @return email
|
||||
**/
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public User password(String password) {
|
||||
this.password = password;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get password
|
||||
* @return password
|
||||
**/
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public User phone(String phone) {
|
||||
this.phone = phone;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get phone
|
||||
* @return phone
|
||||
**/
|
||||
public String getPhone() {
|
||||
return phone;
|
||||
}
|
||||
|
||||
public void setPhone(String phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
public User userStatus(Integer userStatus) {
|
||||
this.userStatus = userStatus;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* User Status
|
||||
* @return userStatus
|
||||
**/
|
||||
public Integer getUserStatus() {
|
||||
return userStatus;
|
||||
}
|
||||
|
||||
public void setUserStatus(Integer userStatus) {
|
||||
this.userStatus = userStatus;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
User user = (User) o;
|
||||
return Objects.equals(id, user.id) &&
|
||||
Objects.equals(username, user.username) &&
|
||||
Objects.equals(firstName, user.firstName) &&
|
||||
Objects.equals(lastName, user.lastName) &&
|
||||
Objects.equals(email, user.email) &&
|
||||
Objects.equals(password, user.password) &&
|
||||
Objects.equals(phone, user.phone) &&
|
||||
Objects.equals(userStatus, user.userStatus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, username, firstName, lastName, email, password, phone, userStatus);
|
||||
}
|
||||
|
||||
@SuppressWarnings("StringBufferReplaceableByString")
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("class User {\n");
|
||||
|
||||
sb.append(" id: ").append(toIndentedString(id)).append("\n");
|
||||
sb.append(" username: ").append(toIndentedString(username)).append("\n");
|
||||
sb.append(" firstName: ").append(toIndentedString(firstName)).append("\n");
|
||||
sb.append(" lastName: ").append(toIndentedString(lastName)).append("\n");
|
||||
sb.append(" email: ").append(toIndentedString(email)).append("\n");
|
||||
sb.append(" password: ").append(toIndentedString(password)).append("\n");
|
||||
sb.append(" phone: ").append(toIndentedString(phone)).append("\n");
|
||||
sb.append(" userStatus: ").append(toIndentedString(userStatus)).append("\n");
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the given object to string with each line indented by 4 spaces
|
||||
* (except the first line).
|
||||
*/
|
||||
private String toIndentedString(Object o) {
|
||||
if (o == null) {
|
||||
return "null";
|
||||
}
|
||||
return o.toString().replace("\n", "\n ");
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
package controllers;
|
||||
|
||||
import javax.inject.*;
|
||||
import play.mvc.*;
|
||||
|
||||
public class ApiDocController extends Controller {
|
||||
|
||||
@Inject
|
||||
private ApiDocController() {
|
||||
}
|
||||
|
||||
public Result api() {
|
||||
return redirect("/assets/lib/swagger-ui/index.html?url=/assets/openapi.json");
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
package controllers;
|
||||
|
||||
import apimodels.Pet;
|
||||
|
||||
import com.typesafe.config.Config;
|
||||
import play.mvc.Controller;
|
||||
import play.mvc.Result;
|
||||
import play.mvc.Http;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.google.inject.Inject;
|
||||
import java.io.File;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
import com.typesafe.config.Config;
|
||||
|
||||
import openapitools.OpenAPIUtils.ApiAction;
|
||||
|
||||
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaPlayFrameworkCodegen")
|
||||
public class PetApiController extends Controller {
|
||||
private final PetApiControllerImpInterface imp;
|
||||
private final ObjectMapper mapper;
|
||||
private final Config configuration;
|
||||
|
||||
@Inject
|
||||
private PetApiController(Config configuration, PetApiControllerImpInterface imp) {
|
||||
this.imp = imp;
|
||||
mapper = new ObjectMapper();
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
@ApiAction
|
||||
public Result addPet(Http.Request request) throws Exception {
|
||||
JsonNode nodebody = request.body().asJson();
|
||||
Pet body;
|
||||
if (nodebody != null) {
|
||||
body = mapper.readValue(nodebody.toString(), Pet.class);
|
||||
if (configuration.getBoolean("useInputBeanValidation")) {
|
||||
OpenAPIUtils.validate(body);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("'body' parameter is required");
|
||||
}
|
||||
return imp.addPetHttp(request, body);
|
||||
}
|
||||
|
||||
@ApiAction
|
||||
public Result findPetsByStatus(Http.Request request) throws Exception {
|
||||
String[] statusArray = request.queryString().get("status");
|
||||
if (statusArray == null) {
|
||||
throw new IllegalArgumentException("'status' parameter is required");
|
||||
}
|
||||
List<String> statusList = OpenAPIUtils.parametersToList("csv", statusArray);
|
||||
List<String> status = new ArrayList<>();
|
||||
for (String curParam : statusList) {
|
||||
if (!curParam.isEmpty()) {
|
||||
//noinspection UseBulkOperation
|
||||
status.add(curParam);
|
||||
}
|
||||
}
|
||||
return imp.findPetsByStatusHttp(request, status);
|
||||
}
|
||||
|
||||
@ApiAction
|
||||
public Result updatePet(Http.Request request) throws Exception {
|
||||
JsonNode nodebody = request.body().asJson();
|
||||
Pet body;
|
||||
if (nodebody != null) {
|
||||
body = mapper.readValue(nodebody.toString(), Pet.class);
|
||||
if (configuration.getBoolean("useInputBeanValidation")) {
|
||||
OpenAPIUtils.validate(body);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("'body' parameter is required");
|
||||
}
|
||||
return imp.updatePetHttp(request, body);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package controllers;
|
||||
|
||||
import apimodels.Pet;
|
||||
|
||||
import play.mvc.Http;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.io.FileInputStream;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
import javax.validation.constraints.*;
|
||||
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaPlayFrameworkCodegen")
|
||||
public class PetApiControllerImp extends PetApiControllerImpInterface {
|
||||
@Override
|
||||
public void addPet(Http.Request request, Pet body) throws Exception {
|
||||
//Do your magic!!!
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Pet> findPetsByStatus(Http.Request request, @NotNull List<String> status) throws Exception {
|
||||
//Do your magic!!!
|
||||
return new ArrayList<Pet>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updatePet(Http.Request request, Pet body) throws Exception {
|
||||
//Do your magic!!!
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package controllers;
|
||||
|
||||
import apimodels.Pet;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.typesafe.config.Config;
|
||||
import play.mvc.Controller;
|
||||
import play.mvc.Http;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import play.mvc.Result;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import static play.mvc.Results.ok;
|
||||
import static play.mvc.Results.unauthorized;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public abstract class PetApiControllerImpInterface {
|
||||
@Inject private Config configuration;
|
||||
@Inject private SecurityAPIUtils securityAPIUtils;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public Result addPetHttp(Http.Request request, Pet body) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_token")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
addPet(request, body);
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
public abstract void addPet(Http.Request request, Pet body) throws Exception;
|
||||
|
||||
public Result findPetsByStatusHttp(Http.Request request, @NotNull List<String> status) throws Exception {
|
||||
List<Pet> obj = findPetsByStatus(request, status);
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
}
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
public abstract List<Pet> findPetsByStatus(Http.Request request, @NotNull List<String> status) throws Exception;
|
||||
|
||||
public Result updatePetHttp(Http.Request request, Pet body) throws Exception {
|
||||
updatePet(request, body);
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
public abstract void updatePet(Http.Request request, Pet body) throws Exception;
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package openapitools;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import play.mvc.Action;
|
||||
import play.mvc.Http;
|
||||
import play.mvc.Result;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
|
||||
public class ApiCall extends Action<OpenAPIUtils.ApiAction> {
|
||||
|
||||
@Inject
|
||||
private ApiCall() {}
|
||||
|
||||
public CompletionStage<Result> call(Http.Request request) {
|
||||
try {
|
||||
//TODO: Do stuff you want to handle with each API call (metrics, logging, etc..)
|
||||
return delegate.call(request);
|
||||
} catch (Throwable t) {
|
||||
//TODO: log the error in your metric
|
||||
|
||||
//We rethrow this error so it will be caught in the ErrorHandler
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package openapitools;
|
||||
|
||||
|
||||
import com.typesafe.config.Config;
|
||||
import play.*;
|
||||
import play.api.OptionalSourceMapper;
|
||||
import play.api.UsefulException;
|
||||
import play.api.routing.Router;
|
||||
import play.http.DefaultHttpErrorHandler;
|
||||
import play.mvc.Http.*;
|
||||
import play.mvc.*;
|
||||
|
||||
import javax.inject.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import static play.mvc.Results.*;
|
||||
|
||||
@Singleton
|
||||
public class ErrorHandler extends DefaultHttpErrorHandler {
|
||||
|
||||
@Inject
|
||||
public ErrorHandler(Config configuration, Environment environment, OptionalSourceMapper sourceMapper, Provider<Router> routes) {
|
||||
super(configuration, environment, sourceMapper, routes);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CompletionStage<Result> onDevServerError(RequestHeader request, UsefulException exception) {
|
||||
return CompletableFuture.completedFuture(
|
||||
handleExceptions(exception)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CompletionStage<Result> onProdServerError(RequestHeader request, UsefulException exception) {
|
||||
return CompletableFuture.completedFuture(
|
||||
handleExceptions(exception)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void logServerError(RequestHeader request, UsefulException usefulException) {
|
||||
//Since the error is already handled, we don't want to print anything on the console
|
||||
//But if you want to have the error printed in the console, just delete this override
|
||||
}
|
||||
|
||||
private Result handleExceptions(Throwable t) {
|
||||
//TODO: Handle exception that need special response (return a special apimodel, notFound(), etc..)
|
||||
return ok();
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
package openapitools;
|
||||
|
||||
import play.mvc.With;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.Validation;
|
||||
import javax.validation.Validator;
|
||||
import javax.validation.ValidatorFactory;
|
||||
|
||||
public class OpenAPIUtils {
|
||||
|
||||
@With(ApiCall.class)
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ApiAction {
|
||||
}
|
||||
|
||||
public static <T> void validate(T obj) {
|
||||
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
|
||||
Validator validator = factory.getValidator();
|
||||
Set<ConstraintViolation<T>> constraintViolations = validator.validate(obj);
|
||||
if (constraintViolations.size() > 0) {
|
||||
StringBuilder errors = new StringBuilder();
|
||||
for (ConstraintViolation<T> constraints : constraintViolations) {
|
||||
errors.append(String.format("%s.%s %s\n",
|
||||
constraints.getRootBeanClass().getSimpleName(),
|
||||
constraints.getPropertyPath(),
|
||||
constraints.getMessage()));
|
||||
}
|
||||
throw new RuntimeException("Bean validation : " + errors);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> parametersToList(String collectionFormat, String[] values){
|
||||
List<String> params = new ArrayList<>();
|
||||
|
||||
if (values == null) {
|
||||
return params;
|
||||
}
|
||||
|
||||
if (values.length >= 1 && collectionFormat.equals("multi")) {
|
||||
params.addAll(Arrays.asList(values));
|
||||
} else {
|
||||
collectionFormat = (collectionFormat == null || collectionFormat.isEmpty() ? "csv" : collectionFormat); // default: csv
|
||||
|
||||
String delimiter = ",";
|
||||
|
||||
switch(collectionFormat) {
|
||||
case "csv": {
|
||||
delimiter = ",";
|
||||
break;
|
||||
}
|
||||
case "ssv": {
|
||||
delimiter = " ";
|
||||
break;
|
||||
}
|
||||
case "tsv": {
|
||||
delimiter = "\t";
|
||||
break;
|
||||
}
|
||||
case "pipes": {
|
||||
delimiter = "|";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
params = Arrays.asList(values[0].split(delimiter));
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
public static String parameterToString(Object param) {
|
||||
if (param == null) {
|
||||
return "";
|
||||
} else if (param instanceof Date) {
|
||||
return formatDatetime((Date) param);
|
||||
} else if (param instanceof Collection) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
for (Object o : (Collection)param) {
|
||||
if (b.length() > 0) {
|
||||
b.append(",");
|
||||
}
|
||||
b.append(String.valueOf(o));
|
||||
}
|
||||
|
||||
return b.toString();
|
||||
} else {
|
||||
return String.valueOf(param);
|
||||
}
|
||||
}
|
||||
|
||||
public static String formatDatetime(Date date) {
|
||||
return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ROOT).format(date);
|
||||
}
|
||||
}
|
@ -0,0 +1,165 @@
|
||||
package openapitools;
|
||||
|
||||
import com.auth0.jwk.Jwk;
|
||||
import com.auth0.jwk.UrlJwkProvider;
|
||||
import com.auth0.jwt.JWT;
|
||||
import com.auth0.jwt.JWTVerifier;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import com.typesafe.config.Config;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import play.mvc.Http;
|
||||
|
||||
import java.net.URL;
|
||||
import java.security.PublicKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Singleton
|
||||
public class SecurityAPIUtils {
|
||||
private final String bearerPrefix = "Bearer ";
|
||||
private final ObjectMapper mapper;
|
||||
|
||||
private boolean useOnlineValidation = false;
|
||||
|
||||
// Online validation
|
||||
private HashMap<String, String> tokenIntrospectEndpoints = new HashMap<>();
|
||||
private final String clientId;
|
||||
private final String clientSecret;
|
||||
|
||||
// Offline validation
|
||||
private HashMap<String, String> jwksEndpoints = new HashMap<>();
|
||||
private String tokenKeyId = "";
|
||||
private JWTVerifier tokenVerifier; //Reusable verifier instance until tokenKeyId changes.
|
||||
|
||||
@Inject
|
||||
SecurityAPIUtils(Config configuration) {
|
||||
mapper = new ObjectMapper();
|
||||
|
||||
clientId = configuration.hasPath("oauth.clientId") ? configuration.getString("oauth.clientId") : "";
|
||||
clientSecret = configuration.hasPath("oauth.clientSecret") ? configuration.getString("oauth.clientSecret") : "";
|
||||
|
||||
tokenIntrospectEndpoints.put("petstore_token", "https://keycloak-dev.business.stingray.com/auth/realms/CSLocal/protocol/openid-connect/token/introspect");
|
||||
|
||||
jwksEndpoints.put("petstore_token", "https://keycloak-dev.business.stingray.com/auth/realms/CSLocal/protocol/openid-connect/certs");
|
||||
}
|
||||
|
||||
private boolean isRequestTokenValidByOnlineCheck(Http.Request request, String securityMethodName) {
|
||||
try {
|
||||
Optional<String> authToken = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
|
||||
if (authToken.isPresent()) {
|
||||
String tokenWithoutBearerPrefix = authToken.get().substring(bearerPrefix.length());
|
||||
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
HttpClient httpClient = builder.build();
|
||||
HttpPost httppost = new HttpPost(this.tokenIntrospectEndpoints.get(securityMethodName));
|
||||
|
||||
List<NameValuePair> params = new ArrayList<>();
|
||||
params.add(new BasicNameValuePair("token", tokenWithoutBearerPrefix));
|
||||
params.add(new BasicNameValuePair("client_id", clientId));
|
||||
params.add(new BasicNameValuePair("client_secret", clientSecret));
|
||||
httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
|
||||
|
||||
HttpResponse response = httpClient.execute(httppost);
|
||||
String responseJsonString = EntityUtils.toString(response.getEntity());
|
||||
HashMap responseJsonObject = mapper.readValue(responseJsonString, HashMap.class);
|
||||
|
||||
return response.getStatusLine().getStatusCode() == HttpStatus.SC_OK && (boolean) responseJsonObject.get("active");
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isRequestTokenValidByOfflineCheck(Http.Request request, String securityMethodName) {
|
||||
try {
|
||||
Optional<String> authHeader = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
|
||||
if (authHeader.isPresent()) {
|
||||
String bearerToken = authHeader.get().substring(bearerPrefix.length());
|
||||
return isTokenValidByOfflineCheck(bearerToken, securityMethodName);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isTokenValidByOfflineCheck(String bearerToken, String securityMethodName) {
|
||||
try {
|
||||
DecodedJWT jwt = JWT.decode(bearerToken);
|
||||
String issuer = jwt.getIssuer();
|
||||
String keyId = jwt.getKeyId();
|
||||
if (!tokenKeyId.equals(keyId)) {
|
||||
if (securityMethodName == null) {
|
||||
securityMethodName = jwksEndpoints.keySet().stream().findFirst().get();
|
||||
}
|
||||
|
||||
Jwk jwk = new UrlJwkProvider(new URL(this.jwksEndpoints.get(securityMethodName))).get(keyId);
|
||||
final PublicKey publicKey = jwk.getPublicKey();
|
||||
|
||||
if (!(publicKey instanceof RSAPublicKey)) {
|
||||
throw new IllegalArgumentException(String.format("Key with ID %s was found in JWKS but is not a RSA-key.", keyId));
|
||||
}
|
||||
|
||||
Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) publicKey, null);
|
||||
tokenVerifier = JWT.require(algorithm)
|
||||
.withIssuer(issuer)
|
||||
.build();
|
||||
tokenKeyId = keyId;
|
||||
}
|
||||
|
||||
DecodedJWT verifiedJWT = tokenVerifier.verify(bearerToken);
|
||||
|
||||
return true;
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public String getOAuthUserIdFromRequestToken(Http.Request requestWithPreviouslyVerifiedToken) {
|
||||
try {
|
||||
Optional<String> authHeader = requestWithPreviouslyVerifiedToken.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
if (authHeader.isPresent()) {
|
||||
String bearerToken = authHeader.get().substring(bearerPrefix.length());
|
||||
return getOAuthUserIdFromToken(bearerToken);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getOAuthUserIdFromToken(String bearerToken) {
|
||||
try {
|
||||
DecodedJWT jwt = JWT.decode(bearerToken);
|
||||
return jwt.getSubject();
|
||||
} catch (Exception exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRequestTokenValid(Http.Request request, String securityMethodName) {
|
||||
return useOnlineValidation ? isRequestTokenValidByOnlineCheck(request, securityMethodName) : isRequestTokenValidByOfflineCheck(request, securityMethodName);
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
name := """openapi-java-playframework"""
|
||||
|
||||
version := "1.0-SNAPSHOT"
|
||||
|
||||
lazy val root = (project in file(".")).enablePlugins(PlayJava)
|
||||
|
||||
scalaVersion := "2.12.6"
|
||||
|
||||
libraryDependencies += "org.webjars" % "swagger-ui" % "3.32.5"
|
||||
libraryDependencies += "javax.validation" % "validation-api" % "2.0.1.Final"
|
||||
libraryDependencies += guice
|
||||
libraryDependencies += "com.auth0" % "java-jwt" % "3.18.1"
|
||||
libraryDependencies += "com.auth0" % "jwks-rsa" % "0.19.0"
|
||||
libraryDependencies += "org.apache.httpcomponents" % "httpclient" % "4.5.6"
|
@ -0,0 +1,374 @@
|
||||
# This is the main configuration file for the application.
|
||||
# https://www.playframework.com/documentation/latest/ConfigFile
|
||||
# ~~~~~
|
||||
# Play uses HOCON as its configuration file format. HOCON has a number
|
||||
# of advantages over other config formats, but there are two things that
|
||||
# can be used when modifying settings.
|
||||
#
|
||||
# You can include other configuration files in this main application.conf file:
|
||||
#include "extra-config.conf"
|
||||
#
|
||||
# You can declare variables and substitute for them:
|
||||
#mykey = ${some.value}
|
||||
#
|
||||
# And if an environment variable exists when there is no other substitution, then
|
||||
# HOCON will fall back to substituting environment variable:
|
||||
#mykey = ${JAVA_HOME}
|
||||
|
||||
play.filters.headers.contentSecurityPolicy=null
|
||||
|
||||
# When using bean validation with the OpenAPI API, the validator will check that every constraint is respected
|
||||
# This is very useful when testing but could add a lot of overhead if you return a lot of data. Benchmark have
|
||||
# shown that the time it takes to validate is exponential.
|
||||
# If this is a concern in your application, or if you don't want to validate the output coming from your API for
|
||||
# respecting its contract, set the "output" property below to "false". Since there is not a lot of data as input for
|
||||
# an endpoint, I highly suggest you let the "input" property set to true.
|
||||
useInputBeanValidation=true
|
||||
useOutputBeanValidation=true
|
||||
|
||||
play.http.errorHandler="openapitools.ErrorHandler"
|
||||
|
||||
## Akka
|
||||
# https://www.playframework.com/documentation/latest/ScalaAkka#Configuration
|
||||
# https://www.playframework.com/documentation/latest/JavaAkka#Configuration
|
||||
# ~~~~~
|
||||
# Play uses Akka internally and exposes Akka Streams and actors in Websockets and
|
||||
# other streaming HTTP responses.
|
||||
akka {
|
||||
# "akka.log-config-on-start" is extraordinarily useful because it log the complete
|
||||
# configuration at INFO level, including defaults and overrides, so it s worth
|
||||
# putting at the very top.
|
||||
#
|
||||
# Put the following in your conf/logback.xml file:
|
||||
#
|
||||
# <logger name="akka.actor" level="INFO" />
|
||||
#
|
||||
# And then uncomment this line to debug the configuration.
|
||||
#
|
||||
#log-config-on-start = true
|
||||
}
|
||||
|
||||
## Secret key
|
||||
# http://www.playframework.com/documentation/latest/ApplicationSecret
|
||||
# ~~~~~
|
||||
# The secret key is used to sign Play's session cookie.
|
||||
# This must be changed for production, but we don't recommend you change it in this file.
|
||||
play.http.secret.key = "changeme"
|
||||
|
||||
## Modules
|
||||
# https://www.playframework.com/documentation/latest/Modules
|
||||
# ~~~~~
|
||||
# Control which modules are loaded when Play starts. Note that modules are
|
||||
# the replacement for "GlobalSettings", which are deprecated in 2.5.x.
|
||||
# Please see https://www.playframework.com/documentation/latest/GlobalSettings
|
||||
# for more information.
|
||||
#
|
||||
# You can also extend Play functionality by using one of the publicly available
|
||||
# Play modules: https://playframework.com/documentation/latest/ModuleDirectory
|
||||
play.modules {
|
||||
# By default, Play will load any class called Module that is defined
|
||||
# in the root package (the "app" directory), or you can define them
|
||||
# explicitly below.
|
||||
# If there are any built-in modules that you want to disable, you can list them here.
|
||||
}
|
||||
|
||||
play.assets {
|
||||
path = "/public"
|
||||
urlPrefix = "/assets"
|
||||
}
|
||||
|
||||
## IDE
|
||||
# https://www.playframework.com/documentation/latest/IDE
|
||||
# ~~~~~
|
||||
# Depending on your IDE, you can add a hyperlink for errors that will jump you
|
||||
# directly to the code location in the IDE in dev mode. The following line makes
|
||||
# use of the IntelliJ IDEA REST interface:
|
||||
#play.editor="http://localhost:63342/api/file/?file=%s&line=%s"
|
||||
|
||||
## Internationalisation
|
||||
# https://www.playframework.com/documentation/latest/JavaI18N
|
||||
# https://www.playframework.com/documentation/latest/ScalaI18N
|
||||
# ~~~~~
|
||||
# Play comes with its own i18n settings, which allow the user's preferred language
|
||||
# to map through to internal messages, or allow the language to be stored in a cookie.
|
||||
play.i18n {
|
||||
# The application languages
|
||||
langs = [ "en" ]
|
||||
|
||||
# Whether the language cookie should be secure or not
|
||||
#langCookieSecure = true
|
||||
|
||||
# Whether the HTTP only attribute of the cookie should be set to true
|
||||
#langCookieHttpOnly = true
|
||||
}
|
||||
|
||||
## Play HTTP settings
|
||||
# ~~~~~
|
||||
play.http {
|
||||
## Router
|
||||
# https://www.playframework.com/documentation/latest/JavaRouting
|
||||
# https://www.playframework.com/documentation/latest/ScalaRouting
|
||||
# ~~~~~
|
||||
# Define the Router object to use for this application.
|
||||
# This router will be looked up first when the application is starting up,
|
||||
# so make sure this is the entry point.
|
||||
# Furthermore, it's assumed your route file is named properly.
|
||||
# So for an application router like `my.application.Router`,
|
||||
# you may need to define a router file `conf/my.application.routes`.
|
||||
# Default to Routes in the root package (aka "apps" folder) (and conf/routes)
|
||||
#router = my.application.Router
|
||||
|
||||
## Action Creator
|
||||
# https://www.playframework.com/documentation/latest/JavaActionCreator
|
||||
# ~~~~~
|
||||
#actionCreator = null
|
||||
|
||||
## ErrorHandler
|
||||
# https://www.playframework.com/documentation/latest/JavaRouting
|
||||
# https://www.playframework.com/documentation/latest/ScalaRouting
|
||||
# ~~~~~
|
||||
# If null, will attempt to load a class called ErrorHandler in the root package,
|
||||
#errorHandler = null
|
||||
|
||||
## Filters
|
||||
# https://www.playframework.com/documentation/latest/ScalaHttpFilters
|
||||
# https://www.playframework.com/documentation/latest/JavaHttpFilters
|
||||
# ~~~~~
|
||||
# Filters run code on every request. They can be used to perform
|
||||
# common logic for all your actions, e.g. adding common headers.
|
||||
# Defaults to "Filters" in the root package (aka "apps" folder)
|
||||
# Alternatively you can explicitly register a class here.
|
||||
#filters = my.application.Filters
|
||||
|
||||
## Session & Flash
|
||||
# https://www.playframework.com/documentation/latest/JavaSessionFlash
|
||||
# https://www.playframework.com/documentation/latest/ScalaSessionFlash
|
||||
# ~~~~~
|
||||
session {
|
||||
# Sets the cookie to be sent only over HTTPS.
|
||||
#secure = true
|
||||
|
||||
# Sets the cookie to be accessed only by the server.
|
||||
#httpOnly = true
|
||||
|
||||
# Sets the max-age field of the cookie to 5 minutes.
|
||||
# NOTE: this only sets when the browser will discard the cookie. Play will consider any
|
||||
# cookie value with a valid signature to be a valid session forever. To implement a server side session timeout,
|
||||
# you need to put a timestamp in the session and check it at regular intervals to possibly expire it.
|
||||
#maxAge = 300
|
||||
|
||||
# Sets the domain on the session cookie.
|
||||
#domain = "example.com"
|
||||
}
|
||||
|
||||
flash {
|
||||
# Sets the cookie to be sent only over HTTPS.
|
||||
#secure = true
|
||||
|
||||
# Sets the cookie to be accessed only by the server.
|
||||
#httpOnly = true
|
||||
}
|
||||
}
|
||||
|
||||
## Netty Provider
|
||||
# https://www.playframework.com/documentation/latest/SettingsNetty
|
||||
# ~~~~~
|
||||
play.server.netty {
|
||||
# Whether the Netty wire should be logged
|
||||
#log.wire = true
|
||||
|
||||
# If you run Play on Linux, you can use Netty's native socket transport
|
||||
# for higher performance with less garbage.
|
||||
#transport = "native"
|
||||
}
|
||||
|
||||
## WS (HTTP Client)
|
||||
# https://www.playframework.com/documentation/latest/ScalaWS#Configuring-WS
|
||||
# ~~~~~
|
||||
# The HTTP client primarily used for REST APIs. The default client can be
|
||||
# configured directly, but you can also create different client instances
|
||||
# with customized settings. You must enable this by adding to build.sbt:
|
||||
#
|
||||
# libraryDependencies += ws // or javaWs if using java
|
||||
#
|
||||
play.ws {
|
||||
# Sets HTTP requests not to follow 302 requests
|
||||
#followRedirects = false
|
||||
|
||||
# Sets the maximum number of open HTTP connections for the client.
|
||||
#ahc.maxConnectionsTotal = 50
|
||||
|
||||
## WS SSL
|
||||
# https://www.playframework.com/documentation/latest/WsSSL
|
||||
# ~~~~~
|
||||
ssl {
|
||||
# Configuring HTTPS with Play WS does not require programming. You can
|
||||
# set up both trustManager and keyManager for mutual authentication, and
|
||||
# turn on JSSE debugging in development with a reload.
|
||||
#debug.handshake = true
|
||||
#trustManager = {
|
||||
# stores = [
|
||||
# { type = "JKS", path = "exampletrust.jks" }
|
||||
# ]
|
||||
#}
|
||||
}
|
||||
}
|
||||
|
||||
## Cache
|
||||
# https://www.playframework.com/documentation/latest/JavaCache
|
||||
# https://www.playframework.com/documentation/latest/ScalaCache
|
||||
# ~~~~~
|
||||
# Play comes with an integrated cache API that can reduce the operational
|
||||
# overhead of repeated requests. You must enable this by adding to build.sbt:
|
||||
#
|
||||
# libraryDependencies += cache
|
||||
#
|
||||
play.cache {
|
||||
# If you want to bind several caches, you can bind the individually
|
||||
#bindCaches = ["db-cache", "user-cache", "session-cache"]
|
||||
}
|
||||
|
||||
## Filters
|
||||
# https://www.playframework.com/documentation/latest/Filters
|
||||
# ~~~~~
|
||||
# There are a number of built-in filters that can be enabled and configured
|
||||
# to give Play greater security. You must enable this by adding to build.sbt:
|
||||
#
|
||||
# libraryDependencies += filters
|
||||
#
|
||||
play.filters {
|
||||
## CORS filter configuration
|
||||
# https://www.playframework.com/documentation/latest/CorsFilter
|
||||
# ~~~~~
|
||||
# CORS is a protocol that allows web applications to make requests from the browser
|
||||
# across different domains.
|
||||
# NOTE: You MUST apply the CORS configuration before the CSRF filter, as CSRF has
|
||||
# dependencies on CORS settings.
|
||||
cors {
|
||||
# Filter paths by a whitelist of path prefixes
|
||||
#pathPrefixes = ["/some/path", ...]
|
||||
|
||||
# The allowed origins. If null, all origins are allowed.
|
||||
#allowedOrigins = ["http://www.example.com"]
|
||||
|
||||
# The allowed HTTP methods. If null, all methods are allowed
|
||||
#allowedHttpMethods = ["GET", "POST"]
|
||||
}
|
||||
|
||||
## CSRF Filter
|
||||
# https://www.playframework.com/documentation/latest/ScalaCsrf#Applying-a-global-CSRF-filter
|
||||
# https://www.playframework.com/documentation/latest/JavaCsrf#Applying-a-global-CSRF-filter
|
||||
# ~~~~~
|
||||
# Play supports multiple methods for verifying that a request is not a CSRF request.
|
||||
# The primary mechanism is a CSRF token. This token gets placed either in the query string
|
||||
# or body of every form submitted, and also gets placed in the users session.
|
||||
# Play then verifies that both tokens are present and match.
|
||||
csrf {
|
||||
# Sets the cookie to be sent only over HTTPS
|
||||
#cookie.secure = true
|
||||
|
||||
# Defaults to CSRFErrorHandler in the root package.
|
||||
#errorHandler = MyCSRFErrorHandler
|
||||
}
|
||||
|
||||
## Security headers filter configuration
|
||||
# https://www.playframework.com/documentation/latest/SecurityHeaders
|
||||
# ~~~~~
|
||||
# Defines security headers that prevent XSS attacks.
|
||||
# If enabled, then all options are set to the below configuration by default:
|
||||
play.filters.headers {
|
||||
|
||||
# The X-Frame-Options header. If null, the header is not set.
|
||||
#frameOptions = "DENY"
|
||||
|
||||
# The X-XSS-Protection header. If null, the header is not set.
|
||||
#xssProtection = "1; mode=block"
|
||||
|
||||
# The X-Content-Type-Options header. If null, the header is not set.
|
||||
#contentTypeOptions = "nosniff"
|
||||
|
||||
# The X-Permitted-Cross-Domain-Policies header. If null, the header is not set.
|
||||
#permittedCrossDomainPolicies = "master-only"
|
||||
|
||||
# The Content-Security-Policy header. If null, the header is not set.
|
||||
contentSecurityPolicy = "default-src 'self'"
|
||||
|
||||
# The Referrer-Policy header. If null, the header is not set.
|
||||
#referrerPolicy = "origin-when-cross-origin, strict-origin-when-cross-origin"
|
||||
|
||||
# If true, allow an action to use .withHeaders to replace one or more of the above headers
|
||||
#allowActionSpecificHeaders = false
|
||||
}
|
||||
|
||||
## Allowed hosts filter configuration
|
||||
# https://www.playframework.com/documentation/latest/AllowedHostsFilter
|
||||
# ~~~~~
|
||||
# Play provides a filter that lets you configure which hosts can access your application.
|
||||
# This is useful to prevent cache poisoning attacks.
|
||||
hosts {
|
||||
# Allow requests to example.com, its subdomains, and localhost:9000.
|
||||
#allowed = [".example.com", "localhost:9000"]
|
||||
}
|
||||
}
|
||||
|
||||
## Evolutions
|
||||
# https://www.playframework.com/documentation/latest/Evolutions
|
||||
# ~~~~~
|
||||
# Evolutions allows database scripts to be automatically run on startup in dev mode
|
||||
# for database migrations. You must enable this by adding to build.sbt:
|
||||
#
|
||||
# libraryDependencies += evolutions
|
||||
#
|
||||
play.evolutions {
|
||||
# You can disable evolutions for a specific datasource if necessary
|
||||
#db.default.enabled = false
|
||||
}
|
||||
|
||||
## Database Connection Pool
|
||||
# https://www.playframework.com/documentation/latest/SettingsJDBC
|
||||
# ~~~~~
|
||||
# Play doesn't require a JDBC database to run, but you can easily enable one.
|
||||
#
|
||||
# libraryDependencies += jdbc
|
||||
#
|
||||
play.db {
|
||||
# The combination of these two settings results in "db.default" as the
|
||||
# default JDBC pool:
|
||||
#config = "db"
|
||||
#default = "default"
|
||||
|
||||
# Play uses HikariCP as the default connection pool. You can override
|
||||
# settings by changing the prototype:
|
||||
prototype {
|
||||
# Sets a fixed JDBC connection pool size of 50
|
||||
#hikaricp.minimumIdle = 50
|
||||
#hikaricp.maximumPoolSize = 50
|
||||
}
|
||||
}
|
||||
|
||||
## JDBC Datasource
|
||||
# https://www.playframework.com/documentation/latest/JavaDatabase
|
||||
# https://www.playframework.com/documentation/latest/ScalaDatabase
|
||||
# ~~~~~
|
||||
# Once JDBC datasource is set up, you can work with several different
|
||||
# database options:
|
||||
#
|
||||
# Slick (Scala preferred option): https://www.playframework.com/documentation/latest/PlaySlick
|
||||
# JPA (Java preferred option): https://playframework.com/documentation/latest/JavaJPA
|
||||
# EBean: https://playframework.com/documentation/latest/JavaEbean
|
||||
# Anorm: https://www.playframework.com/documentation/latest/ScalaAnorm
|
||||
#
|
||||
db {
|
||||
# You can declare as many datasources as you want.
|
||||
# By convention, the default datasource is named `default`
|
||||
|
||||
# https://www.playframework.com/documentation/latest/Developing-with-the-H2-Database
|
||||
#default.driver = org.h2.Driver
|
||||
#default.url = "jdbc:h2:mem:play"
|
||||
#default.username = sa
|
||||
#default.password = ""
|
||||
|
||||
# You can turn on SQL logging for any datasource
|
||||
# https://www.playframework.com/documentation/latest/Highlights25#Logging-SQL-statements
|
||||
#default.logSql=true
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
<!-- https://www.playframework.com/documentation/latest/SettingsLogger -->
|
||||
<configuration>
|
||||
|
||||
<conversionRule conversionWord="coloredLevel" converterClass="play.api.libs.logback.ColoredLevel" />
|
||||
|
||||
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
|
||||
<file>${application.home:-.}/logs/application.log</file>
|
||||
<encoder>
|
||||
<pattern>%date [%level] from %logger in %thread - %message%n%xException</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%coloredLevel %logger{15} - %message%n%xException{10}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="ASYNCFILE" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<appender-ref ref="FILE" />
|
||||
</appender>
|
||||
|
||||
<appender name="ASYNCSTDOUT" class="ch.qos.logback.classic.AsyncAppender">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</appender>
|
||||
|
||||
<logger name="play" level="INFO" />
|
||||
<logger name="application" level="DEBUG" />
|
||||
|
||||
<!-- Off these ones as they are annoying, and anyway we manage configuration ourselves -->
|
||||
<logger name="com.avaje.ebean.config.PropertyMapLoader" level="OFF" />
|
||||
<logger name="com.avaje.ebeaninternal.server.core.XmlConfigLoader" level="OFF" />
|
||||
<logger name="com.avaje.ebeaninternal.server.lib.BackgroundThread" level="OFF" />
|
||||
<logger name="com.gargoylesoftware.htmlunit.javascript" level="OFF" />
|
||||
|
||||
<root level="WARN">
|
||||
<appender-ref ref="ASYNCFILE" />
|
||||
<appender-ref ref="ASYNCSTDOUT" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
@ -0,0 +1,15 @@
|
||||
# Routes
|
||||
# This file defines all application routes (Higher priority routes first)
|
||||
# ~~~~
|
||||
|
||||
GET /api controllers.ApiDocController.api
|
||||
|
||||
|
||||
#Functions for Pet API
|
||||
POST /v2/pet controllers.PetApiController.addPet(request: Request)
|
||||
GET /v2/pet/findByStatus controllers.PetApiController.findPetsByStatus(request: Request)
|
||||
PUT /v2/pet controllers.PetApiController.updatePet(request: Request)
|
||||
|
||||
# Map static resources from the /public folder to the /assets URL path
|
||||
GET /assets/*file controllers.Assets.at(file)
|
||||
GET /versionedAssets/*file controllers.Assets.versioned(file)
|
@ -0,0 +1 @@
|
||||
sbt.version=1.3.13
|
@ -0,0 +1,2 @@
|
||||
// The Play plugin
|
||||
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.8.3")
|
@ -0,0 +1,377 @@
|
||||
{
|
||||
"openapi" : "3.0.1",
|
||||
"info" : {
|
||||
"description" : "This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.",
|
||||
"license" : {
|
||||
"name" : "Apache-2.0",
|
||||
"url" : "https://www.apache.org/licenses/LICENSE-2.0.html"
|
||||
},
|
||||
"title" : "OpenAPI Petstore",
|
||||
"version" : "1.0.0"
|
||||
},
|
||||
"servers" : [ {
|
||||
"url" : "http://petstore.swagger.io/v2"
|
||||
} ],
|
||||
"tags" : [ {
|
||||
"description" : "Everything about your Pets",
|
||||
"name" : "pet"
|
||||
}, {
|
||||
"description" : "Access to Petstore orders",
|
||||
"name" : "store"
|
||||
}, {
|
||||
"description" : "Operations about user",
|
||||
"name" : "user"
|
||||
} ],
|
||||
"paths" : {
|
||||
"/pet" : {
|
||||
"post" : {
|
||||
"operationId" : "addPet",
|
||||
"requestBody" : {
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
"$ref" : "#/components/schemas/Pet"
|
||||
}
|
||||
},
|
||||
"application/xml" : {
|
||||
"schema" : {
|
||||
"$ref" : "#/components/schemas/Pet"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description" : "Pet object that needs to be added to the store",
|
||||
"required" : true
|
||||
},
|
||||
"responses" : {
|
||||
"405" : {
|
||||
"content" : { },
|
||||
"description" : "Invalid input"
|
||||
}
|
||||
},
|
||||
"security" : [ {
|
||||
"petstore_token" : [ "base" ]
|
||||
} ],
|
||||
"summary" : "Add a new pet to the store",
|
||||
"tags" : [ "pet" ],
|
||||
"x-codegen-request-body-name" : "body",
|
||||
"x-contentType" : "application/json",
|
||||
"x-accepts" : "application/json"
|
||||
},
|
||||
"put" : {
|
||||
"operationId" : "updatePet",
|
||||
"requestBody" : {
|
||||
"content" : {
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
"$ref" : "#/components/schemas/Pet"
|
||||
}
|
||||
},
|
||||
"application/xml" : {
|
||||
"schema" : {
|
||||
"$ref" : "#/components/schemas/Pet"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description" : "Pet object that needs to be added to the store",
|
||||
"required" : true
|
||||
},
|
||||
"responses" : {
|
||||
"400" : {
|
||||
"content" : { },
|
||||
"description" : "Invalid ID supplied"
|
||||
},
|
||||
"404" : {
|
||||
"content" : { },
|
||||
"description" : "Pet not found"
|
||||
},
|
||||
"405" : {
|
||||
"content" : { },
|
||||
"description" : "Validation exception"
|
||||
}
|
||||
},
|
||||
"security" : [ {
|
||||
"petstore_auth" : [ "write:pets", "read:pets" ]
|
||||
} ],
|
||||
"summary" : "Update an existing pet",
|
||||
"tags" : [ "pet" ],
|
||||
"x-codegen-request-body-name" : "body",
|
||||
"x-contentType" : "application/json",
|
||||
"x-accepts" : "application/json"
|
||||
}
|
||||
},
|
||||
"/pet/findByStatus" : {
|
||||
"get" : {
|
||||
"description" : "Multiple status values can be provided with comma separated strings",
|
||||
"operationId" : "findPetsByStatus",
|
||||
"parameters" : [ {
|
||||
"description" : "Status values that need to be considered for filter",
|
||||
"explode" : false,
|
||||
"in" : "query",
|
||||
"name" : "status",
|
||||
"required" : true,
|
||||
"schema" : {
|
||||
"items" : {
|
||||
"default" : "available",
|
||||
"enum" : [ "available", "pending", "sold" ],
|
||||
"type" : "string"
|
||||
},
|
||||
"type" : "array"
|
||||
},
|
||||
"style" : "form"
|
||||
} ],
|
||||
"responses" : {
|
||||
"200" : {
|
||||
"content" : {
|
||||
"application/xml" : {
|
||||
"schema" : {
|
||||
"items" : {
|
||||
"$ref" : "#/components/schemas/Pet"
|
||||
},
|
||||
"type" : "array"
|
||||
}
|
||||
},
|
||||
"application/json" : {
|
||||
"schema" : {
|
||||
"items" : {
|
||||
"$ref" : "#/components/schemas/Pet"
|
||||
},
|
||||
"type" : "array"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description" : "successful operation"
|
||||
},
|
||||
"400" : {
|
||||
"content" : { },
|
||||
"description" : "Invalid status value"
|
||||
}
|
||||
},
|
||||
"summary" : "Finds Pets by status",
|
||||
"tags" : [ "pet" ],
|
||||
"x-accepts" : "application/json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"components" : {
|
||||
"schemas" : {
|
||||
"Order" : {
|
||||
"description" : "An order for a pets from the pet store",
|
||||
"properties" : {
|
||||
"id" : {
|
||||
"format" : "int64",
|
||||
"type" : "integer"
|
||||
},
|
||||
"petId" : {
|
||||
"format" : "int64",
|
||||
"type" : "integer"
|
||||
},
|
||||
"quantity" : {
|
||||
"format" : "int32",
|
||||
"type" : "integer"
|
||||
},
|
||||
"shipDate" : {
|
||||
"format" : "date-time",
|
||||
"type" : "string"
|
||||
},
|
||||
"status" : {
|
||||
"description" : "Order Status",
|
||||
"enum" : [ "placed", "approved", "delivered" ],
|
||||
"type" : "string"
|
||||
},
|
||||
"complete" : {
|
||||
"default" : false,
|
||||
"type" : "boolean"
|
||||
}
|
||||
},
|
||||
"title" : "Pet Order",
|
||||
"type" : "object",
|
||||
"xml" : {
|
||||
"name" : "Order"
|
||||
}
|
||||
},
|
||||
"Category" : {
|
||||
"description" : "A category for a pet",
|
||||
"example" : {
|
||||
"name" : "name",
|
||||
"id" : 6
|
||||
},
|
||||
"properties" : {
|
||||
"id" : {
|
||||
"format" : "int64",
|
||||
"type" : "integer"
|
||||
},
|
||||
"name" : {
|
||||
"type" : "string"
|
||||
}
|
||||
},
|
||||
"title" : "Pet category",
|
||||
"type" : "object",
|
||||
"xml" : {
|
||||
"name" : "Category"
|
||||
}
|
||||
},
|
||||
"User" : {
|
||||
"description" : "A User who is purchasing from the pet store",
|
||||
"properties" : {
|
||||
"id" : {
|
||||
"format" : "int64",
|
||||
"type" : "integer"
|
||||
},
|
||||
"username" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"firstName" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"lastName" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"email" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"password" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"phone" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"userStatus" : {
|
||||
"description" : "User Status",
|
||||
"format" : "int32",
|
||||
"type" : "integer"
|
||||
}
|
||||
},
|
||||
"title" : "a User",
|
||||
"type" : "object",
|
||||
"xml" : {
|
||||
"name" : "User"
|
||||
}
|
||||
},
|
||||
"Tag" : {
|
||||
"description" : "A tag for a pet",
|
||||
"example" : {
|
||||
"name" : "name",
|
||||
"id" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"id" : {
|
||||
"format" : "int64",
|
||||
"type" : "integer"
|
||||
},
|
||||
"name" : {
|
||||
"type" : "string"
|
||||
}
|
||||
},
|
||||
"title" : "Pet Tag",
|
||||
"type" : "object",
|
||||
"xml" : {
|
||||
"name" : "Tag"
|
||||
}
|
||||
},
|
||||
"Pet" : {
|
||||
"description" : "A pet for sale in the pet store",
|
||||
"example" : {
|
||||
"photoUrls" : [ "photoUrls", "photoUrls" ],
|
||||
"name" : "doggie",
|
||||
"id" : 0,
|
||||
"category" : {
|
||||
"name" : "name",
|
||||
"id" : 6
|
||||
},
|
||||
"tags" : [ {
|
||||
"name" : "name",
|
||||
"id" : 1
|
||||
}, {
|
||||
"name" : "name",
|
||||
"id" : 1
|
||||
} ],
|
||||
"status" : "available"
|
||||
},
|
||||
"properties" : {
|
||||
"id" : {
|
||||
"format" : "int64",
|
||||
"type" : "integer"
|
||||
},
|
||||
"category" : {
|
||||
"$ref" : "#/components/schemas/Category"
|
||||
},
|
||||
"name" : {
|
||||
"example" : "doggie",
|
||||
"type" : "string"
|
||||
},
|
||||
"photoUrls" : {
|
||||
"items" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"type" : "array",
|
||||
"xml" : {
|
||||
"name" : "photoUrl",
|
||||
"wrapped" : true
|
||||
}
|
||||
},
|
||||
"tags" : {
|
||||
"items" : {
|
||||
"$ref" : "#/components/schemas/Tag"
|
||||
},
|
||||
"type" : "array",
|
||||
"xml" : {
|
||||
"name" : "tag",
|
||||
"wrapped" : true
|
||||
}
|
||||
},
|
||||
"status" : {
|
||||
"description" : "pet status in the store",
|
||||
"enum" : [ "available", "pending", "sold" ],
|
||||
"type" : "string"
|
||||
}
|
||||
},
|
||||
"required" : [ "name", "photoUrls" ],
|
||||
"title" : "a Pet",
|
||||
"type" : "object",
|
||||
"xml" : {
|
||||
"name" : "Pet"
|
||||
}
|
||||
},
|
||||
"ApiResponse" : {
|
||||
"description" : "Describes the result of uploading an image resource",
|
||||
"properties" : {
|
||||
"code" : {
|
||||
"format" : "int32",
|
||||
"type" : "integer"
|
||||
},
|
||||
"type" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"message" : {
|
||||
"type" : "string"
|
||||
}
|
||||
},
|
||||
"title" : "An uploaded response",
|
||||
"type" : "object"
|
||||
}
|
||||
},
|
||||
"securitySchemes" : {
|
||||
"petstore_token" : {
|
||||
"description" : "security definition for using keycloak authentification with control site.",
|
||||
"flows" : {
|
||||
"authorizationCode" : {
|
||||
"authorizationUrl" : "https://keycloak-dev.business.stingray.com/auth/realms/CSLocal/protocol/openid-connect/auth",
|
||||
"scopes" : {
|
||||
"base" : "not sure if we will be using scopes, at least in the beginning, but since we need to specify one...."
|
||||
},
|
||||
"tokenUrl" : "https://keycloak-dev.business.stingray.com/auth/realms/CSLocal/protocol/openid-connect/token"
|
||||
}
|
||||
},
|
||||
"type" : "oauth2",
|
||||
"x-jwksUrl" : "https://keycloak-dev.business.stingray.com/auth/realms/CSLocal/protocol/openid-connect/certs",
|
||||
"x-tokenIntrospectUrl" : "https://keycloak-dev.business.stingray.com/auth/realms/CSLocal/protocol/openid-connect/token/introspect"
|
||||
},
|
||||
"api_key" : {
|
||||
"in" : "header",
|
||||
"name" : "api_key",
|
||||
"type" : "apiKey"
|
||||
}
|
||||
}
|
||||
},
|
||||
"x-original-swagger-version" : "2.0"
|
||||
}
|
@ -69,6 +69,7 @@ app/controllers/UserApiControllerImpInterface.java
|
||||
app/openapitools/ApiCall.java
|
||||
app/openapitools/ErrorHandler.java
|
||||
app/openapitools/OpenAPIUtils.java
|
||||
app/openapitools/SecurityAPIUtils.java
|
||||
build.sbt
|
||||
conf/application.conf
|
||||
conf/logback.xml
|
||||
|
@ -1,6 +1,7 @@
|
||||
import com.google.inject.AbstractModule;
|
||||
|
||||
import controllers.*;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
|
||||
public class Module extends AbstractModule {
|
||||
|
||||
@ -12,5 +13,6 @@ public class Module extends AbstractModule {
|
||||
bind(PetApiControllerImpInterface.class).to(PetApiControllerImp.class);
|
||||
bind(StoreApiControllerImpInterface.class).to(StoreApiControllerImp.class);
|
||||
bind(UserApiControllerImpInterface.class).to(UserApiControllerImp.class);
|
||||
bind(SecurityAPIUtils.class);
|
||||
}
|
||||
}
|
@ -13,7 +13,9 @@ import play.mvc.Result;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import static play.mvc.Results.ok;
|
||||
import static play.mvc.Results.unauthorized;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
@ -21,15 +23,19 @@ import javax.validation.constraints.*;
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public abstract class AnotherFakeApiControllerImpInterface {
|
||||
@Inject private Config configuration;
|
||||
@Inject private SecurityAPIUtils securityAPIUtils;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public Result call123testSpecialTagsHttp(Http.Request request, Client body) throws Exception {
|
||||
Client obj = call123testSpecialTags(request, body);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,9 @@ import play.mvc.Result;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import static play.mvc.Results.ok;
|
||||
import static play.mvc.Results.unauthorized;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
@ -30,11 +32,12 @@ import javax.validation.constraints.*;
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public abstract class FakeApiControllerImpInterface {
|
||||
@Inject private Config configuration;
|
||||
@Inject private SecurityAPIUtils securityAPIUtils;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public Result createXmlItemHttp(Http.Request request, XmlItem xmlItem) throws Exception {
|
||||
createXmlItem(request, xmlItem);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -42,8 +45,9 @@ return ok();
|
||||
|
||||
public Result fakeOuterBooleanSerializeHttp(Http.Request request, Boolean body) throws Exception {
|
||||
Boolean obj = fakeOuterBooleanSerialize(request, body);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -51,11 +55,14 @@ return ok(result);
|
||||
|
||||
public Result fakeOuterCompositeSerializeHttp(Http.Request request, OuterComposite body) throws Exception {
|
||||
OuterComposite obj = fakeOuterCompositeSerialize(request, body);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -63,11 +70,14 @@ return ok(result);
|
||||
|
||||
public Result fakeOuterNumberSerializeHttp(Http.Request request, BigDecimal body) throws Exception {
|
||||
BigDecimal obj = fakeOuterNumberSerialize(request, body);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -75,8 +85,9 @@ return ok(result);
|
||||
|
||||
public Result fakeOuterStringSerializeHttp(Http.Request request, String body) throws Exception {
|
||||
String obj = fakeOuterStringSerialize(request, body);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -84,7 +95,7 @@ return ok(result);
|
||||
|
||||
public Result testBodyWithFileSchemaHttp(Http.Request request, FileSchemaTestClass body) throws Exception {
|
||||
testBodyWithFileSchema(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -92,7 +103,7 @@ return ok();
|
||||
|
||||
public Result testBodyWithQueryParamsHttp(Http.Request request, @NotNull String query, User body) throws Exception {
|
||||
testBodyWithQueryParams(request, query, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -100,11 +111,14 @@ return ok();
|
||||
|
||||
public Result testClientModelHttp(Http.Request request, Client body) throws Exception {
|
||||
Client obj = testClientModel(request, body);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -112,7 +126,7 @@ return ok(result);
|
||||
|
||||
public Result testEndpointParametersHttp(Http.Request request, BigDecimal number, Double _double, String patternWithoutDelimiter, byte[] _byte, Integer integer, Integer int32, Long int64, Float _float, String string, Http.MultipartFormData.FilePart<TemporaryFile> binary, LocalDate date, OffsetDateTime dateTime, String password, String paramCallback) throws Exception {
|
||||
testEndpointParameters(request, number, _double, patternWithoutDelimiter, _byte, integer, int32, int64, _float, string, binary, date, dateTime, password, paramCallback);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -120,7 +134,7 @@ return ok();
|
||||
|
||||
public Result testEnumParametersHttp(Http.Request request, List<String> enumHeaderStringArray, String enumHeaderString, List<String> enumQueryStringArray, String enumQueryString, Integer enumQueryInteger, Double enumQueryDouble, List<String> enumFormStringArray, String enumFormString) throws Exception {
|
||||
testEnumParameters(request, enumHeaderStringArray, enumHeaderString, enumQueryStringArray, enumQueryString, enumQueryInteger, enumQueryDouble, enumFormStringArray, enumFormString);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -128,7 +142,7 @@ return ok();
|
||||
|
||||
public Result testGroupParametersHttp(Http.Request request, @NotNull Integer requiredStringGroup, Boolean requiredBooleanGroup, @NotNull Long requiredInt64Group, Integer stringGroup, Boolean booleanGroup, Long int64Group) throws Exception {
|
||||
testGroupParameters(request, requiredStringGroup, requiredBooleanGroup, requiredInt64Group, stringGroup, booleanGroup, int64Group);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -136,7 +150,7 @@ return ok();
|
||||
|
||||
public Result testInlineAdditionalPropertiesHttp(Http.Request request, Map<String, String> param) throws Exception {
|
||||
testInlineAdditionalProperties(request, param);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -144,7 +158,7 @@ return ok();
|
||||
|
||||
public Result testJsonFormDataHttp(Http.Request request, String param, String param2) throws Exception {
|
||||
testJsonFormData(request, param, param2);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -152,7 +166,7 @@ return ok();
|
||||
|
||||
public Result testQueryParameterCollectionFormatHttp(Http.Request request, @NotNull List<String> pipe, @NotNull List<String> ioutil, @NotNull List<String> http, @NotNull List<String> url, @NotNull List<String> context) throws Exception {
|
||||
testQueryParameterCollectionFormat(request, pipe, ioutil, http, url, context);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,9 @@ import play.mvc.Result;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import static play.mvc.Results.ok;
|
||||
import static play.mvc.Results.unauthorized;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
@ -21,15 +23,19 @@ import javax.validation.constraints.*;
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public abstract class FakeClassnameTags123ApiControllerImpInterface {
|
||||
@Inject private Config configuration;
|
||||
@Inject private SecurityAPIUtils securityAPIUtils;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public Result testClassnameHttp(Http.Request request, Client body) throws Exception {
|
||||
Client obj = testClassname(request, body);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,9 @@ import play.mvc.Result;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import static play.mvc.Results.ok;
|
||||
import static play.mvc.Results.unauthorized;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
@ -24,47 +26,70 @@ import javax.validation.constraints.*;
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public abstract class PetApiControllerImpInterface {
|
||||
@Inject private Config configuration;
|
||||
@Inject private SecurityAPIUtils securityAPIUtils;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public Result addPetHttp(Http.Request request, Pet body) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
addPet(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
public abstract void addPet(Http.Request request, Pet body) throws Exception;
|
||||
|
||||
public Result deletePetHttp(Http.Request request, Long petId, String apiKey) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
deletePet(request, petId, apiKey);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
public abstract void deletePet(Http.Request request, Long petId, String apiKey) throws Exception;
|
||||
|
||||
public Result findPetsByStatusHttp(Http.Request request, @NotNull List<String> status) throws Exception {
|
||||
List<Pet> obj = findPetsByStatus(request, status);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
|
||||
List<Pet> obj = findPetsByStatus(request, status);
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
}
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
public abstract List<Pet> findPetsByStatus(Http.Request request, @NotNull List<String> status) throws Exception;
|
||||
|
||||
public Result findPetsByTagsHttp(Http.Request request, @NotNull Set<String> tags) throws Exception {
|
||||
Set<Pet> obj = findPetsByTags(request, tags);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
|
||||
Set<Pet> obj = findPetsByTags(request, tags);
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
}
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -72,51 +97,76 @@ return ok(result);
|
||||
|
||||
public Result getPetByIdHttp(Http.Request request, Long petId) throws Exception {
|
||||
Pet obj = getPetById(request, petId);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
public abstract Pet getPetById(Http.Request request, Long petId) throws Exception;
|
||||
|
||||
public Result updatePetHttp(Http.Request request, Pet body) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
updatePet(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
public abstract void updatePet(Http.Request request, Pet body) throws Exception;
|
||||
|
||||
public Result updatePetWithFormHttp(Http.Request request, Long petId, String name, String status) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
updatePetWithForm(request, petId, name, status);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
public abstract void updatePetWithForm(Http.Request request, Long petId, String name, String status) throws Exception;
|
||||
|
||||
public Result uploadFileHttp(Http.Request request, Long petId, String additionalMetadata, Http.MultipartFormData.FilePart<TemporaryFile> file) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
ModelApiResponse obj = uploadFile(request, petId, additionalMetadata, file);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
public abstract ModelApiResponse uploadFile(Http.Request request, Long petId, String additionalMetadata, Http.MultipartFormData.FilePart<TemporaryFile> file) throws Exception;
|
||||
|
||||
public Result uploadFileWithRequiredFileHttp(Http.Request request, Long petId, Http.MultipartFormData.FilePart<TemporaryFile> requiredFile, String additionalMetadata) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
ModelApiResponse obj = uploadFileWithRequiredFile(request, petId, requiredFile, additionalMetadata);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,9 @@ import play.mvc.Result;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import static play.mvc.Results.ok;
|
||||
import static play.mvc.Results.unauthorized;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
@ -22,11 +24,12 @@ import javax.validation.constraints.*;
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public abstract class StoreApiControllerImpInterface {
|
||||
@Inject private Config configuration;
|
||||
@Inject private SecurityAPIUtils securityAPIUtils;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public Result deleteOrderHttp(Http.Request request, String orderId) throws Exception {
|
||||
deleteOrder(request, orderId);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -34,8 +37,9 @@ return ok();
|
||||
|
||||
public Result getInventoryHttp(Http.Request request) throws Exception {
|
||||
Map<String, Integer> obj = getInventory(request);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -43,11 +47,14 @@ return ok(result);
|
||||
|
||||
public Result getOrderByIdHttp(Http.Request request, @Min(1) @Max(5)Long orderId) throws Exception {
|
||||
Order obj = getOrderById(request, orderId);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -55,11 +62,14 @@ return ok(result);
|
||||
|
||||
public Result placeOrderHttp(Http.Request request, Order body) throws Exception {
|
||||
Order obj = placeOrder(request, body);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,9 @@ import play.mvc.Result;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import static play.mvc.Results.ok;
|
||||
import static play.mvc.Results.unauthorized;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
@ -23,11 +25,12 @@ import javax.validation.constraints.*;
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public abstract class UserApiControllerImpInterface {
|
||||
@Inject private Config configuration;
|
||||
@Inject private SecurityAPIUtils securityAPIUtils;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public Result createUserHttp(Http.Request request, User body) throws Exception {
|
||||
createUser(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -35,7 +38,7 @@ return ok();
|
||||
|
||||
public Result createUsersWithArrayInputHttp(Http.Request request, List<User> body) throws Exception {
|
||||
createUsersWithArrayInput(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -43,7 +46,7 @@ return ok();
|
||||
|
||||
public Result createUsersWithListInputHttp(Http.Request request, List<User> body) throws Exception {
|
||||
createUsersWithListInput(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -51,7 +54,7 @@ return ok();
|
||||
|
||||
public Result deleteUserHttp(Http.Request request, String username) throws Exception {
|
||||
deleteUser(request, username);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -59,11 +62,14 @@ return ok();
|
||||
|
||||
public Result getUserByNameHttp(Http.Request request, String username) throws Exception {
|
||||
User obj = getUserByName(request, username);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -71,8 +77,9 @@ return ok(result);
|
||||
|
||||
public Result loginUserHttp(Http.Request request, @NotNull String username, @NotNull String password) throws Exception {
|
||||
String obj = loginUser(request, username, password);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -80,7 +87,7 @@ return ok(result);
|
||||
|
||||
public Result logoutUserHttp(Http.Request request) throws Exception {
|
||||
logoutUser(request);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -88,7 +95,7 @@ return ok();
|
||||
|
||||
public Result updateUserHttp(Http.Request request, String username, User body) throws Exception {
|
||||
updateUser(request, username, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,165 @@
|
||||
package openapitools;
|
||||
|
||||
import com.auth0.jwk.Jwk;
|
||||
import com.auth0.jwk.UrlJwkProvider;
|
||||
import com.auth0.jwt.JWT;
|
||||
import com.auth0.jwt.JWTVerifier;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import com.typesafe.config.Config;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import play.mvc.Http;
|
||||
|
||||
import java.net.URL;
|
||||
import java.security.PublicKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Singleton
|
||||
public class SecurityAPIUtils {
|
||||
private final String bearerPrefix = "Bearer ";
|
||||
private final ObjectMapper mapper;
|
||||
|
||||
private boolean useOnlineValidation = false;
|
||||
|
||||
// Online validation
|
||||
private HashMap<String, String> tokenIntrospectEndpoints = new HashMap<>();
|
||||
private final String clientId;
|
||||
private final String clientSecret;
|
||||
|
||||
// Offline validation
|
||||
private HashMap<String, String> jwksEndpoints = new HashMap<>();
|
||||
private String tokenKeyId = "";
|
||||
private JWTVerifier tokenVerifier; //Reusable verifier instance until tokenKeyId changes.
|
||||
|
||||
@Inject
|
||||
SecurityAPIUtils(Config configuration) {
|
||||
mapper = new ObjectMapper();
|
||||
|
||||
clientId = configuration.hasPath("oauth.clientId") ? configuration.getString("oauth.clientId") : "";
|
||||
clientSecret = configuration.hasPath("oauth.clientSecret") ? configuration.getString("oauth.clientSecret") : "";
|
||||
|
||||
tokenIntrospectEndpoints.put("petstore_auth", "");
|
||||
|
||||
jwksEndpoints.put("petstore_auth", "");
|
||||
}
|
||||
|
||||
private boolean isRequestTokenValidByOnlineCheck(Http.Request request, String securityMethodName) {
|
||||
try {
|
||||
Optional<String> authToken = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
|
||||
if (authToken.isPresent()) {
|
||||
String tokenWithoutBearerPrefix = authToken.get().substring(bearerPrefix.length());
|
||||
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
HttpClient httpClient = builder.build();
|
||||
HttpPost httppost = new HttpPost(this.tokenIntrospectEndpoints.get(securityMethodName));
|
||||
|
||||
List<NameValuePair> params = new ArrayList<>();
|
||||
params.add(new BasicNameValuePair("token", tokenWithoutBearerPrefix));
|
||||
params.add(new BasicNameValuePair("client_id", clientId));
|
||||
params.add(new BasicNameValuePair("client_secret", clientSecret));
|
||||
httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
|
||||
|
||||
HttpResponse response = httpClient.execute(httppost);
|
||||
String responseJsonString = EntityUtils.toString(response.getEntity());
|
||||
HashMap responseJsonObject = mapper.readValue(responseJsonString, HashMap.class);
|
||||
|
||||
return response.getStatusLine().getStatusCode() == HttpStatus.SC_OK && (boolean) responseJsonObject.get("active");
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isRequestTokenValidByOfflineCheck(Http.Request request, String securityMethodName) {
|
||||
try {
|
||||
Optional<String> authHeader = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
|
||||
if (authHeader.isPresent()) {
|
||||
String bearerToken = authHeader.get().substring(bearerPrefix.length());
|
||||
return isTokenValidByOfflineCheck(bearerToken, securityMethodName);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isTokenValidByOfflineCheck(String bearerToken, String securityMethodName) {
|
||||
try {
|
||||
DecodedJWT jwt = JWT.decode(bearerToken);
|
||||
String issuer = jwt.getIssuer();
|
||||
String keyId = jwt.getKeyId();
|
||||
if (!tokenKeyId.equals(keyId)) {
|
||||
if (securityMethodName == null) {
|
||||
securityMethodName = jwksEndpoints.keySet().stream().findFirst().get();
|
||||
}
|
||||
|
||||
Jwk jwk = new UrlJwkProvider(new URL(this.jwksEndpoints.get(securityMethodName))).get(keyId);
|
||||
final PublicKey publicKey = jwk.getPublicKey();
|
||||
|
||||
if (!(publicKey instanceof RSAPublicKey)) {
|
||||
throw new IllegalArgumentException(String.format("Key with ID %s was found in JWKS but is not a RSA-key.", keyId));
|
||||
}
|
||||
|
||||
Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) publicKey, null);
|
||||
tokenVerifier = JWT.require(algorithm)
|
||||
.withIssuer(issuer)
|
||||
.build();
|
||||
tokenKeyId = keyId;
|
||||
}
|
||||
|
||||
DecodedJWT verifiedJWT = tokenVerifier.verify(bearerToken);
|
||||
|
||||
return true;
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public String getOAuthUserIdFromRequestToken(Http.Request requestWithPreviouslyVerifiedToken) {
|
||||
try {
|
||||
Optional<String> authHeader = requestWithPreviouslyVerifiedToken.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
if (authHeader.isPresent()) {
|
||||
String bearerToken = authHeader.get().substring(bearerPrefix.length());
|
||||
return getOAuthUserIdFromToken(bearerToken);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getOAuthUserIdFromToken(String bearerToken) {
|
||||
try {
|
||||
DecodedJWT jwt = JWT.decode(bearerToken);
|
||||
return jwt.getSubject();
|
||||
} catch (Exception exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRequestTokenValid(Http.Request request, String securityMethodName) {
|
||||
return useOnlineValidation ? isRequestTokenValidByOnlineCheck(request, securityMethodName) : isRequestTokenValidByOfflineCheck(request, securityMethodName);
|
||||
}
|
||||
}
|
@ -9,3 +9,6 @@ scalaVersion := "2.12.6"
|
||||
libraryDependencies += "org.webjars" % "swagger-ui" % "3.32.5"
|
||||
libraryDependencies += "javax.validation" % "validation-api" % "2.0.1.Final"
|
||||
libraryDependencies += guice
|
||||
libraryDependencies += "com.auth0" % "java-jwt" % "3.18.1"
|
||||
libraryDependencies += "com.auth0" % "jwks-rsa" % "0.19.0"
|
||||
libraryDependencies += "org.apache.httpcomponents" % "httpclient" % "4.5.6"
|
||||
|
@ -20,6 +20,7 @@ app/controllers/UserApiControllerImpInterface.java
|
||||
app/openapitools/ApiCall.java
|
||||
app/openapitools/ErrorHandler.java
|
||||
app/openapitools/OpenAPIUtils.java
|
||||
app/openapitools/SecurityAPIUtils.java
|
||||
build.sbt
|
||||
conf/application.conf
|
||||
conf/logback.xml
|
||||
|
@ -1,6 +1,7 @@
|
||||
import com.google.inject.AbstractModule;
|
||||
|
||||
import controllers.*;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
|
||||
public class Module extends AbstractModule {
|
||||
|
||||
@ -9,5 +10,6 @@ public class Module extends AbstractModule {
|
||||
bind(PetApiControllerImpInterface.class).to(PetApiControllerImp.class);
|
||||
bind(StoreApiControllerImpInterface.class).to(StoreApiControllerImp.class);
|
||||
bind(UserApiControllerImpInterface.class).to(UserApiControllerImp.class);
|
||||
bind(SecurityAPIUtils.class);
|
||||
}
|
||||
}
|
@ -15,43 +15,64 @@ import play.mvc.Result;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import static play.mvc.Results.ok;
|
||||
import static play.mvc.Results.unauthorized;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
|
||||
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public abstract class PetApiControllerImpInterface {
|
||||
@Inject private SecurityAPIUtils securityAPIUtils;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public Result addPetHttp(Http.Request request, Pet body) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
addPet(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
public abstract void addPet(Http.Request request, Pet body) throws Exception;
|
||||
|
||||
public Result deletePetHttp(Http.Request request, Long petId, String apiKey) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
deletePet(request, petId, apiKey);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
public abstract void deletePet(Http.Request request, Long petId, String apiKey) throws Exception;
|
||||
|
||||
public Result findPetsByStatusHttp(Http.Request request, List<String> status) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
List<Pet> obj = findPetsByStatus(request, status);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
public abstract List<Pet> findPetsByStatus(Http.Request request, List<String> status) throws Exception;
|
||||
|
||||
public Result findPetsByTagsHttp(Http.Request request, List<String> tags) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
List<Pet> obj = findPetsByTags(request, tags);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -59,33 +80,47 @@ return ok(result);
|
||||
|
||||
public Result getPetByIdHttp(Http.Request request, Long petId) throws Exception {
|
||||
Pet obj = getPetById(request, petId);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
public abstract Pet getPetById(Http.Request request, Long petId) throws Exception;
|
||||
|
||||
public Result updatePetHttp(Http.Request request, Pet body) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
updatePet(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
public abstract void updatePet(Http.Request request, Pet body) throws Exception;
|
||||
|
||||
public Result updatePetWithFormHttp(Http.Request request, Long petId, String name, String status) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
updatePetWithForm(request, petId, name, status);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
public abstract void updatePetWithForm(Http.Request request, Long petId, String name, String status) throws Exception;
|
||||
|
||||
public Result uploadFileHttp(Http.Request request, Long petId, String additionalMetadata, Http.MultipartFormData.FilePart<TemporaryFile> file) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
ModelApiResponse obj = uploadFile(request, petId, additionalMetadata, file);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
|
@ -14,17 +14,20 @@ import play.mvc.Result;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import static play.mvc.Results.ok;
|
||||
import static play.mvc.Results.unauthorized;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
|
||||
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public abstract class StoreApiControllerImpInterface {
|
||||
@Inject private SecurityAPIUtils securityAPIUtils;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public Result deleteOrderHttp(Http.Request request, String orderId) throws Exception {
|
||||
deleteOrder(request, orderId);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -32,8 +35,9 @@ return ok();
|
||||
|
||||
public Result getInventoryHttp(Http.Request request) throws Exception {
|
||||
Map<String, Integer> obj = getInventory(request);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -41,8 +45,9 @@ return ok(result);
|
||||
|
||||
public Result getOrderByIdHttp(Http.Request request, Long orderId) throws Exception {
|
||||
Order obj = getOrderById(request, orderId);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -50,8 +55,9 @@ return ok(result);
|
||||
|
||||
public Result placeOrderHttp(Http.Request request, Order body) throws Exception {
|
||||
Order obj = placeOrder(request, body);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
|
@ -15,17 +15,20 @@ import play.mvc.Result;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import static play.mvc.Results.ok;
|
||||
import static play.mvc.Results.unauthorized;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
|
||||
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public abstract class UserApiControllerImpInterface {
|
||||
@Inject private SecurityAPIUtils securityAPIUtils;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public Result createUserHttp(Http.Request request, User body) throws Exception {
|
||||
createUser(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -33,7 +36,7 @@ return ok();
|
||||
|
||||
public Result createUsersWithArrayInputHttp(Http.Request request, List<User> body) throws Exception {
|
||||
createUsersWithArrayInput(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -41,7 +44,7 @@ return ok();
|
||||
|
||||
public Result createUsersWithListInputHttp(Http.Request request, List<User> body) throws Exception {
|
||||
createUsersWithListInput(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -49,7 +52,7 @@ return ok();
|
||||
|
||||
public Result deleteUserHttp(Http.Request request, String username) throws Exception {
|
||||
deleteUser(request, username);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -57,8 +60,9 @@ return ok();
|
||||
|
||||
public Result getUserByNameHttp(Http.Request request, String username) throws Exception {
|
||||
User obj = getUserByName(request, username);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -66,8 +70,9 @@ return ok(result);
|
||||
|
||||
public Result loginUserHttp(Http.Request request, String username, String password) throws Exception {
|
||||
String obj = loginUser(request, username, password);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -75,7 +80,7 @@ return ok(result);
|
||||
|
||||
public Result logoutUserHttp(Http.Request request) throws Exception {
|
||||
logoutUser(request);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -83,7 +88,7 @@ return ok();
|
||||
|
||||
public Result updateUserHttp(Http.Request request, String username, User body) throws Exception {
|
||||
updateUser(request, username, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,165 @@
|
||||
package openapitools;
|
||||
|
||||
import com.auth0.jwk.Jwk;
|
||||
import com.auth0.jwk.UrlJwkProvider;
|
||||
import com.auth0.jwt.JWT;
|
||||
import com.auth0.jwt.JWTVerifier;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import com.typesafe.config.Config;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import play.mvc.Http;
|
||||
|
||||
import java.net.URL;
|
||||
import java.security.PublicKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Singleton
|
||||
public class SecurityAPIUtils {
|
||||
private final String bearerPrefix = "Bearer ";
|
||||
private final ObjectMapper mapper;
|
||||
|
||||
private boolean useOnlineValidation = false;
|
||||
|
||||
// Online validation
|
||||
private HashMap<String, String> tokenIntrospectEndpoints = new HashMap<>();
|
||||
private final String clientId;
|
||||
private final String clientSecret;
|
||||
|
||||
// Offline validation
|
||||
private HashMap<String, String> jwksEndpoints = new HashMap<>();
|
||||
private String tokenKeyId = "";
|
||||
private JWTVerifier tokenVerifier; //Reusable verifier instance until tokenKeyId changes.
|
||||
|
||||
@Inject
|
||||
SecurityAPIUtils(Config configuration) {
|
||||
mapper = new ObjectMapper();
|
||||
|
||||
clientId = configuration.hasPath("oauth.clientId") ? configuration.getString("oauth.clientId") : "";
|
||||
clientSecret = configuration.hasPath("oauth.clientSecret") ? configuration.getString("oauth.clientSecret") : "";
|
||||
|
||||
tokenIntrospectEndpoints.put("petstore_auth", "");
|
||||
|
||||
jwksEndpoints.put("petstore_auth", "");
|
||||
}
|
||||
|
||||
private boolean isRequestTokenValidByOnlineCheck(Http.Request request, String securityMethodName) {
|
||||
try {
|
||||
Optional<String> authToken = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
|
||||
if (authToken.isPresent()) {
|
||||
String tokenWithoutBearerPrefix = authToken.get().substring(bearerPrefix.length());
|
||||
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
HttpClient httpClient = builder.build();
|
||||
HttpPost httppost = new HttpPost(this.tokenIntrospectEndpoints.get(securityMethodName));
|
||||
|
||||
List<NameValuePair> params = new ArrayList<>();
|
||||
params.add(new BasicNameValuePair("token", tokenWithoutBearerPrefix));
|
||||
params.add(new BasicNameValuePair("client_id", clientId));
|
||||
params.add(new BasicNameValuePair("client_secret", clientSecret));
|
||||
httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
|
||||
|
||||
HttpResponse response = httpClient.execute(httppost);
|
||||
String responseJsonString = EntityUtils.toString(response.getEntity());
|
||||
HashMap responseJsonObject = mapper.readValue(responseJsonString, HashMap.class);
|
||||
|
||||
return response.getStatusLine().getStatusCode() == HttpStatus.SC_OK && (boolean) responseJsonObject.get("active");
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isRequestTokenValidByOfflineCheck(Http.Request request, String securityMethodName) {
|
||||
try {
|
||||
Optional<String> authHeader = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
|
||||
if (authHeader.isPresent()) {
|
||||
String bearerToken = authHeader.get().substring(bearerPrefix.length());
|
||||
return isTokenValidByOfflineCheck(bearerToken, securityMethodName);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isTokenValidByOfflineCheck(String bearerToken, String securityMethodName) {
|
||||
try {
|
||||
DecodedJWT jwt = JWT.decode(bearerToken);
|
||||
String issuer = jwt.getIssuer();
|
||||
String keyId = jwt.getKeyId();
|
||||
if (!tokenKeyId.equals(keyId)) {
|
||||
if (securityMethodName == null) {
|
||||
securityMethodName = jwksEndpoints.keySet().stream().findFirst().get();
|
||||
}
|
||||
|
||||
Jwk jwk = new UrlJwkProvider(new URL(this.jwksEndpoints.get(securityMethodName))).get(keyId);
|
||||
final PublicKey publicKey = jwk.getPublicKey();
|
||||
|
||||
if (!(publicKey instanceof RSAPublicKey)) {
|
||||
throw new IllegalArgumentException(String.format("Key with ID %s was found in JWKS but is not a RSA-key.", keyId));
|
||||
}
|
||||
|
||||
Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) publicKey, null);
|
||||
tokenVerifier = JWT.require(algorithm)
|
||||
.withIssuer(issuer)
|
||||
.build();
|
||||
tokenKeyId = keyId;
|
||||
}
|
||||
|
||||
DecodedJWT verifiedJWT = tokenVerifier.verify(bearerToken);
|
||||
|
||||
return true;
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public String getOAuthUserIdFromRequestToken(Http.Request requestWithPreviouslyVerifiedToken) {
|
||||
try {
|
||||
Optional<String> authHeader = requestWithPreviouslyVerifiedToken.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
if (authHeader.isPresent()) {
|
||||
String bearerToken = authHeader.get().substring(bearerPrefix.length());
|
||||
return getOAuthUserIdFromToken(bearerToken);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getOAuthUserIdFromToken(String bearerToken) {
|
||||
try {
|
||||
DecodedJWT jwt = JWT.decode(bearerToken);
|
||||
return jwt.getSubject();
|
||||
} catch (Exception exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRequestTokenValid(Http.Request request, String securityMethodName) {
|
||||
return useOnlineValidation ? isRequestTokenValidByOnlineCheck(request, securityMethodName) : isRequestTokenValidByOfflineCheck(request, securityMethodName);
|
||||
}
|
||||
}
|
@ -8,3 +8,6 @@ scalaVersion := "2.12.6"
|
||||
|
||||
libraryDependencies += "org.webjars" % "swagger-ui" % "3.32.5"
|
||||
libraryDependencies += guice
|
||||
libraryDependencies += "com.auth0" % "java-jwt" % "3.18.1"
|
||||
libraryDependencies += "com.auth0" % "jwks-rsa" % "0.19.0"
|
||||
libraryDependencies += "org.apache.httpcomponents" % "httpclient" % "4.5.6"
|
||||
|
@ -19,6 +19,7 @@ app/controllers/UserApiControllerImp.java
|
||||
app/controllers/UserApiControllerImpInterface.java
|
||||
app/openapitools/ApiCall.java
|
||||
app/openapitools/OpenAPIUtils.java
|
||||
app/openapitools/SecurityAPIUtils.java
|
||||
build.sbt
|
||||
conf/application.conf
|
||||
conf/logback.xml
|
||||
|
@ -1,6 +1,7 @@
|
||||
import com.google.inject.AbstractModule;
|
||||
|
||||
import controllers.*;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
|
||||
public class Module extends AbstractModule {
|
||||
|
||||
@ -9,5 +10,6 @@ public class Module extends AbstractModule {
|
||||
bind(PetApiControllerImpInterface.class).to(PetApiControllerImp.class);
|
||||
bind(StoreApiControllerImpInterface.class).to(StoreApiControllerImp.class);
|
||||
bind(UserApiControllerImpInterface.class).to(UserApiControllerImp.class);
|
||||
bind(SecurityAPIUtils.class);
|
||||
}
|
||||
}
|
@ -15,7 +15,9 @@ import play.mvc.Result;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import static play.mvc.Results.ok;
|
||||
import static play.mvc.Results.unauthorized;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
@ -23,47 +25,70 @@ import javax.validation.constraints.*;
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public abstract class PetApiControllerImpInterface {
|
||||
@Inject private Config configuration;
|
||||
@Inject private SecurityAPIUtils securityAPIUtils;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public Result addPetHttp(Http.Request request, Pet body) {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
addPet(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
public abstract void addPet(Http.Request request, Pet body) ;
|
||||
|
||||
public Result deletePetHttp(Http.Request request, Long petId, String apiKey) {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
deletePet(request, petId, apiKey);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
public abstract void deletePet(Http.Request request, Long petId, String apiKey) ;
|
||||
|
||||
public Result findPetsByStatusHttp(Http.Request request, @NotNull List<String> status) {
|
||||
List<Pet> obj = findPetsByStatus(request, status);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
|
||||
List<Pet> obj = findPetsByStatus(request, status);
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
}
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
public abstract List<Pet> findPetsByStatus(Http.Request request, @NotNull List<String> status) ;
|
||||
|
||||
public Result findPetsByTagsHttp(Http.Request request, @NotNull List<String> tags) {
|
||||
List<Pet> obj = findPetsByTags(request, tags);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
|
||||
List<Pet> obj = findPetsByTags(request, tags);
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
}
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -71,39 +96,57 @@ return ok(result);
|
||||
|
||||
public Result getPetByIdHttp(Http.Request request, Long petId) {
|
||||
Pet obj = getPetById(request, petId);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
public abstract Pet getPetById(Http.Request request, Long petId) ;
|
||||
|
||||
public Result updatePetHttp(Http.Request request, Pet body) {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
updatePet(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
public abstract void updatePet(Http.Request request, Pet body) ;
|
||||
|
||||
public Result updatePetWithFormHttp(Http.Request request, Long petId, String name, String status) {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
updatePetWithForm(request, petId, name, status);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
public abstract void updatePetWithForm(Http.Request request, Long petId, String name, String status) ;
|
||||
|
||||
public Result uploadFileHttp(Http.Request request, Long petId, String additionalMetadata, Http.MultipartFormData.FilePart<TemporaryFile> file) {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
ModelApiResponse obj = uploadFile(request, petId, additionalMetadata, file);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,9 @@ import play.mvc.Result;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import static play.mvc.Results.ok;
|
||||
import static play.mvc.Results.unauthorized;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
@ -22,11 +24,12 @@ import javax.validation.constraints.*;
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public abstract class StoreApiControllerImpInterface {
|
||||
@Inject private Config configuration;
|
||||
@Inject private SecurityAPIUtils securityAPIUtils;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public Result deleteOrderHttp(Http.Request request, String orderId) {
|
||||
deleteOrder(request, orderId);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -34,8 +37,9 @@ return ok();
|
||||
|
||||
public Result getInventoryHttp(Http.Request request) {
|
||||
Map<String, Integer> obj = getInventory(request);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -43,11 +47,14 @@ return ok(result);
|
||||
|
||||
public Result getOrderByIdHttp(Http.Request request, @Min(1) @Max(5)Long orderId) {
|
||||
Order obj = getOrderById(request, orderId);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -55,11 +62,14 @@ return ok(result);
|
||||
|
||||
public Result placeOrderHttp(Http.Request request, Order body) {
|
||||
Order obj = placeOrder(request, body);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,9 @@ import play.mvc.Result;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import static play.mvc.Results.ok;
|
||||
import static play.mvc.Results.unauthorized;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
@ -23,11 +25,12 @@ import javax.validation.constraints.*;
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public abstract class UserApiControllerImpInterface {
|
||||
@Inject private Config configuration;
|
||||
@Inject private SecurityAPIUtils securityAPIUtils;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public Result createUserHttp(Http.Request request, User body) {
|
||||
createUser(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -35,7 +38,7 @@ return ok();
|
||||
|
||||
public Result createUsersWithArrayInputHttp(Http.Request request, List<User> body) {
|
||||
createUsersWithArrayInput(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -43,7 +46,7 @@ return ok();
|
||||
|
||||
public Result createUsersWithListInputHttp(Http.Request request, List<User> body) {
|
||||
createUsersWithListInput(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -51,7 +54,7 @@ return ok();
|
||||
|
||||
public Result deleteUserHttp(Http.Request request, String username) {
|
||||
deleteUser(request, username);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -59,11 +62,14 @@ return ok();
|
||||
|
||||
public Result getUserByNameHttp(Http.Request request, String username) {
|
||||
User obj = getUserByName(request, username);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -71,8 +77,9 @@ return ok(result);
|
||||
|
||||
public Result loginUserHttp(Http.Request request, @NotNull String username, @NotNull String password) {
|
||||
String obj = loginUser(request, username, password);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -80,7 +87,7 @@ return ok(result);
|
||||
|
||||
public Result logoutUserHttp(Http.Request request) {
|
||||
logoutUser(request);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -88,7 +95,7 @@ return ok();
|
||||
|
||||
public Result updateUserHttp(Http.Request request, String username, User body) {
|
||||
updateUser(request, username, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,165 @@
|
||||
package openapitools;
|
||||
|
||||
import com.auth0.jwk.Jwk;
|
||||
import com.auth0.jwk.UrlJwkProvider;
|
||||
import com.auth0.jwt.JWT;
|
||||
import com.auth0.jwt.JWTVerifier;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import com.typesafe.config.Config;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import play.mvc.Http;
|
||||
|
||||
import java.net.URL;
|
||||
import java.security.PublicKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Singleton
|
||||
public class SecurityAPIUtils {
|
||||
private final String bearerPrefix = "Bearer ";
|
||||
private final ObjectMapper mapper;
|
||||
|
||||
private boolean useOnlineValidation = false;
|
||||
|
||||
// Online validation
|
||||
private HashMap<String, String> tokenIntrospectEndpoints = new HashMap<>();
|
||||
private final String clientId;
|
||||
private final String clientSecret;
|
||||
|
||||
// Offline validation
|
||||
private HashMap<String, String> jwksEndpoints = new HashMap<>();
|
||||
private String tokenKeyId = "";
|
||||
private JWTVerifier tokenVerifier; //Reusable verifier instance until tokenKeyId changes.
|
||||
|
||||
@Inject
|
||||
SecurityAPIUtils(Config configuration) {
|
||||
mapper = new ObjectMapper();
|
||||
|
||||
clientId = configuration.hasPath("oauth.clientId") ? configuration.getString("oauth.clientId") : "";
|
||||
clientSecret = configuration.hasPath("oauth.clientSecret") ? configuration.getString("oauth.clientSecret") : "";
|
||||
|
||||
tokenIntrospectEndpoints.put("petstore_auth", "");
|
||||
|
||||
jwksEndpoints.put("petstore_auth", "");
|
||||
}
|
||||
|
||||
private boolean isRequestTokenValidByOnlineCheck(Http.Request request, String securityMethodName) {
|
||||
try {
|
||||
Optional<String> authToken = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
|
||||
if (authToken.isPresent()) {
|
||||
String tokenWithoutBearerPrefix = authToken.get().substring(bearerPrefix.length());
|
||||
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
HttpClient httpClient = builder.build();
|
||||
HttpPost httppost = new HttpPost(this.tokenIntrospectEndpoints.get(securityMethodName));
|
||||
|
||||
List<NameValuePair> params = new ArrayList<>();
|
||||
params.add(new BasicNameValuePair("token", tokenWithoutBearerPrefix));
|
||||
params.add(new BasicNameValuePair("client_id", clientId));
|
||||
params.add(new BasicNameValuePair("client_secret", clientSecret));
|
||||
httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
|
||||
|
||||
HttpResponse response = httpClient.execute(httppost);
|
||||
String responseJsonString = EntityUtils.toString(response.getEntity());
|
||||
HashMap responseJsonObject = mapper.readValue(responseJsonString, HashMap.class);
|
||||
|
||||
return response.getStatusLine().getStatusCode() == HttpStatus.SC_OK && (boolean) responseJsonObject.get("active");
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isRequestTokenValidByOfflineCheck(Http.Request request, String securityMethodName) {
|
||||
try {
|
||||
Optional<String> authHeader = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
|
||||
if (authHeader.isPresent()) {
|
||||
String bearerToken = authHeader.get().substring(bearerPrefix.length());
|
||||
return isTokenValidByOfflineCheck(bearerToken, securityMethodName);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isTokenValidByOfflineCheck(String bearerToken, String securityMethodName) {
|
||||
try {
|
||||
DecodedJWT jwt = JWT.decode(bearerToken);
|
||||
String issuer = jwt.getIssuer();
|
||||
String keyId = jwt.getKeyId();
|
||||
if (!tokenKeyId.equals(keyId)) {
|
||||
if (securityMethodName == null) {
|
||||
securityMethodName = jwksEndpoints.keySet().stream().findFirst().get();
|
||||
}
|
||||
|
||||
Jwk jwk = new UrlJwkProvider(new URL(this.jwksEndpoints.get(securityMethodName))).get(keyId);
|
||||
final PublicKey publicKey = jwk.getPublicKey();
|
||||
|
||||
if (!(publicKey instanceof RSAPublicKey)) {
|
||||
throw new IllegalArgumentException(String.format("Key with ID %s was found in JWKS but is not a RSA-key.", keyId));
|
||||
}
|
||||
|
||||
Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) publicKey, null);
|
||||
tokenVerifier = JWT.require(algorithm)
|
||||
.withIssuer(issuer)
|
||||
.build();
|
||||
tokenKeyId = keyId;
|
||||
}
|
||||
|
||||
DecodedJWT verifiedJWT = tokenVerifier.verify(bearerToken);
|
||||
|
||||
return true;
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public String getOAuthUserIdFromRequestToken(Http.Request requestWithPreviouslyVerifiedToken) {
|
||||
try {
|
||||
Optional<String> authHeader = requestWithPreviouslyVerifiedToken.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
if (authHeader.isPresent()) {
|
||||
String bearerToken = authHeader.get().substring(bearerPrefix.length());
|
||||
return getOAuthUserIdFromToken(bearerToken);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getOAuthUserIdFromToken(String bearerToken) {
|
||||
try {
|
||||
DecodedJWT jwt = JWT.decode(bearerToken);
|
||||
return jwt.getSubject();
|
||||
} catch (Exception exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRequestTokenValid(Http.Request request, String securityMethodName) {
|
||||
return useOnlineValidation ? isRequestTokenValidByOnlineCheck(request, securityMethodName) : isRequestTokenValidByOfflineCheck(request, securityMethodName);
|
||||
}
|
||||
}
|
@ -9,3 +9,6 @@ scalaVersion := "2.12.6"
|
||||
libraryDependencies += "org.webjars" % "swagger-ui" % "3.32.5"
|
||||
libraryDependencies += "javax.validation" % "validation-api" % "2.0.1.Final"
|
||||
libraryDependencies += guice
|
||||
libraryDependencies += "com.auth0" % "java-jwt" % "3.18.1"
|
||||
libraryDependencies += "com.auth0" % "jwks-rsa" % "0.19.0"
|
||||
libraryDependencies += "org.apache.httpcomponents" % "httpclient" % "4.5.6"
|
||||
|
@ -16,6 +16,7 @@ app/controllers/UserApiControllerImp.java
|
||||
app/openapitools/ApiCall.java
|
||||
app/openapitools/ErrorHandler.java
|
||||
app/openapitools/OpenAPIUtils.java
|
||||
app/openapitools/SecurityAPIUtils.java
|
||||
build.sbt
|
||||
conf/application.conf
|
||||
conf/logback.xml
|
||||
|
@ -18,6 +18,7 @@ import com.google.inject.Inject;
|
||||
import java.io.File;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
@ -30,12 +31,14 @@ public class PetApiController extends Controller {
|
||||
private final PetApiControllerImp imp;
|
||||
private final ObjectMapper mapper;
|
||||
private final Config configuration;
|
||||
private final SecurityAPIUtils securityAPIUtils;
|
||||
|
||||
@Inject
|
||||
private PetApiController(Config configuration, PetApiControllerImp imp) {
|
||||
private PetApiController(Config configuration, PetApiControllerImp imp, SecurityAPIUtils securityAPIUtils) {
|
||||
this.imp = imp;
|
||||
mapper = new ObjectMapper();
|
||||
this.configuration = configuration;
|
||||
this.securityAPIUtils = securityAPIUtils;
|
||||
}
|
||||
|
||||
@ApiAction
|
||||
@ -50,8 +53,12 @@ public class PetApiController extends Controller {
|
||||
} else {
|
||||
throw new IllegalArgumentException("'body' parameter is required");
|
||||
}
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
imp.addPet(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -64,8 +71,12 @@ return ok();
|
||||
} else {
|
||||
apiKey = null;
|
||||
}
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
imp.deletePet(request, petId, apiKey);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -83,14 +94,21 @@ return ok();
|
||||
status.add(curParam);
|
||||
}
|
||||
}
|
||||
List<Pet> obj = imp.findPetsByStatus(request, status);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
|
||||
List<Pet> obj = imp.findPetsByStatus(request, status);
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
}
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -108,25 +126,35 @@ return ok(result);
|
||||
tags.add(curParam);
|
||||
}
|
||||
}
|
||||
List<Pet> obj = imp.findPetsByTags(request, tags);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
|
||||
List<Pet> obj = imp.findPetsByTags(request, tags);
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
}
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ApiAction
|
||||
public Result getPetById(Http.Request request, Long petId) throws Exception {
|
||||
Pet obj = imp.getPetById(request, petId);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
Pet obj = imp.getPetById(request, petId);
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -142,8 +170,12 @@ return ok(result);
|
||||
} else {
|
||||
throw new IllegalArgumentException("'body' parameter is required");
|
||||
}
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
imp.updatePet(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -163,8 +195,12 @@ return ok();
|
||||
} else {
|
||||
status = null;
|
||||
}
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
imp.updatePetWithForm(request, petId, name, status);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -179,12 +215,19 @@ return ok();
|
||||
}
|
||||
Http.MultipartFormData<TemporaryFile> bodyfile = request.body().asMultipartFormData();
|
||||
Http.MultipartFormData.FilePart<TemporaryFile> file = bodyfile.getFile("file");
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
ModelApiResponse obj = imp.uploadFile(request, petId, additionalMetadata, file);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@ import com.google.inject.Inject;
|
||||
import java.io.File;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
@ -29,37 +30,43 @@ public class StoreApiController extends Controller {
|
||||
private final StoreApiControllerImp imp;
|
||||
private final ObjectMapper mapper;
|
||||
private final Config configuration;
|
||||
private final SecurityAPIUtils securityAPIUtils;
|
||||
|
||||
@Inject
|
||||
private StoreApiController(Config configuration, StoreApiControllerImp imp) {
|
||||
private StoreApiController(Config configuration, StoreApiControllerImp imp, SecurityAPIUtils securityAPIUtils) {
|
||||
this.imp = imp;
|
||||
mapper = new ObjectMapper();
|
||||
this.configuration = configuration;
|
||||
this.securityAPIUtils = securityAPIUtils;
|
||||
}
|
||||
|
||||
@ApiAction
|
||||
public Result deleteOrder(Http.Request request, String orderId) throws Exception {
|
||||
imp.deleteOrder(request, orderId);
|
||||
return ok();
|
||||
imp.deleteOrder(request, orderId);
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ApiAction
|
||||
public Result getInventory(Http.Request request) throws Exception {
|
||||
Map<String, Integer> obj = imp.getInventory(request);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
Map<String, Integer> obj = imp.getInventory(request);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ApiAction
|
||||
public Result getOrderById(Http.Request request, @Min(1) @Max(5)Long orderId) throws Exception {
|
||||
Order obj = imp.getOrderById(request, orderId);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
Order obj = imp.getOrderById(request, orderId);
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -75,12 +82,15 @@ return ok(result);
|
||||
} else {
|
||||
throw new IllegalArgumentException("'body' parameter is required");
|
||||
}
|
||||
Order obj = imp.placeOrder(request, body);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
Order obj = imp.placeOrder(request, body);
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ import com.google.inject.Inject;
|
||||
import java.io.File;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
@ -30,12 +31,14 @@ public class UserApiController extends Controller {
|
||||
private final UserApiControllerImp imp;
|
||||
private final ObjectMapper mapper;
|
||||
private final Config configuration;
|
||||
private final SecurityAPIUtils securityAPIUtils;
|
||||
|
||||
@Inject
|
||||
private UserApiController(Config configuration, UserApiControllerImp imp) {
|
||||
private UserApiController(Config configuration, UserApiControllerImp imp, SecurityAPIUtils securityAPIUtils) {
|
||||
this.imp = imp;
|
||||
mapper = new ObjectMapper();
|
||||
this.configuration = configuration;
|
||||
this.securityAPIUtils = securityAPIUtils;
|
||||
}
|
||||
|
||||
@ApiAction
|
||||
@ -50,8 +53,8 @@ public class UserApiController extends Controller {
|
||||
} else {
|
||||
throw new IllegalArgumentException("'body' parameter is required");
|
||||
}
|
||||
imp.createUser(request, body);
|
||||
return ok();
|
||||
imp.createUser(request, body);
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -69,8 +72,8 @@ return ok();
|
||||
} else {
|
||||
throw new IllegalArgumentException("'body' parameter is required");
|
||||
}
|
||||
imp.createUsersWithArrayInput(request, body);
|
||||
return ok();
|
||||
imp.createUsersWithArrayInput(request, body);
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -88,26 +91,29 @@ return ok();
|
||||
} else {
|
||||
throw new IllegalArgumentException("'body' parameter is required");
|
||||
}
|
||||
imp.createUsersWithListInput(request, body);
|
||||
return ok();
|
||||
imp.createUsersWithListInput(request, body);
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ApiAction
|
||||
public Result deleteUser(Http.Request request, String username) throws Exception {
|
||||
imp.deleteUser(request, username);
|
||||
return ok();
|
||||
imp.deleteUser(request, username);
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ApiAction
|
||||
public Result getUserByName(Http.Request request, String username) throws Exception {
|
||||
User obj = imp.getUserByName(request, username);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
User obj = imp.getUserByName(request, username);
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -127,16 +133,17 @@ return ok(result);
|
||||
} else {
|
||||
throw new IllegalArgumentException("'password' parameter is required");
|
||||
}
|
||||
String obj = imp.loginUser(request, username, password);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
String obj = imp.loginUser(request, username, password);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ApiAction
|
||||
public Result logoutUser(Http.Request request) throws Exception {
|
||||
imp.logoutUser(request);
|
||||
return ok();
|
||||
imp.logoutUser(request);
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -152,8 +159,8 @@ return ok();
|
||||
} else {
|
||||
throw new IllegalArgumentException("'body' parameter is required");
|
||||
}
|
||||
imp.updateUser(request, username, body);
|
||||
return ok();
|
||||
imp.updateUser(request, username, body);
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,165 @@
|
||||
package openapitools;
|
||||
|
||||
import com.auth0.jwk.Jwk;
|
||||
import com.auth0.jwk.UrlJwkProvider;
|
||||
import com.auth0.jwt.JWT;
|
||||
import com.auth0.jwt.JWTVerifier;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import com.typesafe.config.Config;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import play.mvc.Http;
|
||||
|
||||
import java.net.URL;
|
||||
import java.security.PublicKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Singleton
|
||||
public class SecurityAPIUtils {
|
||||
private final String bearerPrefix = "Bearer ";
|
||||
private final ObjectMapper mapper;
|
||||
|
||||
private boolean useOnlineValidation = false;
|
||||
|
||||
// Online validation
|
||||
private HashMap<String, String> tokenIntrospectEndpoints = new HashMap<>();
|
||||
private final String clientId;
|
||||
private final String clientSecret;
|
||||
|
||||
// Offline validation
|
||||
private HashMap<String, String> jwksEndpoints = new HashMap<>();
|
||||
private String tokenKeyId = "";
|
||||
private JWTVerifier tokenVerifier; //Reusable verifier instance until tokenKeyId changes.
|
||||
|
||||
@Inject
|
||||
SecurityAPIUtils(Config configuration) {
|
||||
mapper = new ObjectMapper();
|
||||
|
||||
clientId = configuration.hasPath("oauth.clientId") ? configuration.getString("oauth.clientId") : "";
|
||||
clientSecret = configuration.hasPath("oauth.clientSecret") ? configuration.getString("oauth.clientSecret") : "";
|
||||
|
||||
tokenIntrospectEndpoints.put("petstore_auth", "");
|
||||
|
||||
jwksEndpoints.put("petstore_auth", "");
|
||||
}
|
||||
|
||||
private boolean isRequestTokenValidByOnlineCheck(Http.Request request, String securityMethodName) {
|
||||
try {
|
||||
Optional<String> authToken = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
|
||||
if (authToken.isPresent()) {
|
||||
String tokenWithoutBearerPrefix = authToken.get().substring(bearerPrefix.length());
|
||||
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
HttpClient httpClient = builder.build();
|
||||
HttpPost httppost = new HttpPost(this.tokenIntrospectEndpoints.get(securityMethodName));
|
||||
|
||||
List<NameValuePair> params = new ArrayList<>();
|
||||
params.add(new BasicNameValuePair("token", tokenWithoutBearerPrefix));
|
||||
params.add(new BasicNameValuePair("client_id", clientId));
|
||||
params.add(new BasicNameValuePair("client_secret", clientSecret));
|
||||
httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
|
||||
|
||||
HttpResponse response = httpClient.execute(httppost);
|
||||
String responseJsonString = EntityUtils.toString(response.getEntity());
|
||||
HashMap responseJsonObject = mapper.readValue(responseJsonString, HashMap.class);
|
||||
|
||||
return response.getStatusLine().getStatusCode() == HttpStatus.SC_OK && (boolean) responseJsonObject.get("active");
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isRequestTokenValidByOfflineCheck(Http.Request request, String securityMethodName) {
|
||||
try {
|
||||
Optional<String> authHeader = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
|
||||
if (authHeader.isPresent()) {
|
||||
String bearerToken = authHeader.get().substring(bearerPrefix.length());
|
||||
return isTokenValidByOfflineCheck(bearerToken, securityMethodName);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isTokenValidByOfflineCheck(String bearerToken, String securityMethodName) {
|
||||
try {
|
||||
DecodedJWT jwt = JWT.decode(bearerToken);
|
||||
String issuer = jwt.getIssuer();
|
||||
String keyId = jwt.getKeyId();
|
||||
if (!tokenKeyId.equals(keyId)) {
|
||||
if (securityMethodName == null) {
|
||||
securityMethodName = jwksEndpoints.keySet().stream().findFirst().get();
|
||||
}
|
||||
|
||||
Jwk jwk = new UrlJwkProvider(new URL(this.jwksEndpoints.get(securityMethodName))).get(keyId);
|
||||
final PublicKey publicKey = jwk.getPublicKey();
|
||||
|
||||
if (!(publicKey instanceof RSAPublicKey)) {
|
||||
throw new IllegalArgumentException(String.format("Key with ID %s was found in JWKS but is not a RSA-key.", keyId));
|
||||
}
|
||||
|
||||
Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) publicKey, null);
|
||||
tokenVerifier = JWT.require(algorithm)
|
||||
.withIssuer(issuer)
|
||||
.build();
|
||||
tokenKeyId = keyId;
|
||||
}
|
||||
|
||||
DecodedJWT verifiedJWT = tokenVerifier.verify(bearerToken);
|
||||
|
||||
return true;
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public String getOAuthUserIdFromRequestToken(Http.Request requestWithPreviouslyVerifiedToken) {
|
||||
try {
|
||||
Optional<String> authHeader = requestWithPreviouslyVerifiedToken.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
if (authHeader.isPresent()) {
|
||||
String bearerToken = authHeader.get().substring(bearerPrefix.length());
|
||||
return getOAuthUserIdFromToken(bearerToken);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getOAuthUserIdFromToken(String bearerToken) {
|
||||
try {
|
||||
DecodedJWT jwt = JWT.decode(bearerToken);
|
||||
return jwt.getSubject();
|
||||
} catch (Exception exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRequestTokenValid(Http.Request request, String securityMethodName) {
|
||||
return useOnlineValidation ? isRequestTokenValidByOnlineCheck(request, securityMethodName) : isRequestTokenValidByOfflineCheck(request, securityMethodName);
|
||||
}
|
||||
}
|
@ -9,3 +9,6 @@ scalaVersion := "2.12.6"
|
||||
libraryDependencies += "org.webjars" % "swagger-ui" % "3.32.5"
|
||||
libraryDependencies += "javax.validation" % "validation-api" % "2.0.1.Final"
|
||||
libraryDependencies += guice
|
||||
libraryDependencies += "com.auth0" % "java-jwt" % "3.18.1"
|
||||
libraryDependencies += "com.auth0" % "jwks-rsa" % "0.19.0"
|
||||
libraryDependencies += "org.apache.httpcomponents" % "httpclient" % "4.5.6"
|
||||
|
@ -20,6 +20,7 @@ app/controllers/UserApiControllerImpInterface.java
|
||||
app/openapitools/ApiCall.java
|
||||
app/openapitools/ErrorHandler.java
|
||||
app/openapitools/OpenAPIUtils.java
|
||||
app/openapitools/SecurityAPIUtils.java
|
||||
build.sbt
|
||||
conf/application.conf
|
||||
conf/logback.xml
|
||||
|
@ -1,6 +1,7 @@
|
||||
import com.google.inject.AbstractModule;
|
||||
|
||||
import controllers.*;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
|
||||
public class Module extends AbstractModule {
|
||||
|
||||
@ -9,5 +10,6 @@ public class Module extends AbstractModule {
|
||||
bind(PetApiControllerImpInterface.class).to(PetApiControllerImp.class);
|
||||
bind(StoreApiControllerImpInterface.class).to(StoreApiControllerImp.class);
|
||||
bind(UserApiControllerImpInterface.class).to(UserApiControllerImp.class);
|
||||
bind(SecurityAPIUtils.class);
|
||||
}
|
||||
}
|
@ -15,7 +15,9 @@ import play.mvc.Result;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import static play.mvc.Results.ok;
|
||||
import static play.mvc.Results.unauthorized;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
@ -23,47 +25,70 @@ import javax.validation.constraints.*;
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public abstract class PetApiControllerImpInterface {
|
||||
@Inject private Config configuration;
|
||||
@Inject private SecurityAPIUtils securityAPIUtils;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public Result addPetHttp(Http.Request request, Pet body) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
addPet(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
public abstract void addPet(Http.Request request, Pet body) throws Exception;
|
||||
|
||||
public Result deletePetHttp(Http.Request request, Long petId, String apiKey) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
deletePet(request, petId, apiKey);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
public abstract void deletePet(Http.Request request, Long petId, String apiKey) throws Exception;
|
||||
|
||||
public Result findPetsByStatusHttp(Http.Request request, @NotNull List<String> status) throws Exception {
|
||||
List<Pet> obj = findPetsByStatus(request, status);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
|
||||
List<Pet> obj = findPetsByStatus(request, status);
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
}
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
public abstract List<Pet> findPetsByStatus(Http.Request request, @NotNull List<String> status) throws Exception;
|
||||
|
||||
public Result findPetsByTagsHttp(Http.Request request, @NotNull List<String> tags) throws Exception {
|
||||
List<Pet> obj = findPetsByTags(request, tags);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
|
||||
List<Pet> obj = findPetsByTags(request, tags);
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
}
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -71,39 +96,57 @@ return ok(result);
|
||||
|
||||
public Result getPetByIdHttp(Http.Request request, Long petId) throws Exception {
|
||||
Pet obj = getPetById(request, petId);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
public abstract Pet getPetById(Http.Request request, Long petId) throws Exception;
|
||||
|
||||
public Result updatePetHttp(Http.Request request, Pet body) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
updatePet(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
public abstract void updatePet(Http.Request request, Pet body) throws Exception;
|
||||
|
||||
public Result updatePetWithFormHttp(Http.Request request, Long petId, String name, String status) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
updatePetWithForm(request, petId, name, status);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
public abstract void updatePetWithForm(Http.Request request, Long petId, String name, String status) throws Exception;
|
||||
|
||||
public Result uploadFileHttp(Http.Request request, Long petId, String additionalMetadata, Http.MultipartFormData.FilePart<TemporaryFile> file) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
ModelApiResponse obj = uploadFile(request, petId, additionalMetadata, file);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,9 @@ import play.mvc.Result;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import static play.mvc.Results.ok;
|
||||
import static play.mvc.Results.unauthorized;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
@ -22,11 +24,12 @@ import javax.validation.constraints.*;
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public abstract class StoreApiControllerImpInterface {
|
||||
@Inject private Config configuration;
|
||||
@Inject private SecurityAPIUtils securityAPIUtils;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public Result deleteOrderHttp(Http.Request request, String orderId) throws Exception {
|
||||
deleteOrder(request, orderId);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -34,8 +37,9 @@ return ok();
|
||||
|
||||
public Result getInventoryHttp(Http.Request request) throws Exception {
|
||||
Map<String, Integer> obj = getInventory(request);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -43,11 +47,14 @@ return ok(result);
|
||||
|
||||
public Result getOrderByIdHttp(Http.Request request, @Min(1) @Max(5)Long orderId) throws Exception {
|
||||
Order obj = getOrderById(request, orderId);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -55,11 +62,14 @@ return ok(result);
|
||||
|
||||
public Result placeOrderHttp(Http.Request request, Order body) throws Exception {
|
||||
Order obj = placeOrder(request, body);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,9 @@ import play.mvc.Result;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import static play.mvc.Results.ok;
|
||||
import static play.mvc.Results.unauthorized;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
@ -23,11 +25,12 @@ import javax.validation.constraints.*;
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public abstract class UserApiControllerImpInterface {
|
||||
@Inject private Config configuration;
|
||||
@Inject private SecurityAPIUtils securityAPIUtils;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public Result createUserHttp(Http.Request request, User body) throws Exception {
|
||||
createUser(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -35,7 +38,7 @@ return ok();
|
||||
|
||||
public Result createUsersWithArrayInputHttp(Http.Request request, List<User> body) throws Exception {
|
||||
createUsersWithArrayInput(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -43,7 +46,7 @@ return ok();
|
||||
|
||||
public Result createUsersWithListInputHttp(Http.Request request, List<User> body) throws Exception {
|
||||
createUsersWithListInput(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -51,7 +54,7 @@ return ok();
|
||||
|
||||
public Result deleteUserHttp(Http.Request request, String username) throws Exception {
|
||||
deleteUser(request, username);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -59,11 +62,14 @@ return ok();
|
||||
|
||||
public Result getUserByNameHttp(Http.Request request, String username) throws Exception {
|
||||
User obj = getUserByName(request, username);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -71,8 +77,9 @@ return ok(result);
|
||||
|
||||
public Result loginUserHttp(Http.Request request, @NotNull String username, @NotNull String password) throws Exception {
|
||||
String obj = loginUser(request, username, password);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -80,7 +87,7 @@ return ok(result);
|
||||
|
||||
public Result logoutUserHttp(Http.Request request) throws Exception {
|
||||
logoutUser(request);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -88,7 +95,7 @@ return ok();
|
||||
|
||||
public Result updateUserHttp(Http.Request request, String username, User body) throws Exception {
|
||||
updateUser(request, username, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,165 @@
|
||||
package openapitools;
|
||||
|
||||
import com.auth0.jwk.Jwk;
|
||||
import com.auth0.jwk.UrlJwkProvider;
|
||||
import com.auth0.jwt.JWT;
|
||||
import com.auth0.jwt.JWTVerifier;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import com.typesafe.config.Config;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import play.mvc.Http;
|
||||
|
||||
import java.net.URL;
|
||||
import java.security.PublicKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Singleton
|
||||
public class SecurityAPIUtils {
|
||||
private final String bearerPrefix = "Bearer ";
|
||||
private final ObjectMapper mapper;
|
||||
|
||||
private boolean useOnlineValidation = false;
|
||||
|
||||
// Online validation
|
||||
private HashMap<String, String> tokenIntrospectEndpoints = new HashMap<>();
|
||||
private final String clientId;
|
||||
private final String clientSecret;
|
||||
|
||||
// Offline validation
|
||||
private HashMap<String, String> jwksEndpoints = new HashMap<>();
|
||||
private String tokenKeyId = "";
|
||||
private JWTVerifier tokenVerifier; //Reusable verifier instance until tokenKeyId changes.
|
||||
|
||||
@Inject
|
||||
SecurityAPIUtils(Config configuration) {
|
||||
mapper = new ObjectMapper();
|
||||
|
||||
clientId = configuration.hasPath("oauth.clientId") ? configuration.getString("oauth.clientId") : "";
|
||||
clientSecret = configuration.hasPath("oauth.clientSecret") ? configuration.getString("oauth.clientSecret") : "";
|
||||
|
||||
tokenIntrospectEndpoints.put("petstore_auth", "");
|
||||
|
||||
jwksEndpoints.put("petstore_auth", "");
|
||||
}
|
||||
|
||||
private boolean isRequestTokenValidByOnlineCheck(Http.Request request, String securityMethodName) {
|
||||
try {
|
||||
Optional<String> authToken = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
|
||||
if (authToken.isPresent()) {
|
||||
String tokenWithoutBearerPrefix = authToken.get().substring(bearerPrefix.length());
|
||||
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
HttpClient httpClient = builder.build();
|
||||
HttpPost httppost = new HttpPost(this.tokenIntrospectEndpoints.get(securityMethodName));
|
||||
|
||||
List<NameValuePair> params = new ArrayList<>();
|
||||
params.add(new BasicNameValuePair("token", tokenWithoutBearerPrefix));
|
||||
params.add(new BasicNameValuePair("client_id", clientId));
|
||||
params.add(new BasicNameValuePair("client_secret", clientSecret));
|
||||
httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
|
||||
|
||||
HttpResponse response = httpClient.execute(httppost);
|
||||
String responseJsonString = EntityUtils.toString(response.getEntity());
|
||||
HashMap responseJsonObject = mapper.readValue(responseJsonString, HashMap.class);
|
||||
|
||||
return response.getStatusLine().getStatusCode() == HttpStatus.SC_OK && (boolean) responseJsonObject.get("active");
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isRequestTokenValidByOfflineCheck(Http.Request request, String securityMethodName) {
|
||||
try {
|
||||
Optional<String> authHeader = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
|
||||
if (authHeader.isPresent()) {
|
||||
String bearerToken = authHeader.get().substring(bearerPrefix.length());
|
||||
return isTokenValidByOfflineCheck(bearerToken, securityMethodName);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isTokenValidByOfflineCheck(String bearerToken, String securityMethodName) {
|
||||
try {
|
||||
DecodedJWT jwt = JWT.decode(bearerToken);
|
||||
String issuer = jwt.getIssuer();
|
||||
String keyId = jwt.getKeyId();
|
||||
if (!tokenKeyId.equals(keyId)) {
|
||||
if (securityMethodName == null) {
|
||||
securityMethodName = jwksEndpoints.keySet().stream().findFirst().get();
|
||||
}
|
||||
|
||||
Jwk jwk = new UrlJwkProvider(new URL(this.jwksEndpoints.get(securityMethodName))).get(keyId);
|
||||
final PublicKey publicKey = jwk.getPublicKey();
|
||||
|
||||
if (!(publicKey instanceof RSAPublicKey)) {
|
||||
throw new IllegalArgumentException(String.format("Key with ID %s was found in JWKS but is not a RSA-key.", keyId));
|
||||
}
|
||||
|
||||
Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) publicKey, null);
|
||||
tokenVerifier = JWT.require(algorithm)
|
||||
.withIssuer(issuer)
|
||||
.build();
|
||||
tokenKeyId = keyId;
|
||||
}
|
||||
|
||||
DecodedJWT verifiedJWT = tokenVerifier.verify(bearerToken);
|
||||
|
||||
return true;
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public String getOAuthUserIdFromRequestToken(Http.Request requestWithPreviouslyVerifiedToken) {
|
||||
try {
|
||||
Optional<String> authHeader = requestWithPreviouslyVerifiedToken.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
if (authHeader.isPresent()) {
|
||||
String bearerToken = authHeader.get().substring(bearerPrefix.length());
|
||||
return getOAuthUserIdFromToken(bearerToken);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getOAuthUserIdFromToken(String bearerToken) {
|
||||
try {
|
||||
DecodedJWT jwt = JWT.decode(bearerToken);
|
||||
return jwt.getSubject();
|
||||
} catch (Exception exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRequestTokenValid(Http.Request request, String securityMethodName) {
|
||||
return useOnlineValidation ? isRequestTokenValidByOnlineCheck(request, securityMethodName) : isRequestTokenValidByOfflineCheck(request, securityMethodName);
|
||||
}
|
||||
}
|
@ -9,3 +9,6 @@ scalaVersion := "2.12.6"
|
||||
libraryDependencies += "org.webjars" % "swagger-ui" % "3.32.5"
|
||||
libraryDependencies += "javax.validation" % "validation-api" % "2.0.1.Final"
|
||||
libraryDependencies += guice
|
||||
libraryDependencies += "com.auth0" % "java-jwt" % "3.18.1"
|
||||
libraryDependencies += "com.auth0" % "jwks-rsa" % "0.19.0"
|
||||
libraryDependencies += "org.apache.httpcomponents" % "httpclient" % "4.5.6"
|
||||
|
@ -19,6 +19,7 @@ app/controllers/UserApiControllerImpInterface.java
|
||||
app/openapitools/ApiCall.java
|
||||
app/openapitools/ErrorHandler.java
|
||||
app/openapitools/OpenAPIUtils.java
|
||||
app/openapitools/SecurityAPIUtils.java
|
||||
build.sbt
|
||||
conf/application.conf
|
||||
conf/logback.xml
|
||||
|
@ -1,6 +1,7 @@
|
||||
import com.google.inject.AbstractModule;
|
||||
|
||||
import controllers.*;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
|
||||
public class Module extends AbstractModule {
|
||||
|
||||
@ -9,5 +10,6 @@ public class Module extends AbstractModule {
|
||||
bind(PetApiControllerImpInterface.class).to(PetApiControllerImp.class);
|
||||
bind(StoreApiControllerImpInterface.class).to(StoreApiControllerImp.class);
|
||||
bind(UserApiControllerImpInterface.class).to(UserApiControllerImp.class);
|
||||
bind(SecurityAPIUtils.class);
|
||||
}
|
||||
}
|
@ -15,7 +15,9 @@ import play.mvc.Result;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import static play.mvc.Results.ok;
|
||||
import static play.mvc.Results.unauthorized;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
@ -23,47 +25,70 @@ import javax.validation.constraints.*;
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public abstract class PetApiControllerImpInterface {
|
||||
@Inject private Config configuration;
|
||||
@Inject private SecurityAPIUtils securityAPIUtils;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public Result addPetHttp(Http.Request request, Pet body) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
addPet(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
public abstract void addPet(Http.Request request, Pet body) throws Exception;
|
||||
|
||||
public Result deletePetHttp(Http.Request request, Long petId, String apiKey) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
deletePet(request, petId, apiKey);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
public abstract void deletePet(Http.Request request, Long petId, String apiKey) throws Exception;
|
||||
|
||||
public Result findPetsByStatusHttp(Http.Request request, @NotNull List<String> status) throws Exception {
|
||||
List<Pet> obj = findPetsByStatus(request, status);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
|
||||
List<Pet> obj = findPetsByStatus(request, status);
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
}
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
public abstract List<Pet> findPetsByStatus(Http.Request request, @NotNull List<String> status) throws Exception;
|
||||
|
||||
public Result findPetsByTagsHttp(Http.Request request, @NotNull List<String> tags) throws Exception {
|
||||
List<Pet> obj = findPetsByTags(request, tags);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
|
||||
List<Pet> obj = findPetsByTags(request, tags);
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
for (Pet curItem : obj) {
|
||||
OpenAPIUtils.validate(curItem);
|
||||
}
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -71,39 +96,57 @@ return ok(result);
|
||||
|
||||
public Result getPetByIdHttp(Http.Request request, Long petId) throws Exception {
|
||||
Pet obj = getPetById(request, petId);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
public abstract Pet getPetById(Http.Request request, Long petId) throws Exception;
|
||||
|
||||
public Result updatePetHttp(Http.Request request, Pet body) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
updatePet(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
public abstract void updatePet(Http.Request request, Pet body) throws Exception;
|
||||
|
||||
public Result updatePetWithFormHttp(Http.Request request, Long petId, String name, String status) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
updatePetWithForm(request, petId, name, status);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
public abstract void updatePetWithForm(Http.Request request, Long petId, String name, String status) throws Exception;
|
||||
|
||||
public Result uploadFileHttp(Http.Request request, Long petId, String additionalMetadata, Http.MultipartFormData.FilePart<TemporaryFile> file) throws Exception {
|
||||
if (!securityAPIUtils.isRequestTokenValid(request, "petstore_auth")) {
|
||||
return unauthorized();
|
||||
}
|
||||
|
||||
ModelApiResponse obj = uploadFile(request, petId, additionalMetadata, file);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,9 @@ import play.mvc.Result;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import static play.mvc.Results.ok;
|
||||
import static play.mvc.Results.unauthorized;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
@ -22,11 +24,12 @@ import javax.validation.constraints.*;
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public abstract class StoreApiControllerImpInterface {
|
||||
@Inject private Config configuration;
|
||||
@Inject private SecurityAPIUtils securityAPIUtils;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public Result deleteOrderHttp(Http.Request request, String orderId) throws Exception {
|
||||
deleteOrder(request, orderId);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -34,8 +37,9 @@ return ok();
|
||||
|
||||
public Result getInventoryHttp(Http.Request request) throws Exception {
|
||||
Map<String, Integer> obj = getInventory(request);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -43,11 +47,14 @@ return ok(result);
|
||||
|
||||
public Result getOrderByIdHttp(Http.Request request, @Min(1) @Max(5)Long orderId) throws Exception {
|
||||
Order obj = getOrderById(request, orderId);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -55,11 +62,14 @@ return ok(result);
|
||||
|
||||
public Result placeOrderHttp(Http.Request request, Order body) throws Exception {
|
||||
Order obj = placeOrder(request, body);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,9 @@ import play.mvc.Result;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import openapitools.OpenAPIUtils;
|
||||
import openapitools.SecurityAPIUtils;
|
||||
import static play.mvc.Results.ok;
|
||||
import static play.mvc.Results.unauthorized;
|
||||
import play.libs.Files.TemporaryFile;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
@ -23,11 +25,12 @@ import javax.validation.constraints.*;
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
public abstract class UserApiControllerImpInterface {
|
||||
@Inject private Config configuration;
|
||||
@Inject private SecurityAPIUtils securityAPIUtils;
|
||||
private ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
public Result createUserHttp(Http.Request request, User body) throws Exception {
|
||||
createUser(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -35,7 +38,7 @@ return ok();
|
||||
|
||||
public Result createUsersWithArrayInputHttp(Http.Request request, List<User> body) throws Exception {
|
||||
createUsersWithArrayInput(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -43,7 +46,7 @@ return ok();
|
||||
|
||||
public Result createUsersWithListInputHttp(Http.Request request, List<User> body) throws Exception {
|
||||
createUsersWithListInput(request, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -51,7 +54,7 @@ return ok();
|
||||
|
||||
public Result deleteUserHttp(Http.Request request, String username) throws Exception {
|
||||
deleteUser(request, username);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -59,11 +62,14 @@ return ok();
|
||||
|
||||
public Result getUserByNameHttp(Http.Request request, String username) throws Exception {
|
||||
User obj = getUserByName(request, username);
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
|
||||
if (configuration.getBoolean("useOutputBeanValidation")) {
|
||||
OpenAPIUtils.validate(obj);
|
||||
}
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
}
|
||||
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -71,8 +77,9 @@ return ok(result);
|
||||
|
||||
public Result loginUserHttp(Http.Request request, @NotNull String username, @NotNull String password) throws Exception {
|
||||
String obj = loginUser(request, username, password);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
return ok(result);
|
||||
JsonNode result = mapper.valueToTree(obj);
|
||||
|
||||
return ok(result);
|
||||
|
||||
}
|
||||
|
||||
@ -80,7 +87,7 @@ return ok(result);
|
||||
|
||||
public Result logoutUserHttp(Http.Request request) throws Exception {
|
||||
logoutUser(request);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
@ -88,7 +95,7 @@ return ok();
|
||||
|
||||
public Result updateUserHttp(Http.Request request, String username, User body) throws Exception {
|
||||
updateUser(request, username, body);
|
||||
return ok();
|
||||
return ok();
|
||||
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,165 @@
|
||||
package openapitools;
|
||||
|
||||
import com.auth0.jwk.Jwk;
|
||||
import com.auth0.jwk.UrlJwkProvider;
|
||||
import com.auth0.jwt.JWT;
|
||||
import com.auth0.jwt.JWTVerifier;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import com.typesafe.config.Config;
|
||||
import org.apache.http.HttpHeaders;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import play.mvc.Http;
|
||||
|
||||
import java.net.URL;
|
||||
import java.security.PublicKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Singleton
|
||||
public class SecurityAPIUtils {
|
||||
private final String bearerPrefix = "Bearer ";
|
||||
private final ObjectMapper mapper;
|
||||
|
||||
private boolean useOnlineValidation = false;
|
||||
|
||||
// Online validation
|
||||
private HashMap<String, String> tokenIntrospectEndpoints = new HashMap<>();
|
||||
private final String clientId;
|
||||
private final String clientSecret;
|
||||
|
||||
// Offline validation
|
||||
private HashMap<String, String> jwksEndpoints = new HashMap<>();
|
||||
private String tokenKeyId = "";
|
||||
private JWTVerifier tokenVerifier; //Reusable verifier instance until tokenKeyId changes.
|
||||
|
||||
@Inject
|
||||
SecurityAPIUtils(Config configuration) {
|
||||
mapper = new ObjectMapper();
|
||||
|
||||
clientId = configuration.hasPath("oauth.clientId") ? configuration.getString("oauth.clientId") : "";
|
||||
clientSecret = configuration.hasPath("oauth.clientSecret") ? configuration.getString("oauth.clientSecret") : "";
|
||||
|
||||
tokenIntrospectEndpoints.put("petstore_auth", "");
|
||||
|
||||
jwksEndpoints.put("petstore_auth", "");
|
||||
}
|
||||
|
||||
private boolean isRequestTokenValidByOnlineCheck(Http.Request request, String securityMethodName) {
|
||||
try {
|
||||
Optional<String> authToken = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
|
||||
if (authToken.isPresent()) {
|
||||
String tokenWithoutBearerPrefix = authToken.get().substring(bearerPrefix.length());
|
||||
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
HttpClient httpClient = builder.build();
|
||||
HttpPost httppost = new HttpPost(this.tokenIntrospectEndpoints.get(securityMethodName));
|
||||
|
||||
List<NameValuePair> params = new ArrayList<>();
|
||||
params.add(new BasicNameValuePair("token", tokenWithoutBearerPrefix));
|
||||
params.add(new BasicNameValuePair("client_id", clientId));
|
||||
params.add(new BasicNameValuePair("client_secret", clientSecret));
|
||||
httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
|
||||
|
||||
HttpResponse response = httpClient.execute(httppost);
|
||||
String responseJsonString = EntityUtils.toString(response.getEntity());
|
||||
HashMap responseJsonObject = mapper.readValue(responseJsonString, HashMap.class);
|
||||
|
||||
return response.getStatusLine().getStatusCode() == HttpStatus.SC_OK && (boolean) responseJsonObject.get("active");
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isRequestTokenValidByOfflineCheck(Http.Request request, String securityMethodName) {
|
||||
try {
|
||||
Optional<String> authHeader = request.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
|
||||
if (authHeader.isPresent()) {
|
||||
String bearerToken = authHeader.get().substring(bearerPrefix.length());
|
||||
return isTokenValidByOfflineCheck(bearerToken, securityMethodName);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isTokenValidByOfflineCheck(String bearerToken, String securityMethodName) {
|
||||
try {
|
||||
DecodedJWT jwt = JWT.decode(bearerToken);
|
||||
String issuer = jwt.getIssuer();
|
||||
String keyId = jwt.getKeyId();
|
||||
if (!tokenKeyId.equals(keyId)) {
|
||||
if (securityMethodName == null) {
|
||||
securityMethodName = jwksEndpoints.keySet().stream().findFirst().get();
|
||||
}
|
||||
|
||||
Jwk jwk = new UrlJwkProvider(new URL(this.jwksEndpoints.get(securityMethodName))).get(keyId);
|
||||
final PublicKey publicKey = jwk.getPublicKey();
|
||||
|
||||
if (!(publicKey instanceof RSAPublicKey)) {
|
||||
throw new IllegalArgumentException(String.format("Key with ID %s was found in JWKS but is not a RSA-key.", keyId));
|
||||
}
|
||||
|
||||
Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) publicKey, null);
|
||||
tokenVerifier = JWT.require(algorithm)
|
||||
.withIssuer(issuer)
|
||||
.build();
|
||||
tokenKeyId = keyId;
|
||||
}
|
||||
|
||||
DecodedJWT verifiedJWT = tokenVerifier.verify(bearerToken);
|
||||
|
||||
return true;
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public String getOAuthUserIdFromRequestToken(Http.Request requestWithPreviouslyVerifiedToken) {
|
||||
try {
|
||||
Optional<String> authHeader = requestWithPreviouslyVerifiedToken.getHeaders().get(HttpHeaders.AUTHORIZATION);
|
||||
if (authHeader.isPresent()) {
|
||||
String bearerToken = authHeader.get().substring(bearerPrefix.length());
|
||||
return getOAuthUserIdFromToken(bearerToken);
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getOAuthUserIdFromToken(String bearerToken) {
|
||||
try {
|
||||
DecodedJWT jwt = JWT.decode(bearerToken);
|
||||
return jwt.getSubject();
|
||||
} catch (Exception exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRequestTokenValid(Http.Request request, String securityMethodName) {
|
||||
return useOnlineValidation ? isRequestTokenValidByOnlineCheck(request, securityMethodName) : isRequestTokenValidByOfflineCheck(request, securityMethodName);
|
||||
}
|
||||
}
|
@ -8,3 +8,6 @@ scalaVersion := "2.12.6"
|
||||
|
||||
libraryDependencies += "javax.validation" % "validation-api" % "2.0.1.Final"
|
||||
libraryDependencies += guice
|
||||
libraryDependencies += "com.auth0" % "java-jwt" % "3.18.1"
|
||||
libraryDependencies += "com.auth0" % "jwks-rsa" % "0.19.0"
|
||||
libraryDependencies += "org.apache.httpcomponents" % "httpclient" % "4.5.6"
|
||||
|
@ -19,6 +19,7 @@ app/controllers/UserApiControllerImp.java
|
||||
app/controllers/UserApiControllerImpInterface.java
|
||||
app/openapitools/ErrorHandler.java
|
||||
app/openapitools/OpenAPIUtils.java
|
||||
app/openapitools/SecurityAPIUtils.java
|
||||
build.sbt
|
||||
conf/application.conf
|
||||
conf/logback.xml
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user