[JAVA][Feign] Replace Apache oltu with scribejava (#8318)

* - Replace apache oltu with scribejava
- Implement the following authentication methods
  - ApiKey header
  - HTTP basic authentication
  - Oauth client credentials flow
  - Oauth Implicit flow
  - Oauth Pasword (deprecated)

* Create class hierarchy for Oauth flows implementation

* Add instructions of how to use the ApiClient to Readme.md

* Update samples

* Remove support for java 6 and 7

* Remove java 6 and 7 support from gradle

* Format pom.xml

* Remove empty line

* Update samples

* Remove oltu dependency from build.gradle and build.sbt.
Replace oltu with ScribeJava

Update samples

* Update samples

* Update samples
This commit is contained in:
Hugo Alves 2021-01-19 04:41:25 +00:00 committed by GitHub
parent 6e4c1307a7
commit ede2a2316c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 1208 additions and 1211 deletions

View File

@ -1,100 +1,100 @@
@rem @rem
@rem Copyright 2015 the original author or authors. @rem Copyright 2015 the original author or authors.
@rem @rem
@rem Licensed under the Apache License, Version 2.0 (the "License"); @rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License. @rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at @rem You may obtain a copy of the License at
@rem @rem
@rem https://www.apache.org/licenses/LICENSE-2.0 @rem https://www.apache.org/licenses/LICENSE-2.0
@rem @rem
@rem Unless required by applicable law or agreed to in writing, software @rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS, @rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and @rem See the License for the specific language governing permissions and
@rem limitations under the License. @rem limitations under the License.
@rem @rem
@if "%DEBUG%" == "" @echo off @if "%DEBUG%" == "" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@rem Gradle startup script for Windows @rem Gradle startup script for Windows
@rem @rem
@rem ########################################################################## @rem ##########################################################################
@rem Set local scope for the variables with windows NT shell @rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0 set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=. if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe @rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init if "%ERRORLEVEL%" == "0" goto init
echo. echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo. echo.
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation. echo location of your Java installation.
goto fail goto fail
:findJavaFromJavaHome :findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=% set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init if exist "%JAVA_EXE%" goto init
echo. echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo. echo.
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation. echo location of your Java installation.
goto fail goto fail
:init :init
@rem Get command-line arguments, handling Windows variants @rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args :win9xME_args
@rem Slurp the command line arguments. @rem Slurp the command line arguments.
set CMD_LINE_ARGS= set CMD_LINE_ARGS=
set _SKIP=2 set _SKIP=2
:win9xME_args_slurp :win9xME_args_slurp
if "x%~1" == "x" goto execute if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%* set CMD_LINE_ARGS=%*
:execute :execute
@rem Setup the command line @rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle @rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd if "%ERRORLEVEL%"=="0" goto mainEnd
:fail :fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code! rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1 exit /b 1
:mainEnd :mainEnd
if "%OS%"=="Windows_NT" endlocal if "%OS%"=="Windows_NT" endlocal
:omega :omega

View File

@ -392,6 +392,10 @@ public class JavaClientCodegen extends AbstractJavaCodegen
forceSerializationLibrary(SERIALIZATION_LIBRARY_JACKSON); forceSerializationLibrary(SERIALIZATION_LIBRARY_JACKSON);
supportingFiles.add(new SupportingFile("ParamExpander.mustache", invokerFolder, "ParamExpander.java")); supportingFiles.add(new SupportingFile("ParamExpander.mustache", invokerFolder, "ParamExpander.java"));
supportingFiles.add(new SupportingFile("EncodingUtils.mustache", invokerFolder, "EncodingUtils.java")); supportingFiles.add(new SupportingFile("EncodingUtils.mustache", invokerFolder, "EncodingUtils.java"));
supportingFiles.add(new SupportingFile("auth/DefaultApi20Impl.mustache", authFolder, "DefaultApi20Impl.java"));
supportingFiles.add(new SupportingFile("auth/OauthPasswordGrant.mustache", authFolder, "OauthPasswordGrant.java"));
supportingFiles.add(new SupportingFile("auth/OauthClientCredentialsGrant.mustache", authFolder, "OauthClientCredentialsGrant.java"));
} else if (OKHTTP_GSON.equals(getLibrary()) || StringUtils.isEmpty(getLibrary())) { } else if (OKHTTP_GSON.equals(getLibrary()) || StringUtils.isEmpty(getLibrary())) {
// the "okhttp-gson" library template requires "ApiCallback.mustache" for async call // the "okhttp-gson" library template requires "ApiCallback.mustache" for async call
supportingFiles.add(new SupportingFile("ApiCallback.mustache", invokerFolder, "ApiCallback.java")); supportingFiles.add(new SupportingFile("ApiCallback.mustache", invokerFolder, "ApiCallback.java"));

View File

@ -2,6 +2,10 @@
package {{invokerPackage}}.auth; package {{invokerPackage}}.auth;
{{>generatedAnnotation}}
public enum OAuthFlow { public enum OAuthFlow {
accessCode, implicit, password, application accessCode, //called authorizationCode in OpenAPI 3.0
implicit,
password,
application //called clientCredentials in OpenAPI 3.0
} }

View File

@ -2,11 +2,8 @@ package {{invokerPackage}};
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.logging.Level;
{{#hasOAuthMethods}} import java.util.logging.Logger;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest.AuthenticationRequestBuilder;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest.TokenRequestBuilder;
{{/hasOAuthMethods}}
{{#threetenbp}} {{#threetenbp}}
import org.threeten.bp.*; import org.threeten.bp.*;
@ -41,6 +38,8 @@ import {{invokerPackage}}.auth.OAuth.AccessTokenListener;
{{>generatedAnnotation}} {{>generatedAnnotation}}
public class ApiClient { public class ApiClient {
private static final Logger log = Logger.getLogger(ApiClient.class.getName());
public interface Api {} public interface Api {}
protected ObjectMapper objectMapper; protected ObjectMapper objectMapper;
@ -60,6 +59,7 @@ public class ApiClient {
public ApiClient(String[] authNames) { public ApiClient(String[] authNames) {
this(); this();
for(String authName : authNames) { for(String authName : authNames) {
log.log(Level.FINE, "Creating authentication {0}", authName);
{{#hasAuthMethods}} {{#hasAuthMethods}}
RequestInterceptor auth; RequestInterceptor auth;
{{#authMethods}}if ("{{name}}".equals(authName)) { {{#authMethods}}if ("{{name}}".equals(authName)) {
@ -75,7 +75,7 @@ public class ApiClient {
auth = new ApiKeyAuth({{#isKeyInHeader}}"header"{{/isKeyInHeader}}{{#isKeyInQuery}}"query"{{/isKeyInQuery}}{{#isKeyInCookie}}"cookie"{{/isKeyInCookie}}, "{{keyParamName}}"); auth = new ApiKeyAuth({{#isKeyInHeader}}"header"{{/isKeyInHeader}}{{#isKeyInQuery}}"query"{{/isKeyInQuery}}{{#isKeyInCookie}}"cookie"{{/isKeyInCookie}}, "{{keyParamName}}");
{{/isApiKey}} {{/isApiKey}}
{{#isOAuth}} {{#isOAuth}}
auth = new OAuth(OAuthFlow.{{flow}}, "{{authorizationUrl}}", "{{tokenUrl}}", "{{#scopes}}{{scope}}{{^-last}}, {{/-last}}{{/scopes}}"); auth = buildOauthRequestInterceptor(OAuthFlow.{{flow}}, "{{authorizationUrl}}", "{{tokenUrl}}", "{{#scopes}}{{scope}}{{^-last}}, {{/-last}}{{/scopes}}");
{{/isOAuth}} {{/isOAuth}}
} else {{/authMethods}}{ } else {{/authMethods}}{
throw new RuntimeException("auth name \"" + authName + "\" not found in available auth names"); throw new RuntimeException("auth name \"" + authName + "\" not found in available auth names");
@ -106,36 +106,6 @@ public class ApiClient {
this.setApiKey(apiKey); this.setApiKey(apiKey);
} }
/**
* Helper constructor for single basic auth or password oauth2
* @param authName
* @param username
* @param password
*/
public ApiClient(String authName, String username, String password) {
this(authName);
this.setCredentials(username, password);
}
{{#hasOAuthMethods}}
/**
* Helper constructor for single password oauth2
* @param authName
* @param clientId
* @param secret
* @param username
* @param password
*/
public ApiClient(String authName, String clientId, String secret, String username, String password) {
this(authName);
this.getTokenEndPoint()
.setClientId(clientId)
.setClientSecret(secret)
.setUsername(username)
.setPassword(password);
}
{{/hasOAuthMethods}}
public String getBasePath() { public String getBasePath() {
return basePath; return basePath;
} }
@ -190,10 +160,25 @@ public class ApiClient {
return objectMapper; return objectMapper;
} }
private RequestInterceptor buildOauthRequestInterceptor(OAuthFlow flow, String authorizationUrl, String tokenUrl, String scopes) {
switch (flow) {
case password:
return new OauthPasswordGrant(tokenUrl, scopes);
case application:
return new OauthClientCredentialsGrant(authorizationUrl, tokenUrl, scopes);
default:
throw new RuntimeException("Oauth flow \"" + flow + "\" is not implemented");
}
}
public ObjectMapper getObjectMapper(){ public ObjectMapper getObjectMapper(){
return objectMapper; return objectMapper;
} }
public void setObjectMapper(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
/** /**
* Creates a feign client for given API interface. * Creates a feign client for given API interface.
* *
@ -240,19 +225,13 @@ public class ApiClient {
return contentTypes[0]; return contentTypes[0];
} }
/** /**
* Helper method to configure the bearer token. * Helper method to configure the bearer token.
* @param bearerToken the bearer token. * @param bearerToken the bearer token.
*/ */
public void setBearerToken(String bearerToken) { public void setBearerToken(String bearerToken) {
for(RequestInterceptor apiAuthorization : apiAuthorizations.values()) { HttpBearerAuth apiAuthorization = getAuthorization(HttpBearerAuth.class);
if (apiAuthorization instanceof HttpBearerAuth) { apiAuthorization.setBearerToken(bearerToken);
((HttpBearerAuth) apiAuthorization).setBearerToken(bearerToken);
return;
}
}
throw new RuntimeException("No Bearer authentication configured!");
} }
/** /**
@ -260,66 +239,39 @@ public class ApiClient {
* @param apiKey API key * @param apiKey API key
*/ */
public void setApiKey(String apiKey) { public void setApiKey(String apiKey) {
for(RequestInterceptor apiAuthorization : apiAuthorizations.values()) { ApiKeyAuth apiAuthorization = getAuthorization(ApiKeyAuth.class);
if (apiAuthorization instanceof ApiKeyAuth) { apiAuthorization.setApiKey(apiKey);
ApiKeyAuth keyAuth = (ApiKeyAuth) apiAuthorization;
keyAuth.setApiKey(apiKey);
return ;
}
}
throw new RuntimeException("No API key authentication configured!");
} }
/** /**
* Helper method to configure the username/password for basic auth or password OAuth * Helper method to configure the username/password for basic auth
* @param username Username * @param username Username
* @param password Password * @param password Password
*/ */
public void setCredentials(String username, String password) { public void setCredentials(String username, String password) {
for(RequestInterceptor apiAuthorization : apiAuthorizations.values()) { HttpBasicAuth apiAuthorization = getAuthorization(HttpBasicAuth.class);
if (apiAuthorization instanceof HttpBasicAuth) { apiAuthorization.setCredentials(username, password);
HttpBasicAuth basicAuth = (HttpBasicAuth) apiAuthorization;
basicAuth.setCredentials(username, password);
return;
}
{{#hasOAuthMethods}}
if (apiAuthorization instanceof OAuth) {
OAuth oauth = (OAuth) apiAuthorization;
oauth.getTokenRequestBuilder().setUsername(username).setPassword(password);
return;
}
{{/hasOAuthMethods}}
}
throw new RuntimeException("No Basic authentication or OAuth configured!");
} }
{{#hasOAuthMethods}} {{#hasOAuthMethods}}
/** /**
* Helper method to configure the token endpoint of the first oauth found in the apiAuthorizations (there should be only one) * Helper method to configure the client credentials for Oauth
* @return Token request builder * @param username Username
* @param password Password
*/ */
public TokenRequestBuilder getTokenEndPoint() { public void setClientCredentials(String clientId, String clientSecret) {
for(RequestInterceptor apiAuthorization : apiAuthorizations.values()) { OauthClientCredentialsGrant authorization = getAuthorization(OauthClientCredentialsGrant.class);
if (apiAuthorization instanceof OAuth) { authorization.configure(clientId, clientSecret);
OAuth oauth = (OAuth) apiAuthorization;
return oauth.getTokenRequestBuilder();
}
}
return null;
} }
/** /**
* Helper method to configure authorization endpoint of the first oauth found in the apiAuthorizations (there should be only one) * Helper method to configure the username/password for Oauth password grant
* @return Authentication request builder * @param username Username
* @param password Password
*/ */
public AuthenticationRequestBuilder getAuthorizationEndPoint() { public void setOauthPassword(String username, String password, String clientId, String clientSecret) {
for(RequestInterceptor apiAuthorization : apiAuthorizations.values()) { OauthPasswordGrant apiAuthorization = getAuthorization(OauthPasswordGrant.class);
if (apiAuthorization instanceof OAuth) { apiAuthorization.configure(username, password, clientId, clientSecret);
OAuth oauth = (OAuth) apiAuthorization;
return oauth.getAuthenticationRequestBuilder();
}
}
return null;
} }
/** /**
@ -327,14 +279,9 @@ public class ApiClient {
* @param accessToken Access Token * @param accessToken Access Token
* @param expiresIn Validity period in seconds * @param expiresIn Validity period in seconds
*/ */
public void setAccessToken(String accessToken, Long expiresIn) { public void setAccessToken(String accessToken, Integer expiresIn) {
for(RequestInterceptor apiAuthorization : apiAuthorizations.values()) { OAuth apiAuthorization = getAuthorization(OAuth.class);
if (apiAuthorization instanceof OAuth) { apiAuthorization.setAccessToken(accessToken, expiresIn);
OAuth oauth = (OAuth) apiAuthorization;
oauth.setAccessToken(accessToken, expiresIn);
return;
}
}
} }
/** /**
@ -344,19 +291,7 @@ public class ApiClient {
* @param redirectURI Redirect URI * @param redirectURI Redirect URI
*/ */
public void configureAuthorizationFlow(String clientId, String clientSecret, String redirectURI) { public void configureAuthorizationFlow(String clientId, String clientSecret, String redirectURI) {
for(RequestInterceptor apiAuthorization : apiAuthorizations.values()) { throw new RuntimeException("Not implemented");
if (apiAuthorization instanceof OAuth) {
OAuth oauth = (OAuth) apiAuthorization;
oauth.getTokenRequestBuilder()
.setClientId(clientId)
.setClientSecret(clientSecret)
.setRedirectURI(redirectURI);
oauth.getAuthenticationRequestBuilder()
.setClientId(clientId)
.setRedirectURI(redirectURI);
return;
}
}
} }
/** /**
@ -364,13 +299,8 @@ public class ApiClient {
* @param accessTokenListener Acesss token listener * @param accessTokenListener Acesss token listener
*/ */
public void registerAccessTokenListener(AccessTokenListener accessTokenListener) { public void registerAccessTokenListener(AccessTokenListener accessTokenListener) {
for(RequestInterceptor apiAuthorization : apiAuthorizations.values()) { OAuth apiAuthorization = getAuthorization(OAuth.class);
if (apiAuthorization instanceof OAuth) { apiAuthorization.registerAccessTokenListener(accessTokenListener);
OAuth oauth = (OAuth) apiAuthorization;
oauth.registerAccessTokenListener(accessTokenListener);
return;
}
}
} }
{{/hasOAuthMethods}} {{/hasOAuthMethods}}
@ -396,4 +326,11 @@ public class ApiClient {
feignBuilder.requestInterceptor(authorization); feignBuilder.requestInterceptor(authorization);
} }
private <T extends RequestInterceptor> T getAuthorization(Class<T> type) {
return (T) apiAuthorizations.values()
.stream()
.filter(requestInterceptor -> type.isAssignableFrom(requestInterceptor.getClass()))
.findFirst()
.orElseThrow(() -> new RuntimeException("No Oauth authentication or OAuth configured!"));
}
} }

View File

@ -32,6 +32,41 @@ After the client library is installed/deployed, you can use it in your Maven pro
``` ```
And to use the api you can follow the examples bellow:
```java
//Set bearer token manually
ApiClient apiClient = new ApiClient("petstore_auth_client");
apiClient.setBasePath("https://localhost:8243/petstore/1/");
apiClient.setAccessToken("TOKEN", 10000);
//Use api key
ApiClient apiClient = new ApiClient("api_key", "API KEY");
apiClient.setBasePath("https://localhost:8243/petstore/1/");
//Use http basic authentication
ApiClient apiClient = new ApiClient("basicAuth");
apiClient.setBasePath("https://localhost:8243/petstore/1/");
apiClient.setCredentials("username", "password");
//Oauth password
ApiClient apiClient = new ApiClient("oauth_password");
apiClient.setBasePath("https://localhost:8243/petstore/1/");
apiClient.setOauthPassword("username", "password", "client_id", "client_secret");
//Oauth client credentials flow
ApiClient apiClient = new ApiClient("oauth_client_credentials");
apiClient.setBasePath("https://localhost:8243/petstore/1/");
apiClient.setClientCredentials("client_id", "client_secret");
PetApi petApi = apiClient.buildClient(PetApi.class);
Pet petById = petApi.getPetById(12345L);
System.out.println(petById);
}
```
## Recommendation ## Recommendation
It's recommended to create an instance of `ApiClient` per thread in a multithreaded environment to avoid any potential issues. It's recommended to create an instance of `ApiClient` per thread in a multithreaded environment to avoid any potential issues.
@ -40,4 +75,3 @@ It's recommended to create an instance of `ApiClient` per thread in a multithrea
{{#apiInfo}}{{#apis}}{{#-last}}{{infoEmail}} {{#apiInfo}}{{#apis}}{{#-last}}{{infoEmail}}
{{/-last}}{{/apis}}{{/apiInfo}} {{/-last}}{{/apis}}{{/apiInfo}}

View File

@ -0,0 +1,47 @@
package {{invokerPackage}}.auth;
import com.github.scribejava.core.builder.api.DefaultApi20;
import com.github.scribejava.core.extractors.OAuth2AccessTokenJsonExtractor;
import com.github.scribejava.core.extractors.TokenExtractor;
import com.github.scribejava.core.model.OAuth2AccessToken;
import com.github.scribejava.core.oauth2.bearersignature.BearerSignature;
import com.github.scribejava.core.oauth2.bearersignature.BearerSignatureURIQueryParameter;
import com.github.scribejava.core.oauth2.clientauthentication.ClientAuthentication;
import com.github.scribejava.core.oauth2.clientauthentication.RequestBodyAuthenticationScheme;
{{>generatedAnnotation}}
public class DefaultApi20Impl extends DefaultApi20 {
private final String accessTokenEndpoint;
private final String authorizationBaseUrl;
protected DefaultApi20Impl(String authorizationBaseUrl, String accessTokenEndpoint) {
this.authorizationBaseUrl = authorizationBaseUrl;
this.accessTokenEndpoint = accessTokenEndpoint;
}
@Override
public String getAccessTokenEndpoint() {
return accessTokenEndpoint;
}
@Override
protected String getAuthorizationBaseUrl() {
return authorizationBaseUrl;
}
@Override
public BearerSignature getBearerSignature() {
return BearerSignatureURIQueryParameter.instance();
}
@Override
public ClientAuthentication getClientAuthentication() {
return RequestBodyAuthenticationScheme.instance();
}
@Override
public TokenExtractor<OAuth2AccessToken> getAccessTokenExtractor() {
return OAuth2AccessTokenJsonExtractor.instance();
}
}

View File

@ -1,198 +1,81 @@
package {{invokerPackage}}.auth; package {{invokerPackage}}.auth;
import java.io.IOException; import com.github.scribejava.core.model.OAuth2AccessToken;
import java.util.Collection; import com.github.scribejava.core.oauth.OAuth20Service;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.oltu.oauth2.client.HttpClient;
import org.apache.oltu.oauth2.client.OAuthClient;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest.AuthenticationRequestBuilder;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest.TokenRequestBuilder;
import org.apache.oltu.oauth2.client.response.OAuthClientResponse;
import org.apache.oltu.oauth2.client.response.OAuthClientResponseFactory;
import org.apache.oltu.oauth2.client.response.OAuthJSONAccessTokenResponse;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.types.GrantType;
import org.apache.oltu.oauth2.common.token.BasicOAuthToken;
import feign.Client;
import feign.Request.HttpMethod; import feign.Request.HttpMethod;
import feign.Request.Options;
import feign.RequestInterceptor; import feign.RequestInterceptor;
import feign.RequestTemplate; import feign.RequestTemplate;
import feign.Response;
import feign.RetryableException; import feign.RetryableException;
import feign.Util;
import {{invokerPackage}}.StringUtil;
{{>generatedAnnotation}}
public abstract class OAuth implements RequestInterceptor {
public class OAuth implements RequestInterceptor { static final int MILLIS_PER_SECOND = 1000;
static final int MILLIS_PER_SECOND = 1000; public interface AccessTokenListener {
void notify(OAuth2AccessToken token);
}
public interface AccessTokenListener { private volatile String accessToken;
void notify(BasicOAuthToken token); private Long expirationTimeMillis;
private AccessTokenListener accessTokenListener;
protected OAuth20Service service;
protected String scopes;
protected String authorizationUrl;
protected String tokenUrl;
public OAuth(String authorizationUrl, String tokenUrl, String scopes) {
this.scopes = scopes;
this.authorizationUrl = authorizationUrl;
this.tokenUrl = tokenUrl;
}
@Override
public void apply(RequestTemplate template) {
// If the request already have an authorization (eg. Basic auth), do nothing
if (template.headers().containsKey("Authorization")) {
return;
} }
// If first time, get the token
private volatile String accessToken; if (expirationTimeMillis == null || System.currentTimeMillis() >= expirationTimeMillis) {
private Long expirationTimeMillis; updateAccessToken(template);
private OAuthClient oauthClient;
private TokenRequestBuilder tokenRequestBuilder;
private AuthenticationRequestBuilder authenticationRequestBuilder;
private AccessTokenListener accessTokenListener;
public OAuth(Client client, TokenRequestBuilder requestBuilder) {
this.oauthClient = new OAuthClient(new OAuthFeignClient(client));
this.tokenRequestBuilder = requestBuilder;
} }
if (getAccessToken() != null) {
public OAuth(Client client, OAuthFlow flow, String authorizationUrl, String tokenUrl, String scopes) { template.header("Authorization", "Bearer " + getAccessToken());
this(client, OAuthClientRequest.tokenLocation(tokenUrl).setScope(scopes));
switch(flow) {
case accessCode:
case implicit:
tokenRequestBuilder.setGrantType(GrantType.AUTHORIZATION_CODE);
break;
case password:
tokenRequestBuilder.setGrantType(GrantType.PASSWORD);
break;
case application:
tokenRequestBuilder.setGrantType(GrantType.CLIENT_CREDENTIALS);
break;
default:
break;
}
authenticationRequestBuilder = OAuthClientRequest.authorizationLocation(authorizationUrl);
} }
}
public OAuth(OAuthFlow flow, String authorizationUrl, String tokenUrl, String scopes) { private synchronized void updateAccessToken(RequestTemplate template) {
this(new Client.Default(null, null), flow, authorizationUrl, tokenUrl, scopes); OAuth2AccessToken accessTokenResponse;
try {
accessTokenResponse = getOAuth2AccessToken();
} catch (Exception e) {
throw new RetryableException(0, e.getMessage(), HttpMethod.POST, e, null, template.request());
} }
if (accessTokenResponse != null && accessTokenResponse.getAccessToken() != null) {
@Override setAccessToken(accessTokenResponse.getAccessToken(), accessTokenResponse.getExpiresIn());
public void apply(RequestTemplate template) { if (accessTokenListener != null) {
// If the request already have an authorization (eg. Basic auth), do nothing accessTokenListener.notify(accessTokenResponse);
if (template.headers().containsKey("Authorization")) { }
return;
}
// If first time, get the token
if (expirationTimeMillis == null || System.currentTimeMillis() >= expirationTimeMillis) {
updateAccessToken(template);
}
if (getAccessToken() != null) {
template.header("Authorization", "Bearer " + getAccessToken());
}
} }
}
public synchronized void updateAccessToken(RequestTemplate template) { abstract OAuth2AccessToken getOAuth2AccessToken();
OAuthJSONAccessTokenResponse accessTokenResponse;
try {
accessTokenResponse = oauthClient.accessToken(tokenRequestBuilder.buildBodyMessage());
} catch (Exception e) {
throw new RetryableException(0, e.getMessage(), HttpMethod.POST, e, null, template.request());
}
if (accessTokenResponse != null && accessTokenResponse.getAccessToken() != null) {
setAccessToken(accessTokenResponse.getAccessToken(), accessTokenResponse.getExpiresIn());
if (accessTokenListener != null) {
accessTokenListener.notify((BasicOAuthToken) accessTokenResponse.getOAuthToken());
}
}
}
public synchronized void registerAccessTokenListener(AccessTokenListener accessTokenListener) { abstract OAuthFlow getFlow();
this.accessTokenListener = accessTokenListener;
}
public synchronized String getAccessToken() { public synchronized void registerAccessTokenListener(AccessTokenListener accessTokenListener) {
return accessToken; this.accessTokenListener = accessTokenListener;
} }
public synchronized void setAccessToken(String accessToken, Long expiresIn) { public synchronized String getAccessToken() {
this.accessToken = accessToken; return accessToken;
this.expirationTimeMillis = expiresIn == null ? null : System.currentTimeMillis() + expiresIn * MILLIS_PER_SECOND; }
}
public TokenRequestBuilder getTokenRequestBuilder() { public synchronized void setAccessToken(String accessToken, Integer expiresIn) {
return tokenRequestBuilder; this.accessToken = accessToken;
} this.expirationTimeMillis = expiresIn == null ? null : System.currentTimeMillis() + expiresIn * MILLIS_PER_SECOND;
}
public void setTokenRequestBuilder(TokenRequestBuilder tokenRequestBuilder) { }
this.tokenRequestBuilder = tokenRequestBuilder;
}
public AuthenticationRequestBuilder getAuthenticationRequestBuilder() {
return authenticationRequestBuilder;
}
public void setAuthenticationRequestBuilder(AuthenticationRequestBuilder authenticationRequestBuilder) {
this.authenticationRequestBuilder = authenticationRequestBuilder;
}
public OAuthClient getOauthClient() {
return oauthClient;
}
public void setOauthClient(OAuthClient oauthClient) {
this.oauthClient = oauthClient;
}
public void setOauthClient(Client client) {
this.oauthClient = new OAuthClient( new OAuthFeignClient(client));
}
public static class OAuthFeignClient implements HttpClient {
private Client client;
public OAuthFeignClient() {
this.client = new Client.Default(null, null);
}
public OAuthFeignClient(Client client) {
this.client = client;
}
public <T extends OAuthClientResponse> T execute(OAuthClientRequest request, Map<String, String> headers,
String requestMethod, Class<T> responseClass)
throws OAuthSystemException, OAuthProblemException {
RequestTemplate req = new RequestTemplate()
.append(request.getLocationUri())
.method(requestMethod)
.body(request.getBody());
for (Entry<String, String> entry : headers.entrySet()) {
req.header(entry.getKey(), entry.getValue());
}
Response feignResponse;
String body = "";
try {
feignResponse = client.execute(req.request(), new Options());
body = Util.toString(feignResponse.body().asReader());
} catch (IOException e) {
throw new OAuthSystemException(e);
}
String contentType = null;
Collection<String> contentTypeHeader = feignResponse.headers().get("Content-Type");
if(contentTypeHeader != null) {
contentType = StringUtil.join(contentTypeHeader.toArray(new String[0]), ";");
}
return OAuthClientResponseFactory.createCustomResponse(
body,
contentType,
feignResponse.status(),
responseClass
);
}
public void shutdown() {
// Nothing to do here
}
}
}

View File

@ -0,0 +1,39 @@
package {{invokerPackage}}.auth;
import com.github.scribejava.core.builder.ServiceBuilder;
import com.github.scribejava.core.model.OAuth2AccessToken;
{{>generatedAnnotation}}
public class OauthClientCredentialsGrant extends OAuth {
public OauthClientCredentialsGrant(String authorizationUrl, String tokenUrl, String scopes) {
super(authorizationUrl, tokenUrl, scopes);
}
@Override
protected OAuth2AccessToken getOAuth2AccessToken() {
try {
return service.getAccessTokenClientCredentialsGrant(scopes);
} catch (Exception e) {
throw new RuntimeException("Failed to get oauth token", e);
}
}
@Override
protected OAuthFlow getFlow() {
return OAuthFlow.application;
}
/**
* Configures the client credentials flow
*
* @param clientId
* @param clientSecret
*/
public void configure(String clientId, String clientSecret) {
service = new ServiceBuilder(clientId)
.apiSecret(clientSecret)
.defaultScope(scopes)
.build(new DefaultApi20Impl(authorizationUrl, tokenUrl));
}
}

View File

@ -0,0 +1,48 @@
package {{invokerPackage}}.auth;
import com.github.scribejava.core.builder.ServiceBuilder;
import com.github.scribejava.core.model.OAuth2AccessToken;
{{>generatedAnnotation}}
public class OauthPasswordGrant extends OAuth {
private String username;
private String password;
public OauthPasswordGrant(String tokenUrl, String scopes) {
super(null, tokenUrl, scopes);
}
@Override
protected OAuth2AccessToken getOAuth2AccessToken() {
try {
return service.getAccessTokenPasswordGrant(username, password);
} catch (Exception e) {
throw new RuntimeException("Failed to get oauth token", e);
}
}
@Override
protected OAuthFlow getFlow() {
return OAuthFlow.password;
}
/**
* Configures Oauth password grant flow
* Note: this flow is deprecated.
*
* @param username
* @param password
* @param clientId
* @param clientSecret
*/
public void configure(String username, String password, String clientId, String clientSecret) {
this.username = username;
this.password = password;
//TODO the clientId and secret are optional according with the RFC
service = new ServiceBuilder(clientId)
.apiSecret(clientSecret)
.defaultScope(scopes)
.build(new DefaultApi20Impl(authorizationUrl, tokenUrl));
}
}

View File

@ -33,20 +33,8 @@ if(hasProperty('target') && target == 'android') {
targetSdkVersion 25 targetSdkVersion 25
} }
compileOptions { compileOptions {
{{#supportJava6}}
sourceCompatibility JavaVersion.VERSION_1_6
targetCompatibility JavaVersion.VERSION_1_6
{{/supportJava6}}
{{^supportJava6}}
{{#java8}}
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
{{/java8}}
{{^java8}}
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
{{/java8}}
{{/supportJava6}}
} }
// Rename the aar correctly // Rename the aar correctly
@ -91,20 +79,8 @@ if(hasProperty('target') && target == 'android') {
apply plugin: 'java' apply plugin: 'java'
apply plugin: 'maven' apply plugin: 'maven'
{{#supportJava6}}
sourceCompatibility = JavaVersion.VERSION_1_6
targetCompatibility = JavaVersion.VERSION_1_6
{{/supportJava6}}
{{^supportJava6}}
{{#java8}}
sourceCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8
{{/java8}}
{{^java8}}
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
{{/java8}}
{{/supportJava6}}
install { install {
repositories.mavenInstaller { repositories.mavenInstaller {
@ -131,7 +107,7 @@ ext {
feign_version = "10.11" feign_version = "10.11"
feign_form_version = "3.8.0" feign_form_version = "3.8.0"
junit_version = "4.13.1" junit_version = "4.13.1"
oltu_version = "1.0.1" scribejava_version = "8.0.0"
} }
dependencies { dependencies {
@ -156,7 +132,8 @@ dependencies {
{{#threetenbp}} {{#threetenbp}}
implementation "com.github.joschi.jackson:jackson-datatype-threetenbp:$jackson_threetenbp_version" implementation "com.github.joschi.jackson:jackson-datatype-threetenbp:$jackson_threetenbp_version"
{{/threetenbp}} {{/threetenbp}}
implementation "org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:$oltu_version" implementation "com.brsanthu:migbase64:2.2"
implementation "com.github.scribejava:scribejava-core:$scribejava_version"
implementation "com.brsanthu:migbase64:2.2" implementation "com.brsanthu:migbase64:2.2"
implementation 'javax.annotation:javax.annotation-api:1.3.2' implementation 'javax.annotation:javax.annotation-api:1.3.2'
testImplementation "junit:junit:$junit_version" testImplementation "junit:junit:$junit_version"

View File

@ -19,7 +19,7 @@ lazy val root = (project in file(".")).
"com.fasterxml.jackson.core" % "jackson-databind" % "2.10.3" % "compile", "com.fasterxml.jackson.core" % "jackson-databind" % "2.10.3" % "compile",
"com.fasterxml.jackson.datatype" % "jackson-datatype-{{^java8}}joda{{/java8}}{{#java8}}jsr310{{/java8}}" % "2.9.10" % "compile", "com.fasterxml.jackson.datatype" % "jackson-datatype-{{^java8}}joda{{/java8}}{{#java8}}jsr310{{/java8}}" % "2.9.10" % "compile",
"com.github.joschi.jackson" % "jackson-datatype-threetenbp" % "2.9.10" % "compile", "com.github.joschi.jackson" % "jackson-datatype-threetenbp" % "2.9.10" % "compile",
"org.apache.oltu.oauth2" % "org.apache.oltu.oauth2.client" % "1.0.1" % "compile", "com.github.scribejava" % "scribejava-core" % "8.0.0" % "compile",
"com.brsanthu" % "migbase64" % "2.2" % "compile", "com.brsanthu" % "migbase64" % "2.2" % "compile",
"javax.annotation" % "javax.annotation-api" % "1.3.2" % "compile", "javax.annotation" % "javax.annotation-api" % "1.3.2" % "compile",
"junit" % "junit" % "4.13.1" % "test", "junit" % "junit" % "4.13.1" % "test",

View File

@ -161,17 +161,7 @@
<version>3.1.1</version> <version>3.1.1</version>
<configuration> <configuration>
<doclint>none</doclint> <doclint>none</doclint>
{{#supportJava6}} <source>1.8</source>
<source>1.6</source>
{{/supportJava6}}
{{^supportJava6}}
{{#java8}}
<source>1.8</source>
{{/java8}}
{{^java8}}
<source>1.7</source>
{{/java8}}
{{/supportJava6}}
</configuration> </configuration>
<executions> <executions>
<execution> <execution>
@ -282,40 +272,38 @@
</dependency> </dependency>
{{/openApiNullable}} {{/openApiNullable}}
{{#withXml}} {{#withXml}}
<!-- XML Support -->
<!-- XML Support --> <dependency>
<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId>
<groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId>
<artifactId>jackson-dataformat-xml</artifactId> <version>${jackson-version}</version>
<version>${jackson-version}</version> </dependency>
</dependency>
{{/withXml}} {{/withXml}}
{{#joda}} {{#joda}}
<dependency> <dependency>
<groupId>com.fasterxml.jackson.datatype</groupId> <groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId> <artifactId>jackson-datatype-joda</artifactId>
<version>${jackson-version}</version> <version>${jackson-version}</version>
</dependency> </dependency>
{{/joda}} {{/joda}}
{{#java8}} {{#java8}}
<dependency> <dependency>
<groupId>com.fasterxml.jackson.datatype</groupId> <groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId> <artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson-version}</version> <version>${jackson-version}</version>
</dependency> </dependency>
{{/java8}} {{/java8}}
{{#threetenbp}} {{#threetenbp}}
<dependency> <dependency>
<groupId>com.github.joschi.jackson</groupId> <groupId>com.github.joschi.jackson</groupId>
<artifactId>jackson-datatype-threetenbp</artifactId> <artifactId>jackson-datatype-threetenbp</artifactId>
<version>${jackson-threetenbp-version}</version> <version>${jackson-threetenbp-version}</version>
</dependency> </dependency>
{{/threetenbp}} {{/threetenbp}}
<dependency> <dependency>
<groupId>org.apache.oltu.oauth2</groupId> <groupId>com.github.scribejava</groupId>
<artifactId>org.apache.oltu.oauth2.client</artifactId> <artifactId>scribejava-core</artifactId>
<version>${oltu-version}</version> <version>${scribejava-version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>javax.annotation</groupId> <groupId>javax.annotation</groupId>
@ -346,7 +334,7 @@
</dependencies> </dependencies>
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>{{#supportJava6}}1.6{{/supportJava6}}{{^supportJava6}}{{#java8}}1.8{{/java8}}{{^java8}}1.7{{/java8}}{{/supportJava6}}</java.version> <java.version>1.8</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source> <maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target> <maven.compiler.target>${java.version}</maven.compiler.target>
<swagger-annotations-version>1.5.24</swagger-annotations-version> <swagger-annotations-version>1.5.24</swagger-annotations-version>
@ -363,6 +351,6 @@
<javax-annotation-version>1.3.2</javax-annotation-version> <javax-annotation-version>1.3.2</javax-annotation-version>
<junit-version>4.13.1</junit-version> <junit-version>4.13.1</junit-version>
<maven-plugin-version>1.0.0</maven-plugin-version> <maven-plugin-version>1.0.0</maven-plugin-version>
<oltu-version>1.0.1</oltu-version> <scribejava-version>8.0.0</scribejava-version>
</properties> </properties>
</project> </project>

View File

@ -28,10 +28,13 @@ src/main/java/org/openapitools/client/api/PetApi.java
src/main/java/org/openapitools/client/api/StoreApi.java src/main/java/org/openapitools/client/api/StoreApi.java
src/main/java/org/openapitools/client/api/UserApi.java src/main/java/org/openapitools/client/api/UserApi.java
src/main/java/org/openapitools/client/auth/ApiKeyAuth.java src/main/java/org/openapitools/client/auth/ApiKeyAuth.java
src/main/java/org/openapitools/client/auth/DefaultApi20Impl.java
src/main/java/org/openapitools/client/auth/HttpBasicAuth.java src/main/java/org/openapitools/client/auth/HttpBasicAuth.java
src/main/java/org/openapitools/client/auth/HttpBearerAuth.java src/main/java/org/openapitools/client/auth/HttpBearerAuth.java
src/main/java/org/openapitools/client/auth/OAuth.java src/main/java/org/openapitools/client/auth/OAuth.java
src/main/java/org/openapitools/client/auth/OAuthFlow.java src/main/java/org/openapitools/client/auth/OAuthFlow.java
src/main/java/org/openapitools/client/auth/OauthClientCredentialsGrant.java
src/main/java/org/openapitools/client/auth/OauthPasswordGrant.java
src/main/java/org/openapitools/client/model/AdditionalPropertiesAnyType.java src/main/java/org/openapitools/client/model/AdditionalPropertiesAnyType.java
src/main/java/org/openapitools/client/model/AdditionalPropertiesArray.java src/main/java/org/openapitools/client/model/AdditionalPropertiesArray.java
src/main/java/org/openapitools/client/model/AdditionalPropertiesBoolean.java src/main/java/org/openapitools/client/model/AdditionalPropertiesBoolean.java

View File

@ -32,6 +32,41 @@ After the client library is installed/deployed, you can use it in your Maven pro
``` ```
And to use the api you can follow the examples bellow:
```java
//Set bearer token manually
ApiClient apiClient = new ApiClient("petstore_auth_client");
apiClient.setBasePath("https://localhost:8243/petstore/1/");
apiClient.setAccessToken("TOKEN", 10000);
//Use api key
ApiClient apiClient = new ApiClient("api_key", "API KEY");
apiClient.setBasePath("https://localhost:8243/petstore/1/");
//Use http basic authentication
ApiClient apiClient = new ApiClient("basicAuth");
apiClient.setBasePath("https://localhost:8243/petstore/1/");
apiClient.setCredentials("username", "password");
//Oauth password
ApiClient apiClient = new ApiClient("oauth_password");
apiClient.setBasePath("https://localhost:8243/petstore/1/");
apiClient.setOauthPassword("username", "password", "client_id", "client_secret");
//Oauth client credentials flow
ApiClient apiClient = new ApiClient("oauth_client_credentials");
apiClient.setBasePath("https://localhost:8243/petstore/1/");
apiClient.setClientCredentials("client_id", "client_secret");
PetApi petApi = apiClient.buildClient(PetApi.class);
Pet petById = petApi.getPetById(12345L);
System.out.println(petById);
}
```
## Recommendation ## Recommendation
It's recommended to create an instance of `ApiClient` per thread in a multithreaded environment to avoid any potential issues. It's recommended to create an instance of `ApiClient` per thread in a multithreaded environment to avoid any potential issues.
@ -40,4 +75,3 @@ It's recommended to create an instance of `ApiClient` per thread in a multithrea

View File

@ -33,8 +33,8 @@ if(hasProperty('target') && target == 'android') {
targetSdkVersion 25 targetSdkVersion 25
} }
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_8
} }
// Rename the aar correctly // Rename the aar correctly
@ -79,8 +79,8 @@ if(hasProperty('target') && target == 'android') {
apply plugin: 'java' apply plugin: 'java'
apply plugin: 'maven' apply plugin: 'maven'
sourceCompatibility = JavaVersion.VERSION_1_7 sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_7 targetCompatibility = JavaVersion.VERSION_1_8
install { install {
repositories.mavenInstaller { repositories.mavenInstaller {
@ -102,7 +102,7 @@ ext {
feign_version = "10.11" feign_version = "10.11"
feign_form_version = "3.8.0" feign_form_version = "3.8.0"
junit_version = "4.13.1" junit_version = "4.13.1"
oltu_version = "1.0.1" scribejava_version = "8.0.0"
} }
dependencies { dependencies {
@ -116,7 +116,8 @@ dependencies {
implementation "com.fasterxml.jackson.core:jackson-annotations:$jackson_version" implementation "com.fasterxml.jackson.core:jackson-annotations:$jackson_version"
implementation "com.fasterxml.jackson.core:jackson-databind:$jackson_databind_version" implementation "com.fasterxml.jackson.core:jackson-databind:$jackson_databind_version"
implementation "com.github.joschi.jackson:jackson-datatype-threetenbp:$jackson_threetenbp_version" implementation "com.github.joschi.jackson:jackson-datatype-threetenbp:$jackson_threetenbp_version"
implementation "org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:$oltu_version" implementation "com.brsanthu:migbase64:2.2"
implementation "com.github.scribejava:scribejava-core:$scribejava_version"
implementation "com.brsanthu:migbase64:2.2" implementation "com.brsanthu:migbase64:2.2"
implementation 'javax.annotation:javax.annotation-api:1.3.2' implementation 'javax.annotation:javax.annotation-api:1.3.2'
testImplementation "junit:junit:$junit_version" testImplementation "junit:junit:$junit_version"

View File

@ -19,7 +19,7 @@ lazy val root = (project in file(".")).
"com.fasterxml.jackson.core" % "jackson-databind" % "2.10.3" % "compile", "com.fasterxml.jackson.core" % "jackson-databind" % "2.10.3" % "compile",
"com.fasterxml.jackson.datatype" % "jackson-datatype-joda" % "2.9.10" % "compile", "com.fasterxml.jackson.datatype" % "jackson-datatype-joda" % "2.9.10" % "compile",
"com.github.joschi.jackson" % "jackson-datatype-threetenbp" % "2.9.10" % "compile", "com.github.joschi.jackson" % "jackson-datatype-threetenbp" % "2.9.10" % "compile",
"org.apache.oltu.oauth2" % "org.apache.oltu.oauth2.client" % "1.0.1" % "compile", "com.github.scribejava" % "scribejava-core" % "8.0.0" % "compile",
"com.brsanthu" % "migbase64" % "2.2" % "compile", "com.brsanthu" % "migbase64" % "2.2" % "compile",
"javax.annotation" % "javax.annotation-api" % "1.3.2" % "compile", "javax.annotation" % "javax.annotation-api" % "1.3.2" % "compile",
"junit" % "junit" % "4.13.1" % "test", "junit" % "junit" % "4.13.1" % "test",

View File

@ -154,7 +154,7 @@
<version>3.1.1</version> <version>3.1.1</version>
<configuration> <configuration>
<doclint>none</doclint> <doclint>none</doclint>
<source>1.7</source> <source>1.8</source>
</configuration> </configuration>
<executions> <executions>
<execution> <execution>
@ -257,15 +257,15 @@
<artifactId>jackson-databind</artifactId> <artifactId>jackson-databind</artifactId>
<version>${jackson-databind-version}</version> <version>${jackson-databind-version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.github.joschi.jackson</groupId>
<artifactId>jackson-datatype-threetenbp</artifactId>
<version>${jackson-threetenbp-version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.apache.oltu.oauth2</groupId> <groupId>com.github.joschi.jackson</groupId>
<artifactId>org.apache.oltu.oauth2.client</artifactId> <artifactId>jackson-datatype-threetenbp</artifactId>
<version>${oltu-version}</version> <version>${jackson-threetenbp-version}</version>
</dependency>
<dependency>
<groupId>com.github.scribejava</groupId>
<artifactId>scribejava-core</artifactId>
<version>${scribejava-version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>javax.annotation</groupId> <groupId>javax.annotation</groupId>
@ -296,7 +296,7 @@
</dependencies> </dependencies>
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.7</java.version> <java.version>1.8</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source> <maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target> <maven.compiler.target>${java.version}</maven.compiler.target>
<swagger-annotations-version>1.5.24</swagger-annotations-version> <swagger-annotations-version>1.5.24</swagger-annotations-version>
@ -308,6 +308,6 @@
<javax-annotation-version>1.3.2</javax-annotation-version> <javax-annotation-version>1.3.2</javax-annotation-version>
<junit-version>4.13.1</junit-version> <junit-version>4.13.1</junit-version>
<maven-plugin-version>1.0.0</maven-plugin-version> <maven-plugin-version>1.0.0</maven-plugin-version>
<oltu-version>1.0.1</oltu-version> <scribejava-version>8.0.0</scribejava-version>
</properties> </properties>
</project> </project>

View File

@ -2,9 +2,8 @@ package org.openapitools.client;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.logging.Level;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest.AuthenticationRequestBuilder; import java.util.logging.Logger;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest.TokenRequestBuilder;
import org.threeten.bp.*; import org.threeten.bp.*;
@ -24,6 +23,8 @@ import org.openapitools.client.auth.OAuth.AccessTokenListener;
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen") @javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen")
public class ApiClient { public class ApiClient {
private static final Logger log = Logger.getLogger(ApiClient.class.getName());
public interface Api {} public interface Api {}
protected ObjectMapper objectMapper; protected ObjectMapper objectMapper;
@ -43,6 +44,7 @@ public class ApiClient {
public ApiClient(String[] authNames) { public ApiClient(String[] authNames) {
this(); this();
for(String authName : authNames) { for(String authName : authNames) {
log.log(Level.FINE, "Creating authentication {0}", authName);
RequestInterceptor auth; RequestInterceptor auth;
if ("api_key".equals(authName)) { if ("api_key".equals(authName)) {
auth = new ApiKeyAuth("header", "api_key"); auth = new ApiKeyAuth("header", "api_key");
@ -51,7 +53,7 @@ public class ApiClient {
} else if ("http_basic_test".equals(authName)) { } else if ("http_basic_test".equals(authName)) {
auth = new HttpBasicAuth(); auth = new HttpBasicAuth();
} else if ("petstore_auth".equals(authName)) { } else if ("petstore_auth".equals(authName)) {
auth = new OAuth(OAuthFlow.implicit, "http://petstore.swagger.io/api/oauth/dialog", "", "write:pets, read:pets"); auth = buildOauthRequestInterceptor(OAuthFlow.implicit, "http://petstore.swagger.io/api/oauth/dialog", "", "write:pets, read:pets");
} else { } else {
throw new RuntimeException("auth name \"" + authName + "\" not found in available auth names"); throw new RuntimeException("auth name \"" + authName + "\" not found in available auth names");
} }
@ -77,34 +79,6 @@ public class ApiClient {
this.setApiKey(apiKey); this.setApiKey(apiKey);
} }
/**
* Helper constructor for single basic auth or password oauth2
* @param authName
* @param username
* @param password
*/
public ApiClient(String authName, String username, String password) {
this(authName);
this.setCredentials(username, password);
}
/**
* Helper constructor for single password oauth2
* @param authName
* @param clientId
* @param secret
* @param username
* @param password
*/
public ApiClient(String authName, String clientId, String secret, String username, String password) {
this(authName);
this.getTokenEndPoint()
.setClientId(clientId)
.setClientSecret(secret)
.setUsername(username)
.setPassword(password);
}
public String getBasePath() { public String getBasePath() {
return basePath; return basePath;
} }
@ -147,10 +121,25 @@ public class ApiClient {
return objectMapper; return objectMapper;
} }
private RequestInterceptor buildOauthRequestInterceptor(OAuthFlow flow, String authorizationUrl, String tokenUrl, String scopes) {
switch (flow) {
case password:
return new OauthPasswordGrant(tokenUrl, scopes);
case application:
return new OauthClientCredentialsGrant(authorizationUrl, tokenUrl, scopes);
default:
throw new RuntimeException("Oauth flow \"" + flow + "\" is not implemented");
}
}
public ObjectMapper getObjectMapper(){ public ObjectMapper getObjectMapper(){
return objectMapper; return objectMapper;
} }
public void setObjectMapper(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
/** /**
* Creates a feign client for given API interface. * Creates a feign client for given API interface.
* *
@ -197,19 +186,13 @@ public class ApiClient {
return contentTypes[0]; return contentTypes[0];
} }
/** /**
* Helper method to configure the bearer token. * Helper method to configure the bearer token.
* @param bearerToken the bearer token. * @param bearerToken the bearer token.
*/ */
public void setBearerToken(String bearerToken) { public void setBearerToken(String bearerToken) {
for(RequestInterceptor apiAuthorization : apiAuthorizations.values()) { HttpBearerAuth apiAuthorization = getAuthorization(HttpBearerAuth.class);
if (apiAuthorization instanceof HttpBearerAuth) { apiAuthorization.setBearerToken(bearerToken);
((HttpBearerAuth) apiAuthorization).setBearerToken(bearerToken);
return;
}
}
throw new RuntimeException("No Bearer authentication configured!");
} }
/** /**
@ -217,63 +200,38 @@ public class ApiClient {
* @param apiKey API key * @param apiKey API key
*/ */
public void setApiKey(String apiKey) { public void setApiKey(String apiKey) {
for(RequestInterceptor apiAuthorization : apiAuthorizations.values()) { ApiKeyAuth apiAuthorization = getAuthorization(ApiKeyAuth.class);
if (apiAuthorization instanceof ApiKeyAuth) { apiAuthorization.setApiKey(apiKey);
ApiKeyAuth keyAuth = (ApiKeyAuth) apiAuthorization;
keyAuth.setApiKey(apiKey);
return ;
}
}
throw new RuntimeException("No API key authentication configured!");
} }
/** /**
* Helper method to configure the username/password for basic auth or password OAuth * Helper method to configure the username/password for basic auth
* @param username Username * @param username Username
* @param password Password * @param password Password
*/ */
public void setCredentials(String username, String password) { public void setCredentials(String username, String password) {
for(RequestInterceptor apiAuthorization : apiAuthorizations.values()) { HttpBasicAuth apiAuthorization = getAuthorization(HttpBasicAuth.class);
if (apiAuthorization instanceof HttpBasicAuth) { apiAuthorization.setCredentials(username, password);
HttpBasicAuth basicAuth = (HttpBasicAuth) apiAuthorization;
basicAuth.setCredentials(username, password);
return;
}
if (apiAuthorization instanceof OAuth) {
OAuth oauth = (OAuth) apiAuthorization;
oauth.getTokenRequestBuilder().setUsername(username).setPassword(password);
return;
}
}
throw new RuntimeException("No Basic authentication or OAuth configured!");
} }
/** /**
* Helper method to configure the token endpoint of the first oauth found in the apiAuthorizations (there should be only one) * Helper method to configure the client credentials for Oauth
* @return Token request builder * @param username Username
* @param password Password
*/ */
public TokenRequestBuilder getTokenEndPoint() { public void setClientCredentials(String clientId, String clientSecret) {
for(RequestInterceptor apiAuthorization : apiAuthorizations.values()) { OauthClientCredentialsGrant authorization = getAuthorization(OauthClientCredentialsGrant.class);
if (apiAuthorization instanceof OAuth) { authorization.configure(clientId, clientSecret);
OAuth oauth = (OAuth) apiAuthorization;
return oauth.getTokenRequestBuilder();
}
}
return null;
} }
/** /**
* Helper method to configure authorization endpoint of the first oauth found in the apiAuthorizations (there should be only one) * Helper method to configure the username/password for Oauth password grant
* @return Authentication request builder * @param username Username
* @param password Password
*/ */
public AuthenticationRequestBuilder getAuthorizationEndPoint() { public void setOauthPassword(String username, String password, String clientId, String clientSecret) {
for(RequestInterceptor apiAuthorization : apiAuthorizations.values()) { OauthPasswordGrant apiAuthorization = getAuthorization(OauthPasswordGrant.class);
if (apiAuthorization instanceof OAuth) { apiAuthorization.configure(username, password, clientId, clientSecret);
OAuth oauth = (OAuth) apiAuthorization;
return oauth.getAuthenticationRequestBuilder();
}
}
return null;
} }
/** /**
@ -281,14 +239,9 @@ public class ApiClient {
* @param accessToken Access Token * @param accessToken Access Token
* @param expiresIn Validity period in seconds * @param expiresIn Validity period in seconds
*/ */
public void setAccessToken(String accessToken, Long expiresIn) { public void setAccessToken(String accessToken, Integer expiresIn) {
for(RequestInterceptor apiAuthorization : apiAuthorizations.values()) { OAuth apiAuthorization = getAuthorization(OAuth.class);
if (apiAuthorization instanceof OAuth) { apiAuthorization.setAccessToken(accessToken, expiresIn);
OAuth oauth = (OAuth) apiAuthorization;
oauth.setAccessToken(accessToken, expiresIn);
return;
}
}
} }
/** /**
@ -298,19 +251,7 @@ public class ApiClient {
* @param redirectURI Redirect URI * @param redirectURI Redirect URI
*/ */
public void configureAuthorizationFlow(String clientId, String clientSecret, String redirectURI) { public void configureAuthorizationFlow(String clientId, String clientSecret, String redirectURI) {
for(RequestInterceptor apiAuthorization : apiAuthorizations.values()) { throw new RuntimeException("Not implemented");
if (apiAuthorization instanceof OAuth) {
OAuth oauth = (OAuth) apiAuthorization;
oauth.getTokenRequestBuilder()
.setClientId(clientId)
.setClientSecret(clientSecret)
.setRedirectURI(redirectURI);
oauth.getAuthenticationRequestBuilder()
.setClientId(clientId)
.setRedirectURI(redirectURI);
return;
}
}
} }
/** /**
@ -318,13 +259,8 @@ public class ApiClient {
* @param accessTokenListener Acesss token listener * @param accessTokenListener Acesss token listener
*/ */
public void registerAccessTokenListener(AccessTokenListener accessTokenListener) { public void registerAccessTokenListener(AccessTokenListener accessTokenListener) {
for(RequestInterceptor apiAuthorization : apiAuthorizations.values()) { OAuth apiAuthorization = getAuthorization(OAuth.class);
if (apiAuthorization instanceof OAuth) { apiAuthorization.registerAccessTokenListener(accessTokenListener);
OAuth oauth = (OAuth) apiAuthorization;
oauth.registerAccessTokenListener(accessTokenListener);
return;
}
}
} }
/** /**
@ -349,4 +285,11 @@ public class ApiClient {
feignBuilder.requestInterceptor(authorization); feignBuilder.requestInterceptor(authorization);
} }
private <T extends RequestInterceptor> T getAuthorization(Class<T> type) {
return (T) apiAuthorizations.values()
.stream()
.filter(requestInterceptor -> type.isAssignableFrom(requestInterceptor.getClass()))
.findFirst()
.orElseThrow(() -> new RuntimeException("No Oauth authentication or OAuth configured!"));
}
} }

View File

@ -0,0 +1,47 @@
package org.openapitools.client.auth;
import com.github.scribejava.core.builder.api.DefaultApi20;
import com.github.scribejava.core.extractors.OAuth2AccessTokenJsonExtractor;
import com.github.scribejava.core.extractors.TokenExtractor;
import com.github.scribejava.core.model.OAuth2AccessToken;
import com.github.scribejava.core.oauth2.bearersignature.BearerSignature;
import com.github.scribejava.core.oauth2.bearersignature.BearerSignatureURIQueryParameter;
import com.github.scribejava.core.oauth2.clientauthentication.ClientAuthentication;
import com.github.scribejava.core.oauth2.clientauthentication.RequestBodyAuthenticationScheme;
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen")
public class DefaultApi20Impl extends DefaultApi20 {
private final String accessTokenEndpoint;
private final String authorizationBaseUrl;
protected DefaultApi20Impl(String authorizationBaseUrl, String accessTokenEndpoint) {
this.authorizationBaseUrl = authorizationBaseUrl;
this.accessTokenEndpoint = accessTokenEndpoint;
}
@Override
public String getAccessTokenEndpoint() {
return accessTokenEndpoint;
}
@Override
protected String getAuthorizationBaseUrl() {
return authorizationBaseUrl;
}
@Override
public BearerSignature getBearerSignature() {
return BearerSignatureURIQueryParameter.instance();
}
@Override
public ClientAuthentication getClientAuthentication() {
return RequestBodyAuthenticationScheme.instance();
}
@Override
public TokenExtractor<OAuth2AccessToken> getAccessTokenExtractor() {
return OAuth2AccessTokenJsonExtractor.instance();
}
}

View File

@ -1,198 +1,81 @@
package org.openapitools.client.auth; package org.openapitools.client.auth;
import java.io.IOException; import com.github.scribejava.core.model.OAuth2AccessToken;
import java.util.Collection; import com.github.scribejava.core.oauth.OAuth20Service;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.oltu.oauth2.client.HttpClient;
import org.apache.oltu.oauth2.client.OAuthClient;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest.AuthenticationRequestBuilder;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest.TokenRequestBuilder;
import org.apache.oltu.oauth2.client.response.OAuthClientResponse;
import org.apache.oltu.oauth2.client.response.OAuthClientResponseFactory;
import org.apache.oltu.oauth2.client.response.OAuthJSONAccessTokenResponse;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.types.GrantType;
import org.apache.oltu.oauth2.common.token.BasicOAuthToken;
import feign.Client;
import feign.Request.HttpMethod; import feign.Request.HttpMethod;
import feign.Request.Options;
import feign.RequestInterceptor; import feign.RequestInterceptor;
import feign.RequestTemplate; import feign.RequestTemplate;
import feign.Response;
import feign.RetryableException; import feign.RetryableException;
import feign.Util;
import org.openapitools.client.StringUtil;
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen")
public abstract class OAuth implements RequestInterceptor {
public class OAuth implements RequestInterceptor { static final int MILLIS_PER_SECOND = 1000;
static final int MILLIS_PER_SECOND = 1000; public interface AccessTokenListener {
void notify(OAuth2AccessToken token);
}
public interface AccessTokenListener { private volatile String accessToken;
void notify(BasicOAuthToken token); private Long expirationTimeMillis;
private AccessTokenListener accessTokenListener;
protected OAuth20Service service;
protected String scopes;
protected String authorizationUrl;
protected String tokenUrl;
public OAuth(String authorizationUrl, String tokenUrl, String scopes) {
this.scopes = scopes;
this.authorizationUrl = authorizationUrl;
this.tokenUrl = tokenUrl;
}
@Override
public void apply(RequestTemplate template) {
// If the request already have an authorization (eg. Basic auth), do nothing
if (template.headers().containsKey("Authorization")) {
return;
} }
// If first time, get the token
private volatile String accessToken; if (expirationTimeMillis == null || System.currentTimeMillis() >= expirationTimeMillis) {
private Long expirationTimeMillis; updateAccessToken(template);
private OAuthClient oauthClient;
private TokenRequestBuilder tokenRequestBuilder;
private AuthenticationRequestBuilder authenticationRequestBuilder;
private AccessTokenListener accessTokenListener;
public OAuth(Client client, TokenRequestBuilder requestBuilder) {
this.oauthClient = new OAuthClient(new OAuthFeignClient(client));
this.tokenRequestBuilder = requestBuilder;
} }
if (getAccessToken() != null) {
public OAuth(Client client, OAuthFlow flow, String authorizationUrl, String tokenUrl, String scopes) { template.header("Authorization", "Bearer " + getAccessToken());
this(client, OAuthClientRequest.tokenLocation(tokenUrl).setScope(scopes));
switch(flow) {
case accessCode:
case implicit:
tokenRequestBuilder.setGrantType(GrantType.AUTHORIZATION_CODE);
break;
case password:
tokenRequestBuilder.setGrantType(GrantType.PASSWORD);
break;
case application:
tokenRequestBuilder.setGrantType(GrantType.CLIENT_CREDENTIALS);
break;
default:
break;
}
authenticationRequestBuilder = OAuthClientRequest.authorizationLocation(authorizationUrl);
} }
}
public OAuth(OAuthFlow flow, String authorizationUrl, String tokenUrl, String scopes) { private synchronized void updateAccessToken(RequestTemplate template) {
this(new Client.Default(null, null), flow, authorizationUrl, tokenUrl, scopes); OAuth2AccessToken accessTokenResponse;
try {
accessTokenResponse = getOAuth2AccessToken();
} catch (Exception e) {
throw new RetryableException(0, e.getMessage(), HttpMethod.POST, e, null, template.request());
} }
if (accessTokenResponse != null && accessTokenResponse.getAccessToken() != null) {
@Override setAccessToken(accessTokenResponse.getAccessToken(), accessTokenResponse.getExpiresIn());
public void apply(RequestTemplate template) { if (accessTokenListener != null) {
// If the request already have an authorization (eg. Basic auth), do nothing accessTokenListener.notify(accessTokenResponse);
if (template.headers().containsKey("Authorization")) { }
return;
}
// If first time, get the token
if (expirationTimeMillis == null || System.currentTimeMillis() >= expirationTimeMillis) {
updateAccessToken(template);
}
if (getAccessToken() != null) {
template.header("Authorization", "Bearer " + getAccessToken());
}
} }
}
public synchronized void updateAccessToken(RequestTemplate template) { abstract OAuth2AccessToken getOAuth2AccessToken();
OAuthJSONAccessTokenResponse accessTokenResponse;
try {
accessTokenResponse = oauthClient.accessToken(tokenRequestBuilder.buildBodyMessage());
} catch (Exception e) {
throw new RetryableException(0, e.getMessage(), HttpMethod.POST, e, null, template.request());
}
if (accessTokenResponse != null && accessTokenResponse.getAccessToken() != null) {
setAccessToken(accessTokenResponse.getAccessToken(), accessTokenResponse.getExpiresIn());
if (accessTokenListener != null) {
accessTokenListener.notify((BasicOAuthToken) accessTokenResponse.getOAuthToken());
}
}
}
public synchronized void registerAccessTokenListener(AccessTokenListener accessTokenListener) { abstract OAuthFlow getFlow();
this.accessTokenListener = accessTokenListener;
}
public synchronized String getAccessToken() { public synchronized void registerAccessTokenListener(AccessTokenListener accessTokenListener) {
return accessToken; this.accessTokenListener = accessTokenListener;
} }
public synchronized void setAccessToken(String accessToken, Long expiresIn) { public synchronized String getAccessToken() {
this.accessToken = accessToken; return accessToken;
this.expirationTimeMillis = expiresIn == null ? null : System.currentTimeMillis() + expiresIn * MILLIS_PER_SECOND; }
}
public TokenRequestBuilder getTokenRequestBuilder() { public synchronized void setAccessToken(String accessToken, Integer expiresIn) {
return tokenRequestBuilder; this.accessToken = accessToken;
} this.expirationTimeMillis = expiresIn == null ? null : System.currentTimeMillis() + expiresIn * MILLIS_PER_SECOND;
}
public void setTokenRequestBuilder(TokenRequestBuilder tokenRequestBuilder) { }
this.tokenRequestBuilder = tokenRequestBuilder;
}
public AuthenticationRequestBuilder getAuthenticationRequestBuilder() {
return authenticationRequestBuilder;
}
public void setAuthenticationRequestBuilder(AuthenticationRequestBuilder authenticationRequestBuilder) {
this.authenticationRequestBuilder = authenticationRequestBuilder;
}
public OAuthClient getOauthClient() {
return oauthClient;
}
public void setOauthClient(OAuthClient oauthClient) {
this.oauthClient = oauthClient;
}
public void setOauthClient(Client client) {
this.oauthClient = new OAuthClient( new OAuthFeignClient(client));
}
public static class OAuthFeignClient implements HttpClient {
private Client client;
public OAuthFeignClient() {
this.client = new Client.Default(null, null);
}
public OAuthFeignClient(Client client) {
this.client = client;
}
public <T extends OAuthClientResponse> T execute(OAuthClientRequest request, Map<String, String> headers,
String requestMethod, Class<T> responseClass)
throws OAuthSystemException, OAuthProblemException {
RequestTemplate req = new RequestTemplate()
.append(request.getLocationUri())
.method(requestMethod)
.body(request.getBody());
for (Entry<String, String> entry : headers.entrySet()) {
req.header(entry.getKey(), entry.getValue());
}
Response feignResponse;
String body = "";
try {
feignResponse = client.execute(req.request(), new Options());
body = Util.toString(feignResponse.body().asReader());
} catch (IOException e) {
throw new OAuthSystemException(e);
}
String contentType = null;
Collection<String> contentTypeHeader = feignResponse.headers().get("Content-Type");
if(contentTypeHeader != null) {
contentType = StringUtil.join(contentTypeHeader.toArray(new String[0]), ";");
}
return OAuthClientResponseFactory.createCustomResponse(
body,
contentType,
feignResponse.status(),
responseClass
);
}
public void shutdown() {
// Nothing to do here
}
}
}

View File

@ -13,6 +13,10 @@
package org.openapitools.client.auth; package org.openapitools.client.auth;
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen")
public enum OAuthFlow { public enum OAuthFlow {
accessCode, implicit, password, application accessCode, //called authorizationCode in OpenAPI 3.0
implicit,
password,
application //called clientCredentials in OpenAPI 3.0
} }

View File

@ -0,0 +1,39 @@
package org.openapitools.client.auth;
import com.github.scribejava.core.builder.ServiceBuilder;
import com.github.scribejava.core.model.OAuth2AccessToken;
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen")
public class OauthClientCredentialsGrant extends OAuth {
public OauthClientCredentialsGrant(String authorizationUrl, String tokenUrl, String scopes) {
super(authorizationUrl, tokenUrl, scopes);
}
@Override
protected OAuth2AccessToken getOAuth2AccessToken() {
try {
return service.getAccessTokenClientCredentialsGrant(scopes);
} catch (Exception e) {
throw new RuntimeException("Failed to get oauth token", e);
}
}
@Override
protected OAuthFlow getFlow() {
return OAuthFlow.application;
}
/**
* Configures the client credentials flow
*
* @param clientId
* @param clientSecret
*/
public void configure(String clientId, String clientSecret) {
service = new ServiceBuilder(clientId)
.apiSecret(clientSecret)
.defaultScope(scopes)
.build(new DefaultApi20Impl(authorizationUrl, tokenUrl));
}
}

View File

@ -0,0 +1,48 @@
package org.openapitools.client.auth;
import com.github.scribejava.core.builder.ServiceBuilder;
import com.github.scribejava.core.model.OAuth2AccessToken;
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen")
public class OauthPasswordGrant extends OAuth {
private String username;
private String password;
public OauthPasswordGrant(String tokenUrl, String scopes) {
super(null, tokenUrl, scopes);
}
@Override
protected OAuth2AccessToken getOAuth2AccessToken() {
try {
return service.getAccessTokenPasswordGrant(username, password);
} catch (Exception e) {
throw new RuntimeException("Failed to get oauth token", e);
}
}
@Override
protected OAuthFlow getFlow() {
return OAuthFlow.password;
}
/**
* Configures Oauth password grant flow
* Note: this flow is deprecated.
*
* @param username
* @param password
* @param clientId
* @param clientSecret
*/
public void configure(String username, String password, String clientId, String clientSecret) {
this.username = username;
this.password = password;
//TODO the clientId and secret are optional according with the RFC
service = new ServiceBuilder(clientId)
.apiSecret(clientSecret)
.defaultScope(scopes)
.build(new DefaultApi20Impl(authorizationUrl, tokenUrl));
}
}

View File

@ -28,10 +28,13 @@ src/main/java/org/openapitools/client/api/PetApi.java
src/main/java/org/openapitools/client/api/StoreApi.java src/main/java/org/openapitools/client/api/StoreApi.java
src/main/java/org/openapitools/client/api/UserApi.java src/main/java/org/openapitools/client/api/UserApi.java
src/main/java/org/openapitools/client/auth/ApiKeyAuth.java src/main/java/org/openapitools/client/auth/ApiKeyAuth.java
src/main/java/org/openapitools/client/auth/DefaultApi20Impl.java
src/main/java/org/openapitools/client/auth/HttpBasicAuth.java src/main/java/org/openapitools/client/auth/HttpBasicAuth.java
src/main/java/org/openapitools/client/auth/HttpBearerAuth.java src/main/java/org/openapitools/client/auth/HttpBearerAuth.java
src/main/java/org/openapitools/client/auth/OAuth.java src/main/java/org/openapitools/client/auth/OAuth.java
src/main/java/org/openapitools/client/auth/OAuthFlow.java src/main/java/org/openapitools/client/auth/OAuthFlow.java
src/main/java/org/openapitools/client/auth/OauthClientCredentialsGrant.java
src/main/java/org/openapitools/client/auth/OauthPasswordGrant.java
src/main/java/org/openapitools/client/model/AdditionalPropertiesAnyType.java src/main/java/org/openapitools/client/model/AdditionalPropertiesAnyType.java
src/main/java/org/openapitools/client/model/AdditionalPropertiesArray.java src/main/java/org/openapitools/client/model/AdditionalPropertiesArray.java
src/main/java/org/openapitools/client/model/AdditionalPropertiesBoolean.java src/main/java/org/openapitools/client/model/AdditionalPropertiesBoolean.java

View File

@ -32,6 +32,41 @@ After the client library is installed/deployed, you can use it in your Maven pro
``` ```
And to use the api you can follow the examples bellow:
```java
//Set bearer token manually
ApiClient apiClient = new ApiClient("petstore_auth_client");
apiClient.setBasePath("https://localhost:8243/petstore/1/");
apiClient.setAccessToken("TOKEN", 10000);
//Use api key
ApiClient apiClient = new ApiClient("api_key", "API KEY");
apiClient.setBasePath("https://localhost:8243/petstore/1/");
//Use http basic authentication
ApiClient apiClient = new ApiClient("basicAuth");
apiClient.setBasePath("https://localhost:8243/petstore/1/");
apiClient.setCredentials("username", "password");
//Oauth password
ApiClient apiClient = new ApiClient("oauth_password");
apiClient.setBasePath("https://localhost:8243/petstore/1/");
apiClient.setOauthPassword("username", "password", "client_id", "client_secret");
//Oauth client credentials flow
ApiClient apiClient = new ApiClient("oauth_client_credentials");
apiClient.setBasePath("https://localhost:8243/petstore/1/");
apiClient.setClientCredentials("client_id", "client_secret");
PetApi petApi = apiClient.buildClient(PetApi.class);
Pet petById = petApi.getPetById(12345L);
System.out.println(petById);
}
```
## Recommendation ## Recommendation
It's recommended to create an instance of `ApiClient` per thread in a multithreaded environment to avoid any potential issues. It's recommended to create an instance of `ApiClient` per thread in a multithreaded environment to avoid any potential issues.
@ -40,4 +75,3 @@ It's recommended to create an instance of `ApiClient` per thread in a multithrea

View File

@ -33,8 +33,8 @@ if(hasProperty('target') && target == 'android') {
targetSdkVersion 25 targetSdkVersion 25
} }
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_8
} }
// Rename the aar correctly // Rename the aar correctly
@ -79,8 +79,8 @@ if(hasProperty('target') && target == 'android') {
apply plugin: 'java' apply plugin: 'java'
apply plugin: 'maven' apply plugin: 'maven'
sourceCompatibility = JavaVersion.VERSION_1_7 sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_7 targetCompatibility = JavaVersion.VERSION_1_8
install { install {
repositories.mavenInstaller { repositories.mavenInstaller {
@ -103,7 +103,7 @@ ext {
feign_version = "10.11" feign_version = "10.11"
feign_form_version = "3.8.0" feign_form_version = "3.8.0"
junit_version = "4.13.1" junit_version = "4.13.1"
oltu_version = "1.0.1" scribejava_version = "8.0.0"
} }
dependencies { dependencies {
@ -118,7 +118,8 @@ dependencies {
implementation "com.fasterxml.jackson.core:jackson-databind:$jackson_databind_version" implementation "com.fasterxml.jackson.core:jackson-databind:$jackson_databind_version"
implementation "org.openapitools:jackson-databind-nullable:$jackson_databind_nullable_version" implementation "org.openapitools:jackson-databind-nullable:$jackson_databind_nullable_version"
implementation "com.github.joschi.jackson:jackson-datatype-threetenbp:$jackson_threetenbp_version" implementation "com.github.joschi.jackson:jackson-datatype-threetenbp:$jackson_threetenbp_version"
implementation "org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:$oltu_version" implementation "com.brsanthu:migbase64:2.2"
implementation "com.github.scribejava:scribejava-core:$scribejava_version"
implementation "com.brsanthu:migbase64:2.2" implementation "com.brsanthu:migbase64:2.2"
implementation 'javax.annotation:javax.annotation-api:1.3.2' implementation 'javax.annotation:javax.annotation-api:1.3.2'
testImplementation "junit:junit:$junit_version" testImplementation "junit:junit:$junit_version"

View File

@ -19,7 +19,7 @@ lazy val root = (project in file(".")).
"com.fasterxml.jackson.core" % "jackson-databind" % "2.10.3" % "compile", "com.fasterxml.jackson.core" % "jackson-databind" % "2.10.3" % "compile",
"com.fasterxml.jackson.datatype" % "jackson-datatype-joda" % "2.9.10" % "compile", "com.fasterxml.jackson.datatype" % "jackson-datatype-joda" % "2.9.10" % "compile",
"com.github.joschi.jackson" % "jackson-datatype-threetenbp" % "2.9.10" % "compile", "com.github.joschi.jackson" % "jackson-datatype-threetenbp" % "2.9.10" % "compile",
"org.apache.oltu.oauth2" % "org.apache.oltu.oauth2.client" % "1.0.1" % "compile", "com.github.scribejava" % "scribejava-core" % "8.0.0" % "compile",
"com.brsanthu" % "migbase64" % "2.2" % "compile", "com.brsanthu" % "migbase64" % "2.2" % "compile",
"javax.annotation" % "javax.annotation-api" % "1.3.2" % "compile", "javax.annotation" % "javax.annotation-api" % "1.3.2" % "compile",
"junit" % "junit" % "4.13.1" % "test", "junit" % "junit" % "4.13.1" % "test",

View File

@ -154,7 +154,7 @@
<version>3.1.1</version> <version>3.1.1</version>
<configuration> <configuration>
<doclint>none</doclint> <doclint>none</doclint>
<source>1.7</source> <source>1.8</source>
</configuration> </configuration>
<executions> <executions>
<execution> <execution>
@ -262,15 +262,15 @@
<artifactId>jackson-databind-nullable</artifactId> <artifactId>jackson-databind-nullable</artifactId>
<version>${jackson-databind-nullable-version}</version> <version>${jackson-databind-nullable-version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.github.joschi.jackson</groupId>
<artifactId>jackson-datatype-threetenbp</artifactId>
<version>${jackson-threetenbp-version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.apache.oltu.oauth2</groupId> <groupId>com.github.joschi.jackson</groupId>
<artifactId>org.apache.oltu.oauth2.client</artifactId> <artifactId>jackson-datatype-threetenbp</artifactId>
<version>${oltu-version}</version> <version>${jackson-threetenbp-version}</version>
</dependency>
<dependency>
<groupId>com.github.scribejava</groupId>
<artifactId>scribejava-core</artifactId>
<version>${scribejava-version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>javax.annotation</groupId> <groupId>javax.annotation</groupId>
@ -301,7 +301,7 @@
</dependencies> </dependencies>
<properties> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.7</java.version> <java.version>1.8</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source> <maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target> <maven.compiler.target>${java.version}</maven.compiler.target>
<swagger-annotations-version>1.5.24</swagger-annotations-version> <swagger-annotations-version>1.5.24</swagger-annotations-version>
@ -314,6 +314,6 @@
<javax-annotation-version>1.3.2</javax-annotation-version> <javax-annotation-version>1.3.2</javax-annotation-version>
<junit-version>4.13.1</junit-version> <junit-version>4.13.1</junit-version>
<maven-plugin-version>1.0.0</maven-plugin-version> <maven-plugin-version>1.0.0</maven-plugin-version>
<oltu-version>1.0.1</oltu-version> <scribejava-version>8.0.0</scribejava-version>
</properties> </properties>
</project> </project>

View File

@ -2,9 +2,8 @@ package org.openapitools.client;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.logging.Level;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest.AuthenticationRequestBuilder; import java.util.logging.Logger;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest.TokenRequestBuilder;
import org.threeten.bp.*; import org.threeten.bp.*;
@ -25,6 +24,8 @@ import org.openapitools.client.auth.OAuth.AccessTokenListener;
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen") @javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen")
public class ApiClient { public class ApiClient {
private static final Logger log = Logger.getLogger(ApiClient.class.getName());
public interface Api {} public interface Api {}
protected ObjectMapper objectMapper; protected ObjectMapper objectMapper;
@ -44,6 +45,7 @@ public class ApiClient {
public ApiClient(String[] authNames) { public ApiClient(String[] authNames) {
this(); this();
for(String authName : authNames) { for(String authName : authNames) {
log.log(Level.FINE, "Creating authentication {0}", authName);
RequestInterceptor auth; RequestInterceptor auth;
if ("api_key".equals(authName)) { if ("api_key".equals(authName)) {
auth = new ApiKeyAuth("header", "api_key"); auth = new ApiKeyAuth("header", "api_key");
@ -52,7 +54,7 @@ public class ApiClient {
} else if ("http_basic_test".equals(authName)) { } else if ("http_basic_test".equals(authName)) {
auth = new HttpBasicAuth(); auth = new HttpBasicAuth();
} else if ("petstore_auth".equals(authName)) { } else if ("petstore_auth".equals(authName)) {
auth = new OAuth(OAuthFlow.implicit, "http://petstore.swagger.io/api/oauth/dialog", "", "write:pets, read:pets"); auth = buildOauthRequestInterceptor(OAuthFlow.implicit, "http://petstore.swagger.io/api/oauth/dialog", "", "write:pets, read:pets");
} else { } else {
throw new RuntimeException("auth name \"" + authName + "\" not found in available auth names"); throw new RuntimeException("auth name \"" + authName + "\" not found in available auth names");
} }
@ -78,34 +80,6 @@ public class ApiClient {
this.setApiKey(apiKey); this.setApiKey(apiKey);
} }
/**
* Helper constructor for single basic auth or password oauth2
* @param authName
* @param username
* @param password
*/
public ApiClient(String authName, String username, String password) {
this(authName);
this.setCredentials(username, password);
}
/**
* Helper constructor for single password oauth2
* @param authName
* @param clientId
* @param secret
* @param username
* @param password
*/
public ApiClient(String authName, String clientId, String secret, String username, String password) {
this(authName);
this.getTokenEndPoint()
.setClientId(clientId)
.setClientSecret(secret)
.setUsername(username)
.setPassword(password);
}
public String getBasePath() { public String getBasePath() {
return basePath; return basePath;
} }
@ -150,10 +124,25 @@ public class ApiClient {
return objectMapper; return objectMapper;
} }
private RequestInterceptor buildOauthRequestInterceptor(OAuthFlow flow, String authorizationUrl, String tokenUrl, String scopes) {
switch (flow) {
case password:
return new OauthPasswordGrant(tokenUrl, scopes);
case application:
return new OauthClientCredentialsGrant(authorizationUrl, tokenUrl, scopes);
default:
throw new RuntimeException("Oauth flow \"" + flow + "\" is not implemented");
}
}
public ObjectMapper getObjectMapper(){ public ObjectMapper getObjectMapper(){
return objectMapper; return objectMapper;
} }
public void setObjectMapper(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
/** /**
* Creates a feign client for given API interface. * Creates a feign client for given API interface.
* *
@ -200,19 +189,13 @@ public class ApiClient {
return contentTypes[0]; return contentTypes[0];
} }
/** /**
* Helper method to configure the bearer token. * Helper method to configure the bearer token.
* @param bearerToken the bearer token. * @param bearerToken the bearer token.
*/ */
public void setBearerToken(String bearerToken) { public void setBearerToken(String bearerToken) {
for(RequestInterceptor apiAuthorization : apiAuthorizations.values()) { HttpBearerAuth apiAuthorization = getAuthorization(HttpBearerAuth.class);
if (apiAuthorization instanceof HttpBearerAuth) { apiAuthorization.setBearerToken(bearerToken);
((HttpBearerAuth) apiAuthorization).setBearerToken(bearerToken);
return;
}
}
throw new RuntimeException("No Bearer authentication configured!");
} }
/** /**
@ -220,63 +203,38 @@ public class ApiClient {
* @param apiKey API key * @param apiKey API key
*/ */
public void setApiKey(String apiKey) { public void setApiKey(String apiKey) {
for(RequestInterceptor apiAuthorization : apiAuthorizations.values()) { ApiKeyAuth apiAuthorization = getAuthorization(ApiKeyAuth.class);
if (apiAuthorization instanceof ApiKeyAuth) { apiAuthorization.setApiKey(apiKey);
ApiKeyAuth keyAuth = (ApiKeyAuth) apiAuthorization;
keyAuth.setApiKey(apiKey);
return ;
}
}
throw new RuntimeException("No API key authentication configured!");
} }
/** /**
* Helper method to configure the username/password for basic auth or password OAuth * Helper method to configure the username/password for basic auth
* @param username Username * @param username Username
* @param password Password * @param password Password
*/ */
public void setCredentials(String username, String password) { public void setCredentials(String username, String password) {
for(RequestInterceptor apiAuthorization : apiAuthorizations.values()) { HttpBasicAuth apiAuthorization = getAuthorization(HttpBasicAuth.class);
if (apiAuthorization instanceof HttpBasicAuth) { apiAuthorization.setCredentials(username, password);
HttpBasicAuth basicAuth = (HttpBasicAuth) apiAuthorization;
basicAuth.setCredentials(username, password);
return;
}
if (apiAuthorization instanceof OAuth) {
OAuth oauth = (OAuth) apiAuthorization;
oauth.getTokenRequestBuilder().setUsername(username).setPassword(password);
return;
}
}
throw new RuntimeException("No Basic authentication or OAuth configured!");
} }
/** /**
* Helper method to configure the token endpoint of the first oauth found in the apiAuthorizations (there should be only one) * Helper method to configure the client credentials for Oauth
* @return Token request builder * @param username Username
* @param password Password
*/ */
public TokenRequestBuilder getTokenEndPoint() { public void setClientCredentials(String clientId, String clientSecret) {
for(RequestInterceptor apiAuthorization : apiAuthorizations.values()) { OauthClientCredentialsGrant authorization = getAuthorization(OauthClientCredentialsGrant.class);
if (apiAuthorization instanceof OAuth) { authorization.configure(clientId, clientSecret);
OAuth oauth = (OAuth) apiAuthorization;
return oauth.getTokenRequestBuilder();
}
}
return null;
} }
/** /**
* Helper method to configure authorization endpoint of the first oauth found in the apiAuthorizations (there should be only one) * Helper method to configure the username/password for Oauth password grant
* @return Authentication request builder * @param username Username
* @param password Password
*/ */
public AuthenticationRequestBuilder getAuthorizationEndPoint() { public void setOauthPassword(String username, String password, String clientId, String clientSecret) {
for(RequestInterceptor apiAuthorization : apiAuthorizations.values()) { OauthPasswordGrant apiAuthorization = getAuthorization(OauthPasswordGrant.class);
if (apiAuthorization instanceof OAuth) { apiAuthorization.configure(username, password, clientId, clientSecret);
OAuth oauth = (OAuth) apiAuthorization;
return oauth.getAuthenticationRequestBuilder();
}
}
return null;
} }
/** /**
@ -284,14 +242,9 @@ public class ApiClient {
* @param accessToken Access Token * @param accessToken Access Token
* @param expiresIn Validity period in seconds * @param expiresIn Validity period in seconds
*/ */
public void setAccessToken(String accessToken, Long expiresIn) { public void setAccessToken(String accessToken, Integer expiresIn) {
for(RequestInterceptor apiAuthorization : apiAuthorizations.values()) { OAuth apiAuthorization = getAuthorization(OAuth.class);
if (apiAuthorization instanceof OAuth) { apiAuthorization.setAccessToken(accessToken, expiresIn);
OAuth oauth = (OAuth) apiAuthorization;
oauth.setAccessToken(accessToken, expiresIn);
return;
}
}
} }
/** /**
@ -301,19 +254,7 @@ public class ApiClient {
* @param redirectURI Redirect URI * @param redirectURI Redirect URI
*/ */
public void configureAuthorizationFlow(String clientId, String clientSecret, String redirectURI) { public void configureAuthorizationFlow(String clientId, String clientSecret, String redirectURI) {
for(RequestInterceptor apiAuthorization : apiAuthorizations.values()) { throw new RuntimeException("Not implemented");
if (apiAuthorization instanceof OAuth) {
OAuth oauth = (OAuth) apiAuthorization;
oauth.getTokenRequestBuilder()
.setClientId(clientId)
.setClientSecret(clientSecret)
.setRedirectURI(redirectURI);
oauth.getAuthenticationRequestBuilder()
.setClientId(clientId)
.setRedirectURI(redirectURI);
return;
}
}
} }
/** /**
@ -321,13 +262,8 @@ public class ApiClient {
* @param accessTokenListener Acesss token listener * @param accessTokenListener Acesss token listener
*/ */
public void registerAccessTokenListener(AccessTokenListener accessTokenListener) { public void registerAccessTokenListener(AccessTokenListener accessTokenListener) {
for(RequestInterceptor apiAuthorization : apiAuthorizations.values()) { OAuth apiAuthorization = getAuthorization(OAuth.class);
if (apiAuthorization instanceof OAuth) { apiAuthorization.registerAccessTokenListener(accessTokenListener);
OAuth oauth = (OAuth) apiAuthorization;
oauth.registerAccessTokenListener(accessTokenListener);
return;
}
}
} }
/** /**
@ -352,4 +288,11 @@ public class ApiClient {
feignBuilder.requestInterceptor(authorization); feignBuilder.requestInterceptor(authorization);
} }
private <T extends RequestInterceptor> T getAuthorization(Class<T> type) {
return (T) apiAuthorizations.values()
.stream()
.filter(requestInterceptor -> type.isAssignableFrom(requestInterceptor.getClass()))
.findFirst()
.orElseThrow(() -> new RuntimeException("No Oauth authentication or OAuth configured!"));
}
} }

View File

@ -0,0 +1,47 @@
package org.openapitools.client.auth;
import com.github.scribejava.core.builder.api.DefaultApi20;
import com.github.scribejava.core.extractors.OAuth2AccessTokenJsonExtractor;
import com.github.scribejava.core.extractors.TokenExtractor;
import com.github.scribejava.core.model.OAuth2AccessToken;
import com.github.scribejava.core.oauth2.bearersignature.BearerSignature;
import com.github.scribejava.core.oauth2.bearersignature.BearerSignatureURIQueryParameter;
import com.github.scribejava.core.oauth2.clientauthentication.ClientAuthentication;
import com.github.scribejava.core.oauth2.clientauthentication.RequestBodyAuthenticationScheme;
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen")
public class DefaultApi20Impl extends DefaultApi20 {
private final String accessTokenEndpoint;
private final String authorizationBaseUrl;
protected DefaultApi20Impl(String authorizationBaseUrl, String accessTokenEndpoint) {
this.authorizationBaseUrl = authorizationBaseUrl;
this.accessTokenEndpoint = accessTokenEndpoint;
}
@Override
public String getAccessTokenEndpoint() {
return accessTokenEndpoint;
}
@Override
protected String getAuthorizationBaseUrl() {
return authorizationBaseUrl;
}
@Override
public BearerSignature getBearerSignature() {
return BearerSignatureURIQueryParameter.instance();
}
@Override
public ClientAuthentication getClientAuthentication() {
return RequestBodyAuthenticationScheme.instance();
}
@Override
public TokenExtractor<OAuth2AccessToken> getAccessTokenExtractor() {
return OAuth2AccessTokenJsonExtractor.instance();
}
}

View File

@ -1,198 +1,81 @@
package org.openapitools.client.auth; package org.openapitools.client.auth;
import java.io.IOException; import com.github.scribejava.core.model.OAuth2AccessToken;
import java.util.Collection; import com.github.scribejava.core.oauth.OAuth20Service;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.oltu.oauth2.client.HttpClient;
import org.apache.oltu.oauth2.client.OAuthClient;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest.AuthenticationRequestBuilder;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest.TokenRequestBuilder;
import org.apache.oltu.oauth2.client.response.OAuthClientResponse;
import org.apache.oltu.oauth2.client.response.OAuthClientResponseFactory;
import org.apache.oltu.oauth2.client.response.OAuthJSONAccessTokenResponse;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.types.GrantType;
import org.apache.oltu.oauth2.common.token.BasicOAuthToken;
import feign.Client;
import feign.Request.HttpMethod; import feign.Request.HttpMethod;
import feign.Request.Options;
import feign.RequestInterceptor; import feign.RequestInterceptor;
import feign.RequestTemplate; import feign.RequestTemplate;
import feign.Response;
import feign.RetryableException; import feign.RetryableException;
import feign.Util;
import org.openapitools.client.StringUtil;
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen")
public abstract class OAuth implements RequestInterceptor {
public class OAuth implements RequestInterceptor { static final int MILLIS_PER_SECOND = 1000;
static final int MILLIS_PER_SECOND = 1000; public interface AccessTokenListener {
void notify(OAuth2AccessToken token);
}
public interface AccessTokenListener { private volatile String accessToken;
void notify(BasicOAuthToken token); private Long expirationTimeMillis;
private AccessTokenListener accessTokenListener;
protected OAuth20Service service;
protected String scopes;
protected String authorizationUrl;
protected String tokenUrl;
public OAuth(String authorizationUrl, String tokenUrl, String scopes) {
this.scopes = scopes;
this.authorizationUrl = authorizationUrl;
this.tokenUrl = tokenUrl;
}
@Override
public void apply(RequestTemplate template) {
// If the request already have an authorization (eg. Basic auth), do nothing
if (template.headers().containsKey("Authorization")) {
return;
} }
// If first time, get the token
private volatile String accessToken; if (expirationTimeMillis == null || System.currentTimeMillis() >= expirationTimeMillis) {
private Long expirationTimeMillis; updateAccessToken(template);
private OAuthClient oauthClient;
private TokenRequestBuilder tokenRequestBuilder;
private AuthenticationRequestBuilder authenticationRequestBuilder;
private AccessTokenListener accessTokenListener;
public OAuth(Client client, TokenRequestBuilder requestBuilder) {
this.oauthClient = new OAuthClient(new OAuthFeignClient(client));
this.tokenRequestBuilder = requestBuilder;
} }
if (getAccessToken() != null) {
public OAuth(Client client, OAuthFlow flow, String authorizationUrl, String tokenUrl, String scopes) { template.header("Authorization", "Bearer " + getAccessToken());
this(client, OAuthClientRequest.tokenLocation(tokenUrl).setScope(scopes));
switch(flow) {
case accessCode:
case implicit:
tokenRequestBuilder.setGrantType(GrantType.AUTHORIZATION_CODE);
break;
case password:
tokenRequestBuilder.setGrantType(GrantType.PASSWORD);
break;
case application:
tokenRequestBuilder.setGrantType(GrantType.CLIENT_CREDENTIALS);
break;
default:
break;
}
authenticationRequestBuilder = OAuthClientRequest.authorizationLocation(authorizationUrl);
} }
}
public OAuth(OAuthFlow flow, String authorizationUrl, String tokenUrl, String scopes) { private synchronized void updateAccessToken(RequestTemplate template) {
this(new Client.Default(null, null), flow, authorizationUrl, tokenUrl, scopes); OAuth2AccessToken accessTokenResponse;
try {
accessTokenResponse = getOAuth2AccessToken();
} catch (Exception e) {
throw new RetryableException(0, e.getMessage(), HttpMethod.POST, e, null, template.request());
} }
if (accessTokenResponse != null && accessTokenResponse.getAccessToken() != null) {
@Override setAccessToken(accessTokenResponse.getAccessToken(), accessTokenResponse.getExpiresIn());
public void apply(RequestTemplate template) { if (accessTokenListener != null) {
// If the request already have an authorization (eg. Basic auth), do nothing accessTokenListener.notify(accessTokenResponse);
if (template.headers().containsKey("Authorization")) { }
return;
}
// If first time, get the token
if (expirationTimeMillis == null || System.currentTimeMillis() >= expirationTimeMillis) {
updateAccessToken(template);
}
if (getAccessToken() != null) {
template.header("Authorization", "Bearer " + getAccessToken());
}
} }
}
public synchronized void updateAccessToken(RequestTemplate template) { abstract OAuth2AccessToken getOAuth2AccessToken();
OAuthJSONAccessTokenResponse accessTokenResponse;
try {
accessTokenResponse = oauthClient.accessToken(tokenRequestBuilder.buildBodyMessage());
} catch (Exception e) {
throw new RetryableException(0, e.getMessage(), HttpMethod.POST, e, null, template.request());
}
if (accessTokenResponse != null && accessTokenResponse.getAccessToken() != null) {
setAccessToken(accessTokenResponse.getAccessToken(), accessTokenResponse.getExpiresIn());
if (accessTokenListener != null) {
accessTokenListener.notify((BasicOAuthToken) accessTokenResponse.getOAuthToken());
}
}
}
public synchronized void registerAccessTokenListener(AccessTokenListener accessTokenListener) { abstract OAuthFlow getFlow();
this.accessTokenListener = accessTokenListener;
}
public synchronized String getAccessToken() { public synchronized void registerAccessTokenListener(AccessTokenListener accessTokenListener) {
return accessToken; this.accessTokenListener = accessTokenListener;
} }
public synchronized void setAccessToken(String accessToken, Long expiresIn) { public synchronized String getAccessToken() {
this.accessToken = accessToken; return accessToken;
this.expirationTimeMillis = expiresIn == null ? null : System.currentTimeMillis() + expiresIn * MILLIS_PER_SECOND; }
}
public TokenRequestBuilder getTokenRequestBuilder() { public synchronized void setAccessToken(String accessToken, Integer expiresIn) {
return tokenRequestBuilder; this.accessToken = accessToken;
} this.expirationTimeMillis = expiresIn == null ? null : System.currentTimeMillis() + expiresIn * MILLIS_PER_SECOND;
}
public void setTokenRequestBuilder(TokenRequestBuilder tokenRequestBuilder) { }
this.tokenRequestBuilder = tokenRequestBuilder;
}
public AuthenticationRequestBuilder getAuthenticationRequestBuilder() {
return authenticationRequestBuilder;
}
public void setAuthenticationRequestBuilder(AuthenticationRequestBuilder authenticationRequestBuilder) {
this.authenticationRequestBuilder = authenticationRequestBuilder;
}
public OAuthClient getOauthClient() {
return oauthClient;
}
public void setOauthClient(OAuthClient oauthClient) {
this.oauthClient = oauthClient;
}
public void setOauthClient(Client client) {
this.oauthClient = new OAuthClient( new OAuthFeignClient(client));
}
public static class OAuthFeignClient implements HttpClient {
private Client client;
public OAuthFeignClient() {
this.client = new Client.Default(null, null);
}
public OAuthFeignClient(Client client) {
this.client = client;
}
public <T extends OAuthClientResponse> T execute(OAuthClientRequest request, Map<String, String> headers,
String requestMethod, Class<T> responseClass)
throws OAuthSystemException, OAuthProblemException {
RequestTemplate req = new RequestTemplate()
.append(request.getLocationUri())
.method(requestMethod)
.body(request.getBody());
for (Entry<String, String> entry : headers.entrySet()) {
req.header(entry.getKey(), entry.getValue());
}
Response feignResponse;
String body = "";
try {
feignResponse = client.execute(req.request(), new Options());
body = Util.toString(feignResponse.body().asReader());
} catch (IOException e) {
throw new OAuthSystemException(e);
}
String contentType = null;
Collection<String> contentTypeHeader = feignResponse.headers().get("Content-Type");
if(contentTypeHeader != null) {
contentType = StringUtil.join(contentTypeHeader.toArray(new String[0]), ";");
}
return OAuthClientResponseFactory.createCustomResponse(
body,
contentType,
feignResponse.status(),
responseClass
);
}
public void shutdown() {
// Nothing to do here
}
}
}

View File

@ -13,6 +13,10 @@
package org.openapitools.client.auth; package org.openapitools.client.auth;
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen")
public enum OAuthFlow { public enum OAuthFlow {
accessCode, implicit, password, application accessCode, //called authorizationCode in OpenAPI 3.0
implicit,
password,
application //called clientCredentials in OpenAPI 3.0
} }

View File

@ -0,0 +1,39 @@
package org.openapitools.client.auth;
import com.github.scribejava.core.builder.ServiceBuilder;
import com.github.scribejava.core.model.OAuth2AccessToken;
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen")
public class OauthClientCredentialsGrant extends OAuth {
public OauthClientCredentialsGrant(String authorizationUrl, String tokenUrl, String scopes) {
super(authorizationUrl, tokenUrl, scopes);
}
@Override
protected OAuth2AccessToken getOAuth2AccessToken() {
try {
return service.getAccessTokenClientCredentialsGrant(scopes);
} catch (Exception e) {
throw new RuntimeException("Failed to get oauth token", e);
}
}
@Override
protected OAuthFlow getFlow() {
return OAuthFlow.application;
}
/**
* Configures the client credentials flow
*
* @param clientId
* @param clientSecret
*/
public void configure(String clientId, String clientSecret) {
service = new ServiceBuilder(clientId)
.apiSecret(clientSecret)
.defaultScope(scopes)
.build(new DefaultApi20Impl(authorizationUrl, tokenUrl));
}
}

View File

@ -0,0 +1,48 @@
package org.openapitools.client.auth;
import com.github.scribejava.core.builder.ServiceBuilder;
import com.github.scribejava.core.model.OAuth2AccessToken;
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen")
public class OauthPasswordGrant extends OAuth {
private String username;
private String password;
public OauthPasswordGrant(String tokenUrl, String scopes) {
super(null, tokenUrl, scopes);
}
@Override
protected OAuth2AccessToken getOAuth2AccessToken() {
try {
return service.getAccessTokenPasswordGrant(username, password);
} catch (Exception e) {
throw new RuntimeException("Failed to get oauth token", e);
}
}
@Override
protected OAuthFlow getFlow() {
return OAuthFlow.password;
}
/**
* Configures Oauth password grant flow
* Note: this flow is deprecated.
*
* @param username
* @param password
* @param clientId
* @param clientSecret
*/
public void configure(String username, String password, String clientId, String clientSecret) {
this.username = username;
this.password = password;
//TODO the clientId and secret are optional according with the RFC
service = new ServiceBuilder(clientId)
.apiSecret(clientSecret)
.defaultScope(scopes)
.build(new DefaultApi20Impl(authorizationUrl, tokenUrl));
}
}

View File

@ -13,6 +13,10 @@
package org.openapitools.client.auth; package org.openapitools.client.auth;
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen")
public enum OAuthFlow { public enum OAuthFlow {
accessCode, implicit, password, application accessCode, //called authorizationCode in OpenAPI 3.0
implicit,
password,
application //called clientCredentials in OpenAPI 3.0
} }

View File

@ -13,6 +13,10 @@
package org.openapitools.client.auth; package org.openapitools.client.auth;
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen")
public enum OAuthFlow { public enum OAuthFlow {
accessCode, implicit, password, application accessCode, //called authorizationCode in OpenAPI 3.0
implicit,
password,
application //called clientCredentials in OpenAPI 3.0
} }

View File

@ -13,6 +13,10 @@
package org.openapitools.client.auth; package org.openapitools.client.auth;
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen")
public enum OAuthFlow { public enum OAuthFlow {
accessCode, implicit, password, application accessCode, //called authorizationCode in OpenAPI 3.0
implicit,
password,
application //called clientCredentials in OpenAPI 3.0
} }

View File

@ -13,6 +13,10 @@
package org.openapitools.client.auth; package org.openapitools.client.auth;
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen")
public enum OAuthFlow { public enum OAuthFlow {
accessCode, implicit, password, application accessCode, //called authorizationCode in OpenAPI 3.0
implicit,
password,
application //called clientCredentials in OpenAPI 3.0
} }

View File

@ -13,6 +13,10 @@
package org.openapitools.client.auth; package org.openapitools.client.auth;
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen")
public enum OAuthFlow { public enum OAuthFlow {
accessCode, implicit, password, application accessCode, //called authorizationCode in OpenAPI 3.0
implicit,
password,
application //called clientCredentials in OpenAPI 3.0
} }

View File

@ -13,6 +13,10 @@
package org.openapitools.client.auth; package org.openapitools.client.auth;
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen")
public enum OAuthFlow { public enum OAuthFlow {
accessCode, implicit, password, application accessCode, //called authorizationCode in OpenAPI 3.0
implicit,
password,
application //called clientCredentials in OpenAPI 3.0
} }

View File

@ -13,6 +13,10 @@
package org.openapitools.client.auth; package org.openapitools.client.auth;
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen")
public enum OAuthFlow { public enum OAuthFlow {
accessCode, implicit, password, application accessCode, //called authorizationCode in OpenAPI 3.0
implicit,
password,
application //called clientCredentials in OpenAPI 3.0
} }

View File

@ -13,6 +13,10 @@
package org.openapitools.client.auth; package org.openapitools.client.auth;
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen")
public enum OAuthFlow { public enum OAuthFlow {
accessCode, implicit, password, application accessCode, //called authorizationCode in OpenAPI 3.0
implicit,
password,
application //called clientCredentials in OpenAPI 3.0
} }

View File

@ -1,131 +1,131 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent> <parent>
<artifactId>oss-parent</artifactId> <artifactId>oss-parent</artifactId>
<groupId>org.sonatype.oss</groupId> <groupId>org.sonatype.oss</groupId>
<version>5</version> <version>5</version>
<relativePath>../pom.xml/pom.xml</relativePath> <relativePath>../pom.xml/pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>org.openapitools</groupId> <groupId>org.openapitools</groupId>
<artifactId>openapi-undertow-server</artifactId> <artifactId>openapi-undertow-server</artifactId>
<name>openapi-undertow-server</name> <name>openapi-undertow-server</name>
<version>1.0.0</version> <version>1.0.0</version>
<build> <build>
<defaultGoal>install</defaultGoal> <defaultGoal>install</defaultGoal>
<directory>target</directory> <directory>target</directory>
<finalName>${project.artifactId}-${project.version}</finalName> <finalName>${project.artifactId}-${project.version}</finalName>
<plugins> <plugins>
<plugin> <plugin>
<artifactId>maven-enforcer-plugin</artifactId> <artifactId>maven-enforcer-plugin</artifactId>
<version>3.0.0-M1</version> <version>3.0.0-M1</version>
<executions> <executions>
<execution> <execution>
<id>enforce-maven</id> <id>enforce-maven</id>
<goals> <goals>
<goal>enforce</goal> <goal>enforce</goal>
</goals> </goals>
<configuration> <configuration>
<rules> <rules>
<requireMavenVersion> <requireMavenVersion>
<version>2.2.0</version> <version>2.2.0</version>
</requireMavenVersion> </requireMavenVersion>
</rules> </rules>
</configuration> </configuration>
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin> <plugin>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version> <version>2.4.3</version>
<executions> <executions>
<execution> <execution>
<phase>package</phase> <phase>package</phase>
<goals> <goals>
<goal>shade</goal> <goal>shade</goal>
</goals> </goals>
<configuration> <configuration>
<transformers> <transformers>
<transformer /> <transformer />
</transformers> </transformers>
</configuration> </configuration>
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin> <plugin>
<artifactId>maven-jar-plugin</artifactId> <artifactId>maven-jar-plugin</artifactId>
<version>2.6</version> <version>2.6</version>
<configuration> <configuration>
<archive> <archive>
<manifest> <manifest>
<mainClass>com.networknt.server.Server</mainClass> <mainClass>com.networknt.server.Server</mainClass>
</manifest> </manifest>
</archive> </archive>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.codehaus.mojo</groupId> <groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId> <artifactId>exec-maven-plugin</artifactId>
<version>1.4.0</version> <version>1.4.0</version>
<configuration> <configuration>
<executable>java</executable> <executable>java</executable>
<arguments> <arguments>
<argument>-jar</argument> <argument>-jar</argument>
<argument>target/${project.build.finalName}.jar</argument> <argument>target/${project.build.finalName}.jar</argument>
</arguments> </arguments>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
<repositories> <repositories>
<repository> <repository>
<snapshots /> <snapshots />
<id>sonatype-snapshots</id> <id>sonatype-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url> <url>https://oss.sonatype.org/content/repositories/snapshots</url>
</repository> </repository>
</repositories> </repositories>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<version>4.13</version> <version>4.13</version>
<scope>test</scope> <scope>test</scope>
<exclusions> <exclusions>
<exclusion> <exclusion>
<artifactId>hamcrest-core</artifactId> <artifactId>hamcrest-core</artifactId>
<groupId>org.hamcrest</groupId> <groupId>org.hamcrest</groupId>
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.httpcomponents</groupId> <groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId> <artifactId>httpclient</artifactId>
<version>4.5.2</version> <version>4.5.2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<properties> <properties>
<version.httpasyncclient>4.1.2</version.httpasyncclient> <version.httpasyncclient>4.1.2</version.httpasyncclient>
<version.jackson.databind>2.9.10.4</version.jackson.databind> <version.jackson.databind>2.9.10.4</version.jackson.databind>
<version.jsonpath>2.2.0</version.jsonpath> <version.jsonpath>2.2.0</version.jsonpath>
<version.commons.codec>1.10</version.commons.codec> <version.commons.codec>1.10</version.commons.codec>
<version.metrics>3.1.2</version.metrics> <version.metrics>3.1.2</version.metrics>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<version.encoder>1.2</version.encoder> <version.encoder>1.2</version.encoder>
<version.httpclient>4.5.2</version.httpclient> <version.httpclient>4.5.2</version.httpclient>
<version.undertow>1.4.0.Final</version.undertow> <version.undertow>1.4.0.Final</version.undertow>
<version.jose4j>0.5.2</version.jose4j> <version.jose4j>0.5.2</version.jose4j>
<version.commons-lang>2.6</version.commons-lang> <version.commons-lang>2.6</version.commons-lang>
<java.version>1.8</java.version> <java.version>1.8</java.version>
<version.jackson>2.9.10</version.jackson> <version.jackson>2.9.10</version.jackson>
<version.framework>0.1.1</version.framework> <version.framework>0.1.1</version.framework>
<version.swagger>1.5.10</version.swagger> <version.swagger>1.5.10</version.swagger>
<version.mockito>2.1.0-beta.124</version.mockito> <version.mockito>2.1.0-beta.124</version.mockito>
<version.slf4j>1.7.21</version.slf4j> <version.slf4j>1.7.21</version.slf4j>
<version.commons.io>2.5</version.commons.io> <version.commons.io>2.5</version.commons.io>
<version.logback>1.1.7</version.logback> <version.logback>1.1.7</version.logback>
<version.junit>4.13</version.junit> <version.junit>4.13</version.junit>
<version.antlr4>4.5.3</version.antlr4> <version.antlr4>4.5.3</version.antlr4>
</properties> </properties>
</project> </project>