parent
a45820e845
commit
934de80796
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 - 2024, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (Pvt) Ltd. licenses this file to you under the Apache License,
|
||||||
|
* Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.entgra.device.mgt.core.apimgt.extension.rest.api;
|
||||||
|
|
||||||
|
import io.entgra.device.mgt.core.apimgt.extension.rest.api.bean.OAuthClientResponse;
|
||||||
|
import io.entgra.device.mgt.core.apimgt.extension.rest.api.exceptions.BadRequestException;
|
||||||
|
import io.entgra.device.mgt.core.apimgt.extension.rest.api.exceptions.OAuthClientException;
|
||||||
|
import io.entgra.device.mgt.core.apimgt.extension.rest.api.exceptions.UnexpectedResponseException;
|
||||||
|
import okhttp3.Request;
|
||||||
|
|
||||||
|
public interface IOAuthClientService {
|
||||||
|
/**
|
||||||
|
* Handle execution of a APIM REST services invocation request. Token and cache handling will be handled by the
|
||||||
|
* service itself.
|
||||||
|
* @param request Instance of {@link Request} to execute
|
||||||
|
* @return Instance of {@link OAuthClientResponse} when successful invocation happens
|
||||||
|
* @throws OAuthClientException {@link OAuthClientException}
|
||||||
|
* @throws BadRequestException {@link BadRequestException}
|
||||||
|
* @throws UnexpectedResponseException {@link UnexpectedResponseException}
|
||||||
|
*/
|
||||||
|
OAuthClientResponse execute(Request request) throws OAuthClientException, BadRequestException,
|
||||||
|
UnexpectedResponseException;
|
||||||
|
}
|
@ -0,0 +1,385 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 - 2024, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (Pvt) Ltd. licenses this file to you under the Apache License,
|
||||||
|
* Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.entgra.device.mgt.core.apimgt.extension.rest.api;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import io.entgra.device.mgt.core.apimgt.extension.rest.api.bean.OAuthClientResponse;
|
||||||
|
import io.entgra.device.mgt.core.apimgt.extension.rest.api.constants.Constants;
|
||||||
|
import io.entgra.device.mgt.core.apimgt.extension.rest.api.exceptions.BadRequestException;
|
||||||
|
import io.entgra.device.mgt.core.apimgt.extension.rest.api.exceptions.OAuthClientException;
|
||||||
|
import io.entgra.device.mgt.core.apimgt.extension.rest.api.exceptions.UnexpectedResponseException;
|
||||||
|
import io.entgra.device.mgt.core.apimgt.extension.rest.api.util.HttpsTrustManagerUtils;
|
||||||
|
import okhttp3.Credentials;
|
||||||
|
import okhttp3.MediaType;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.RequestBody;
|
||||||
|
import okhttp3.Response;
|
||||||
|
import okhttp3.ResponseBody;
|
||||||
|
import org.apache.commons.httpclient.HttpStatus;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.wso2.carbon.apimgt.impl.APIManagerConfiguration;
|
||||||
|
import org.wso2.carbon.apimgt.impl.internal.ServiceReferenceHolder;
|
||||||
|
import org.wso2.carbon.context.PrivilegedCarbonContext;
|
||||||
|
import org.wso2.carbon.user.api.UserRealm;
|
||||||
|
import org.wso2.carbon.user.api.UserStoreException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
public class OAuthClient implements IOAuthClientService {
|
||||||
|
|
||||||
|
private static final Log log = LogFactory.getLog(OAuthClient.class);
|
||||||
|
private static final OkHttpClient client = new OkHttpClient(HttpsTrustManagerUtils.getSSLClient().newBuilder());
|
||||||
|
private static final Gson gson = new Gson();
|
||||||
|
private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
|
||||||
|
private static final String IDN_DCR_CLIENT_PREFIX = "_REST_API_INVOKER_SERVICE";
|
||||||
|
private static final APIManagerConfiguration config =
|
||||||
|
ServiceReferenceHolder.getInstance().getAPIManagerConfigurationService().getAPIManagerConfiguration();
|
||||||
|
private static final String tokenEndpoint = config.getFirstProperty(Constants.TOKE_END_POINT);
|
||||||
|
private static final String dcrEndpoint = config.getFirstProperty(Constants.DCR_END_POINT);
|
||||||
|
private static final Map<String, CacheWrapper> cache = new ConcurrentHashMap<>();
|
||||||
|
private static final int MAX_RETRY_ATTEMPT = 2;
|
||||||
|
|
||||||
|
private OAuthClient() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OAuthClient getInstance() {
|
||||||
|
return OAuthClientHolder.INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle execution of a APIM REST services invocation request. Token and cache handling will be handled by the
|
||||||
|
* service itself.
|
||||||
|
* @param request Instance of {@link Request} to execute
|
||||||
|
* @return Instance of {@link OAuthClientResponse} when successful invocation happens
|
||||||
|
* @throws OAuthClientException {@link OAuthClientException}
|
||||||
|
* @throws BadRequestException {@link BadRequestException}
|
||||||
|
* @throws UnexpectedResponseException {@link UnexpectedResponseException}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public OAuthClientResponse execute(Request request) throws OAuthClientException, BadRequestException,
|
||||||
|
UnexpectedResponseException {
|
||||||
|
int currentRetryAttempt = 0;
|
||||||
|
OAuthClientResponse oAuthClientResponse;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
request = intercept(request);
|
||||||
|
try (Response response = client.newCall(request).execute()) {
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
oAuthClientResponse = mapToOAuthClientResponse(response);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.code() == HttpStatus.SC_NOT_FOUND) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.info("Resource not found for the request [ " + request.url() + " ]");
|
||||||
|
}
|
||||||
|
oAuthClientResponse = mapToOAuthClientResponse(response);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// entering to the retrying phase, so increment the counter
|
||||||
|
currentRetryAttempt++;
|
||||||
|
if (response.code() == HttpStatus.SC_UNAUTHORIZED) {
|
||||||
|
if (currentRetryAttempt <= MAX_RETRY_ATTEMPT) {
|
||||||
|
refresh();
|
||||||
|
} else {
|
||||||
|
String msg =
|
||||||
|
"Request [ " + request.url() + " ] failed with code : [ " + response.code() + " ]" +
|
||||||
|
" & body : [ " + (response.body() != null ?
|
||||||
|
response.body().string() : " empty body received!") + " ]";
|
||||||
|
log.error(msg);
|
||||||
|
throw new UnexpectedResponseException(msg);
|
||||||
|
}
|
||||||
|
} else if (HttpStatus.SC_BAD_REQUEST == response.code()) {
|
||||||
|
String msg =
|
||||||
|
"Encountered a bad request! Request [ " + request.url() + " ] failed with code : " +
|
||||||
|
"[ " + response.code() + " ] & body : [ " + (response.body() != null ?
|
||||||
|
response.body().string() : " empty body received!") + " ]";
|
||||||
|
log.error(msg);
|
||||||
|
throw new BadRequestException(msg);
|
||||||
|
} else {
|
||||||
|
String msg =
|
||||||
|
"Request [ " + request.url() + " ]failed with code : [ " + response.code() + " ] & " +
|
||||||
|
"body : [ " + (response.body() != null ? response.body().string() : " empty " +
|
||||||
|
"body received!") + " ]";
|
||||||
|
log.error(msg);
|
||||||
|
throw new UnexpectedResponseException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
String msg =
|
||||||
|
"Error occurred while executing the request : [ " + request.method() + ":" + request.url() +
|
||||||
|
" ]";
|
||||||
|
throw new OAuthClientException(msg, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return oAuthClientResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dynamic client registration will be handled through here. These clients can be located under carbon console's
|
||||||
|
* service provider section in respective tenants.
|
||||||
|
*
|
||||||
|
* @return Instance of {@link Keys} containing the dcr client's credentials
|
||||||
|
* @throws UserStoreException Throws when error encountered while obtaining user realm service
|
||||||
|
* @throws IOException Throws when error encountered while executing dcr request
|
||||||
|
* @throws OAuthClientException Throws when failed to register dcr client
|
||||||
|
*/
|
||||||
|
private Keys idnDynamicClientRegistration() throws UserStoreException, IOException, OAuthClientException {
|
||||||
|
UserRealm userRealm = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUserRealm();
|
||||||
|
String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain();
|
||||||
|
String tenantAdminUsername = userRealm.getRealmConfiguration().getAdminUserName();
|
||||||
|
String tenantAdminPassword = userRealm.getRealmConfiguration().getAdminPassword();
|
||||||
|
String tenantAwareClientName = tenantDomain.toUpperCase() + IDN_DCR_CLIENT_PREFIX;
|
||||||
|
|
||||||
|
List<String> grantTypes = Arrays.asList(Constants.PASSWORD_GRANT_TYPE, Constants.REFRESH_TOKEN_GRANT_TYPE);
|
||||||
|
String dcrRequestJsonStr = (new JSONObject())
|
||||||
|
.put("clientName", tenantAwareClientName)
|
||||||
|
.put("owner", tenantAdminUsername)
|
||||||
|
.put("saasApp", true)
|
||||||
|
.put("grantType", String.join(Constants.SPACE, grantTypes))
|
||||||
|
.toString();
|
||||||
|
|
||||||
|
RequestBody requestBody = RequestBody.Companion.create(dcrRequestJsonStr, JSON);
|
||||||
|
Request dcrRequest = new Request.Builder()
|
||||||
|
.url(dcrEndpoint)
|
||||||
|
.addHeader(Constants.AUTHORIZATION_HEADER_NAME, Credentials.basic(tenantAdminUsername,
|
||||||
|
tenantAdminPassword))
|
||||||
|
.post(requestBody)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
try (Response response = client.newCall(dcrRequest).execute()) {
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
return mapKeys(response.body());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String msg = "Error encountered while processing DCR request. Tried client : [ " + tenantAwareClientName + " ]";
|
||||||
|
log.error(msg);
|
||||||
|
throw new OAuthClientException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Token obtaining procedure will be handled here. Since the required permissions for invoking the APIM REST
|
||||||
|
* services are available for the tenant admins, this procedure will use admin credentials for obtaining tokens.
|
||||||
|
* Also, please note that these tokens are only use for invoking APIM REST services only. The password grant uses
|
||||||
|
* since it facilitates the use of refresh token.
|
||||||
|
*
|
||||||
|
* @param keys Dcr client credentials to obtain a token
|
||||||
|
* @return Instance of {@link Tokens} containing the tokens
|
||||||
|
* @throws UserStoreException Throws when error encountered while obtaining user realm service
|
||||||
|
* @throws IOException Throws when error encountered while executing token request
|
||||||
|
* @throws OAuthClientException Throws when failed to obtain tokens
|
||||||
|
*/
|
||||||
|
private Tokens idnTokenGeneration(Keys keys) throws UserStoreException, IOException, OAuthClientException {
|
||||||
|
UserRealm userRealm = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUserRealm();
|
||||||
|
String tenantAdminUsername = userRealm.getRealmConfiguration().getAdminUserName();
|
||||||
|
String tenantAdminPassword = userRealm.getRealmConfiguration().getAdminPassword();
|
||||||
|
|
||||||
|
String tokenRequestJsonStr = (new JSONObject())
|
||||||
|
.put("grant_type", Constants.PASSWORD_GRANT_TYPE)
|
||||||
|
.put("username", tenantAdminUsername)
|
||||||
|
.put("password", tenantAdminPassword)
|
||||||
|
.put("scope", Constants.SCOPES)
|
||||||
|
.toString();
|
||||||
|
|
||||||
|
RequestBody requestBody = RequestBody.Companion.create(tokenRequestJsonStr, JSON);
|
||||||
|
Request tokenRequest = new Request.Builder()
|
||||||
|
.url(tokenEndpoint)
|
||||||
|
.addHeader(Constants.AUTHORIZATION_HEADER_NAME, Credentials.basic(keys.consumerKey,
|
||||||
|
keys.consumerSecret))
|
||||||
|
.post(requestBody)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
try (Response response = client.newCall(tokenRequest).execute()) {
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
return mapTokens(response.body());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String msg = "Error encountered while processing token registration request";
|
||||||
|
log.error(msg);
|
||||||
|
throw new OAuthClientException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain and refresh idn auth tokens. Note that in the first try it try to obtain new tokens via refresh_token
|
||||||
|
* grant type, if it fails it tries to obtain new tokens via password grant type.
|
||||||
|
* @param keys Instance of {@link Keys} containing the dcr client's credentials
|
||||||
|
* @param refreshToken Refresh token
|
||||||
|
* @return Instance of {@link Tokens} containing the tokens
|
||||||
|
* @throws UserStoreException Throws when error encountered while obtaining user realm service
|
||||||
|
* @throws IOException Throws when error encountered while executing token request
|
||||||
|
* @throws OAuthClientException Throws when failed to obtain tokens
|
||||||
|
*/
|
||||||
|
private Tokens idnTokenRefresh(Keys keys, String refreshToken) throws UserStoreException, IOException,
|
||||||
|
OAuthClientException {
|
||||||
|
String tokenRequestJsonStr = (new JSONObject())
|
||||||
|
.put("grant_type", Constants.REFRESH_TOKEN_GRANT_TYPE)
|
||||||
|
.put("refresh_token", refreshToken)
|
||||||
|
.put("scope", Constants.SCOPES)
|
||||||
|
.toString();
|
||||||
|
|
||||||
|
RequestBody requestBody = RequestBody.Companion.create(tokenRequestJsonStr, JSON);
|
||||||
|
Request tokenRequest = new Request.Builder()
|
||||||
|
.url(tokenEndpoint)
|
||||||
|
.addHeader(Constants.AUTHORIZATION_HEADER_NAME, Credentials.basic(keys.consumerKey,
|
||||||
|
keys.consumerSecret))
|
||||||
|
.post(requestBody)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
try (Response response = client.newCall(tokenRequest).execute()) {
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
return mapTokens(response.body());
|
||||||
|
} else {
|
||||||
|
return idnTokenGeneration(keys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Intercept the request and add authorization header base on available tokens.
|
||||||
|
* @param request Instance of the {@link Request} to intercept
|
||||||
|
* @return Intercepted request
|
||||||
|
* @throws OAuthClientException Throws when error encountered while adding authorization header
|
||||||
|
*/
|
||||||
|
private Request intercept(Request request) throws OAuthClientException {
|
||||||
|
String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain();
|
||||||
|
CacheWrapper cacheWrapper = cache.computeIfAbsent(tenantDomain, key -> {
|
||||||
|
CacheWrapper constructedWrapper = null;
|
||||||
|
try {
|
||||||
|
Keys keys = idnDynamicClientRegistration();
|
||||||
|
Tokens tokens = idnTokenGeneration(keys);
|
||||||
|
constructedWrapper = new CacheWrapper(keys, tokens);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error encountered while updating the cache", e);
|
||||||
|
}
|
||||||
|
return constructedWrapper;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (cacheWrapper == null) {
|
||||||
|
throw new OAuthClientException("Failed to obtain tokens. Hence aborting request intercepting process");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Request.Builder(request).header(Constants.AUTHORIZATION_HEADER_NAME,
|
||||||
|
Constants.AUTHORIZATION_HEADER_PREFIX_BEARER + cacheWrapper.tokens.accessToken).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh cached tokens.
|
||||||
|
* @throws OAuthClientException Throws when error encountered while refreshing the tokens
|
||||||
|
*/
|
||||||
|
private void refresh() throws OAuthClientException {
|
||||||
|
String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain();
|
||||||
|
CacheWrapper cacheWrapper = cache.computeIfPresent(tenantDomain, (key, value) -> {
|
||||||
|
CacheWrapper updatedCacheWrapper = null;
|
||||||
|
try {
|
||||||
|
Tokens tokens = idnTokenRefresh(value.keys, value.tokens.refreshToken);
|
||||||
|
updatedCacheWrapper = new CacheWrapper(value.keys, tokens);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error encountered while updating the cache", e);
|
||||||
|
}
|
||||||
|
return updatedCacheWrapper;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (cacheWrapper == null) {
|
||||||
|
throw new OAuthClientException("Failed to refresh tokens. Hence aborting request executing process");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Keys mapKeys(ResponseBody responseBody) {
|
||||||
|
Keys keys = new Keys();
|
||||||
|
if (responseBody == null) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Received empty request body for mapping into keys");
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject jsonObject = gson.fromJson(responseBody.toString(), JSONObject.class);
|
||||||
|
keys.consumerKey = jsonObject.getString("clientId");
|
||||||
|
keys.consumerSecret = jsonObject.getString("clientSecret");
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Tokens mapTokens(ResponseBody responseBody) {
|
||||||
|
Tokens tokens = new Tokens();
|
||||||
|
if (responseBody == null) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Received empty request body for mapping into tokens");
|
||||||
|
}
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject jsonObject = gson.fromJson(responseBody.toString(), JSONObject.class);
|
||||||
|
tokens.accessToken = jsonObject.getString("access_token");
|
||||||
|
tokens.refreshToken = jsonObject.getString("refresh_token");
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
private OAuthClientResponse mapToOAuthClientResponse(Response response) throws IOException {
|
||||||
|
return new OAuthClientResponse(response.code(),
|
||||||
|
response.body() != null ? response.body().string() : null, response.isSuccessful());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holder for {@link OAuthClient} instance
|
||||||
|
*/
|
||||||
|
private static class OAuthClientHolder {
|
||||||
|
private static final OAuthClient INSTANCE = new OAuthClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Act as an internal data class for containing dcr credentials, hence no need of expose as a bean
|
||||||
|
*/
|
||||||
|
private class Keys {
|
||||||
|
String consumerKey;
|
||||||
|
String consumerSecret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Act as an internal data class for containing dcr tokens, hence no need of expose as a bean
|
||||||
|
*/
|
||||||
|
private class Tokens {
|
||||||
|
String accessToken;
|
||||||
|
String refreshToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Act as an internal data class for containing cached tokens and keys, hence no need of expose as a bean
|
||||||
|
*/
|
||||||
|
private class CacheWrapper {
|
||||||
|
Keys keys;
|
||||||
|
Tokens tokens;
|
||||||
|
|
||||||
|
CacheWrapper(Keys keys, Tokens tokens) {
|
||||||
|
this.keys = keys;
|
||||||
|
this.tokens = tokens;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 - 2024, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (Pvt) Ltd. licenses this file to you under the Apache License,
|
||||||
|
* Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.entgra.device.mgt.core.apimgt.extension.rest.api.bean;
|
||||||
|
|
||||||
|
public class OAuthClientResponse {
|
||||||
|
private final int code;
|
||||||
|
private final String body;
|
||||||
|
private final boolean isSuccessful;
|
||||||
|
|
||||||
|
public OAuthClientResponse(int code, String body, boolean isSuccessful) {
|
||||||
|
this.code = code;
|
||||||
|
this.body = body;
|
||||||
|
this.isSuccessful = isSuccessful;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBody() {
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSuccessful() {
|
||||||
|
return isSuccessful;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 - 2024, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (Pvt) Ltd. licenses this file to you under the Apache License,
|
||||||
|
* Version 2.0 (the "License"); you may not use this file except
|
||||||
|
* in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.entgra.device.mgt.core.apimgt.extension.rest.api.exceptions;
|
||||||
|
|
||||||
|
public class OAuthClientException extends Exception {
|
||||||
|
public OAuthClientException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OAuthClientException(String msg, Throwable throwable) {
|
||||||
|
super(msg, throwable);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue