Merge pull request 'Fix dcr and token endpoint related issues' (#9) from vigneshan/device-mgt-core:fix/key-mgt-api into master

Reviewed-on: community/device-mgt-core#9
pull/1/head
Pahansith Gunathilake 2 years ago
commit bd9aa0ea5c

@ -49,6 +49,7 @@ public class APIUtil {
private static final String DEFAULT_ANALYTICS_ARTIFACT_TAG = "analytics_artifacts_management"; private static final String DEFAULT_ANALYTICS_ARTIFACT_TAG = "analytics_artifacts_management";
private static final String DEFAULT_TRANSPORT_MGT_TAG = "transport_management"; private static final String DEFAULT_TRANSPORT_MGT_TAG = "transport_management";
private static final String DEFAULT_ENTERPRISE_TAG= "androidforwork"; private static final String DEFAULT_ENTERPRISE_TAG= "androidforwork";
private static final String DEFAULT_ANALYTICS_MGT_TAG= "analytics_management";
public static final String PERMISSION_PROPERTY_NAME = "name"; public static final String PERMISSION_PROPERTY_NAME = "name";
@ -119,6 +120,7 @@ public class APIUtil {
allowedApisTags.add(DEFAULT_APP_MGT_SUB_MGT_TAG); allowedApisTags.add(DEFAULT_APP_MGT_SUB_MGT_TAG);
allowedApisTags.add(DEFAULT_ANALYTICS_ARTIFACT_TAG); allowedApisTags.add(DEFAULT_ANALYTICS_ARTIFACT_TAG);
allowedApisTags.add(DEFAULT_TRANSPORT_MGT_TAG); allowedApisTags.add(DEFAULT_TRANSPORT_MGT_TAG);
allowedApisTags.add(DEFAULT_ANALYTICS_MGT_TAG);
// In an environment only super tenant should be capable of calling this API tag // In an environment only super tenant should be capable of calling this API tag
if (PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId() == if (PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId() ==
MultitenantConstants.SUPER_TENANT_ID) { MultitenantConstants.SUPER_TENANT_ID) {

@ -28,9 +28,9 @@ import javax.xml.bind.annotation.XmlRootElement;
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
public class DCRRequest { public class DCRRequest {
@XmlElement(required = true) @XmlElement(required = true)
private String clientName; private String applicationName;
@XmlElement(required = true) @XmlElement(required = true)
private String owner; private String username;
@XmlElement(required = true) @XmlElement(required = true)
private String grantTypes; private String grantTypes;
@XmlElement @XmlElement
@ -40,20 +40,20 @@ public class DCRRequest {
@XmlElement @XmlElement
private boolean isSaasApp; private boolean isSaasApp;
public String getClientName() { public String getApplicationName() {
return clientName; return applicationName;
} }
public void setClientName(String clientName) { public void setApplicationName(String applicationName) {
this.clientName = clientName; this.applicationName = applicationName;
} }
public String getOwner() { public String getUsername() {
return owner; return username;
} }
public void setOwner(String owner) { public void setUsername(String username) {
this.owner = owner; this.username = username;
} }
public String getGrantTypes() { public String getGrantTypes() {

@ -20,6 +20,7 @@ package org.wso2.carbon.apimgt.keymgt.extension.api;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam; import javax.ws.rs.FormParam;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST; import javax.ws.rs.POST;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
@ -38,9 +39,12 @@ public interface KeyManagerService {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Path("/token") @Path("/token")
Response generateAccessToken(@FormParam("client_id") String clientId, Response generateAccessToken(@HeaderParam("Authorization") String basicAuthHeader,
@FormParam("client_id") String clientId,
@FormParam("client_secret") String clientSecret, @FormParam("client_secret") String clientSecret,
@FormParam("refresh_token") String refreshToken, @FormParam("refresh_token") String refreshToken,
@FormParam("scope") String scope, @FormParam("scope") String scope,
@FormParam("grant_type") String grantType); @FormParam("grant_type") String grantType,
@FormParam("assertion") String assertion,
@FormParam("admin_access_token") String admin_access_token);
} }

@ -27,14 +27,17 @@ import org.wso2.carbon.apimgt.keymgt.extension.exception.BadRequestException;
import org.wso2.carbon.apimgt.keymgt.extension.exception.KeyMgtException; import org.wso2.carbon.apimgt.keymgt.extension.exception.KeyMgtException;
import org.wso2.carbon.apimgt.keymgt.extension.service.KeyMgtService; import org.wso2.carbon.apimgt.keymgt.extension.service.KeyMgtService;
import org.wso2.carbon.apimgt.keymgt.extension.service.KeyMgtServiceImpl; import org.wso2.carbon.apimgt.keymgt.extension.service.KeyMgtServiceImpl;
import org.wso2.carbon.device.mgt.common.exceptions.UnAuthorizedException;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam; import javax.ws.rs.FormParam;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST; import javax.ws.rs.POST;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.util.Base64;
public class KeyManagerServiceImpl implements KeyManagerService { public class KeyManagerServiceImpl implements KeyManagerService {
@ -46,7 +49,7 @@ public class KeyManagerServiceImpl implements KeyManagerService {
public Response dynamicClientRegistration(DCRRequest dcrRequest) { public Response dynamicClientRegistration(DCRRequest dcrRequest) {
try { try {
KeyMgtService keyMgtService = new KeyMgtServiceImpl(); KeyMgtService keyMgtService = new KeyMgtServiceImpl();
DCRResponse resp = keyMgtService.dynamicClientRegistration(dcrRequest.getClientName(), dcrRequest.getOwner(), DCRResponse resp = keyMgtService.dynamicClientRegistration(dcrRequest.getApplicationName(), dcrRequest.getUsername(),
dcrRequest.getGrantTypes(), dcrRequest.getCallBackUrl(), dcrRequest.getTags(), dcrRequest.getIsSaasApp()); dcrRequest.getGrantTypes(), dcrRequest.getCallBackUrl(), dcrRequest.getTags(), dcrRequest.getIsSaasApp());
return Response.status(Response.Status.CREATED).entity(resp).build(); return Response.status(Response.Status.CREATED).entity(resp).build();
} catch (KeyMgtException e) { } catch (KeyMgtException e) {
@ -58,20 +61,32 @@ public class KeyManagerServiceImpl implements KeyManagerService {
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Path("/token") @Path("/token")
public Response generateAccessToken(@FormParam("client_id") String clientId, public Response generateAccessToken(@HeaderParam("Authorization") String basicAuthHeader,
@FormParam("client_id") String clientId,
@FormParam("client_secret") String clientSecret, @FormParam("client_secret") String clientSecret,
@FormParam("refresh_token") String refreshToken, @FormParam("refresh_token") String refreshToken,
@FormParam("scope") String scope, @FormParam("scope") String scope,
@FormParam("grant_type") String grantType) { @FormParam("grant_type") String grantType,
@FormParam("assertion") String assertion,
@FormParam("admin_access_token") String admin_access_token) {
try { try {
if (basicAuthHeader == null) {
String msg = "Invalid credentials. Make sure your API call is invoked with a Basic Authorization header.";
throw new UnAuthorizedException(msg);
}
String encodedClientCredentials = new String(Base64.getDecoder().decode(basicAuthHeader.split(" ")[1]));
KeyMgtService keyMgtService = new KeyMgtServiceImpl(); KeyMgtService keyMgtService = new KeyMgtServiceImpl();
TokenResponse resp = keyMgtService.generateAccessToken( TokenResponse resp = keyMgtService.generateAccessToken(
new TokenRequest(clientId, clientSecret, refreshToken, scope, grantType)); new TokenRequest(encodedClientCredentials.split(":")[0],
encodedClientCredentials.split(":")[1], refreshToken, scope,
grantType, assertion,admin_access_token));
return Response.status(Response.Status.CREATED).entity(resp).build(); return Response.status(Response.Status.CREATED).entity(resp).build();
} catch (KeyMgtException e) { } catch (KeyMgtException e) {
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build(); return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
} catch (BadRequestException e) { } catch (BadRequestException e) {
return Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage()).build(); return Response.status(Response.Status.BAD_REQUEST).entity(e.getMessage()).build();
} catch (UnAuthorizedException e) {
return Response.status(Response.Status.UNAUTHORIZED).entity(e.getMessage()).build();
} }
} }
} }

@ -19,27 +19,27 @@
package org.wso2.carbon.apimgt.keymgt.extension; package org.wso2.carbon.apimgt.keymgt.extension;
public class DCRResponse { public class DCRResponse {
String clientId; String client_id;
String clientSecret; String client_secret;
public DCRResponse(String clientId, String clientSecret) { public DCRResponse(String client_id, String client_secret) {
this.clientId = clientId; this.client_id = client_id;
this.clientSecret = clientSecret; this.client_secret = client_secret;
} }
public String getClientId() { public String getClientId() {
return clientId; return client_id;
} }
public void setClientId(String clientId) { public void setClientId(String client_id) {
this.clientId = clientId; this.client_id = client_id;
} }
public String getClientSecret() { public String getClientSecret() {
return clientSecret; return client_secret;
} }
public void setClientSecret(String clientSecret) { public void setClientSecret(String client_secret) {
this.clientSecret = clientSecret; this.client_secret = client_secret;
} }
} }

@ -24,13 +24,18 @@ public class TokenRequest {
private String refreshToken; private String refreshToken;
private String scope; private String scope;
private String grantType; private String grantType;
private String assertion;
private String admin_access_token;
public TokenRequest(String clientId, String clientSecret, String refreshToken, String scope, String grantType) { public TokenRequest(String clientId, String clientSecret, String refreshToken, String scope, String grantType,
String assertion, String admin_access_token) {
this.clientId = clientId; this.clientId = clientId;
this.clientSecret = clientSecret; this.clientSecret = clientSecret;
this.refreshToken = refreshToken; this.refreshToken = refreshToken;
this.scope = scope; this.scope = scope;
this.grantType = grantType; this.grantType = grantType;
this.assertion = assertion;
this.admin_access_token = admin_access_token;
} }
public String getClientId() { public String getClientId() {
@ -72,4 +77,20 @@ public class TokenRequest {
public void setRefreshToken(String refreshToken) { public void setRefreshToken(String refreshToken) {
this.refreshToken = refreshToken; this.refreshToken = refreshToken;
} }
public String getAssertion() {
return assertion;
}
public void setAssertion(String assertion) {
this.assertion = assertion;
}
public String getAdminAccessToken() {
return admin_access_token;
}
public void setAdminAccessToken(String admin_access_token) {
this.admin_access_token = admin_access_token;
}
} }

@ -22,14 +22,14 @@ public class TokenResponse {
private String access_token; private String access_token;
private String refresh_token; private String refresh_token;
private String scope; private String scope;
private String tokenType; private String token_type;
private int expires_in; private int expires_in;
public TokenResponse(String access_token, String refresh_token, String scope, String tokenType, int expires_in) { public TokenResponse(String access_token, String refresh_token, String scope, String token_type, int expires_in) {
this.access_token = access_token; this.access_token = access_token;
this.refresh_token = refresh_token; this.refresh_token = refresh_token;
this.scope = scope; this.scope = scope;
this.tokenType = tokenType; this.token_type = token_type;
this.expires_in = expires_in; this.expires_in = expires_in;
} }
@ -57,12 +57,12 @@ public class TokenResponse {
this.scope = scope; this.scope = scope;
} }
public String getTokenType() { public String getToken_Type() {
return tokenType; return token_type;
} }
public void setTokenType(String tokenType) { public void setTokenType(String token_type) {
this.tokenType = tokenType; this.token_type = token_type;
} }
public int getExpiresIn() { public int getExpiresIn() {

@ -20,6 +20,7 @@ package org.wso2.carbon.apimgt.keymgt.extension.service;
import com.google.gson.Gson; import com.google.gson.Gson;
import okhttp3.Credentials; import okhttp3.Credentials;
import okhttp3.FormBody;
import okhttp3.MediaType; import okhttp3.MediaType;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
import okhttp3.Request; import okhttp3.Request;
@ -41,7 +42,6 @@ import org.wso2.carbon.apimgt.keymgt.extension.KeyMgtConstants;
import org.wso2.carbon.apimgt.keymgt.extension.OAuthApplication; import org.wso2.carbon.apimgt.keymgt.extension.OAuthApplication;
import org.wso2.carbon.apimgt.keymgt.extension.TokenRequest; import org.wso2.carbon.apimgt.keymgt.extension.TokenRequest;
import org.wso2.carbon.apimgt.keymgt.extension.TokenResponse; import org.wso2.carbon.apimgt.keymgt.extension.TokenResponse;
import org.wso2.carbon.apimgt.keymgt.extension.exception.BadRequestException;
import org.wso2.carbon.apimgt.keymgt.extension.exception.KeyMgtException; import org.wso2.carbon.apimgt.keymgt.extension.exception.KeyMgtException;
import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.mgt.core.config.DeviceConfigurationManager; import org.wso2.carbon.device.mgt.core.config.DeviceConfigurationManager;
@ -53,9 +53,7 @@ import org.wso2.carbon.user.api.UserStoreManager;
import org.wso2.carbon.user.core.service.RealmService; import org.wso2.carbon.user.core.service.RealmService;
import org.wso2.carbon.utils.multitenancy.MultitenantUtils; import org.wso2.carbon.utils.multitenancy.MultitenantUtils;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager; import javax.net.ssl.X509TrustManager;
@ -82,6 +80,17 @@ public class KeyMgtServiceImpl implements KeyMgtService {
public DCRResponse dynamicClientRegistration(String clientName, String owner, String grantTypes, String callBackUrl, public DCRResponse dynamicClientRegistration(String clientName, String owner, String grantTypes, String callBackUrl,
String[] tags, boolean isSaasApp) throws KeyMgtException { String[] tags, boolean isSaasApp) throws KeyMgtException {
if (owner == null) {
PrivilegedCarbonContext threadLocalCarbonContext = PrivilegedCarbonContext.getThreadLocalCarbonContext();
try {
owner = APIUtil.getTenantAdminUserName(threadLocalCarbonContext.getTenantDomain());
} catch (APIManagementException e) {
String msg = "Error occurred while retrieving admin user for the tenant " + threadLocalCarbonContext.getTenantDomain();
log.error(msg, e);
throw new KeyMgtException(msg);
}
}
String tenantDomain = MultitenantUtils.getTenantDomain(owner); String tenantDomain = MultitenantUtils.getTenantDomain(owner);
int tenantId; int tenantId;
@ -97,10 +106,8 @@ public class KeyMgtServiceImpl implements KeyMgtService {
kmConfig = getKeyManagerConfig(); kmConfig = getKeyManagerConfig();
if (KeyMgtConstants.SUPER_TENANT.equals(tenantDomain)) { if (KeyMgtConstants.SUPER_TENANT.equals(tenantDomain)) {
OAuthApplication superTenantOauthApp = createOauthApplication( OAuthApplication dcrApplication = createOauthApplication(clientName, kmConfig.getAdminUsername(), tags);
KeyMgtConstants.RESERVED_OAUTH_APP_NAME_PREFIX + KeyMgtConstants.SUPER_TENANT, return new DCRResponse(dcrApplication.getClientId(), dcrApplication.getClientSecret());
kmConfig.getAdminUsername(), tags);
return new DCRResponse(superTenantOauthApp.getClientId(), superTenantOauthApp.getClientSecret());
} else { } else {
// super-tenant admin dcr and token generation // super-tenant admin dcr and token generation
OAuthApplication superTenantOauthApp = createOauthApplication( OAuthApplication superTenantOauthApp = createOauthApplication(
@ -141,7 +148,7 @@ public class KeyMgtServiceImpl implements KeyMgtService {
} }
} }
public TokenResponse generateAccessToken(TokenRequest tokenRequest) throws KeyMgtException, BadRequestException { public TokenResponse generateAccessToken(TokenRequest tokenRequest) throws KeyMgtException {
try { try {
Application application = APIUtil.getApplicationByClientId(tokenRequest.getClientId()); Application application = APIUtil.getApplicationByClientId(tokenRequest.getClientId());
String tenantDomain = MultitenantUtils.getTenantDomain(application.getOwner()); String tenantDomain = MultitenantUtils.getTenantDomain(application.getOwner());
@ -167,20 +174,43 @@ public class KeyMgtServiceImpl implements KeyMgtService {
} }
JSONObject jsonObject = new JSONObject(); JSONObject jsonObject = new JSONObject();
if ("client_credentials".equals(tokenRequest.getGrantType())) { RequestBody appTokenPayload;
jsonObject.put("grant_type", "password"); switch (tokenRequest.getGrantType()) {
jsonObject.put("username", username); case "client_credentials":
jsonObject.put("password", password); case "password":
} else if ("refresh_token".equals(tokenRequest.getGrantType())) { appTokenPayload = new FormBody.Builder()
jsonObject.put("grant_type", "refresh_token"); .add("grant_type", "password")
jsonObject.put("refresh_token", tokenRequest.getRefreshToken()); .add("username", username)
} else { .add("password", password)
msg = "Invalid grant type: " + tokenRequest.getGrantType(); .add("scope", tokenRequest.getScope()).build();
throw new BadRequestException(msg); break;
case "refresh_token":
appTokenPayload = new FormBody.Builder()
.add("grant_type", "refresh_token")
.add("refresh_token", tokenRequest.getRefreshToken())
.add("scope", tokenRequest.getScope()).build();
break;
case "urn:ietf:params:oauth:grant-type:jwt-bearer":
appTokenPayload = new FormBody.Builder()
.add("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer")
.add("assertion", tokenRequest.getAssertion())
.add("scope", tokenRequest.getScope()).build();
break;
case "access_token":
appTokenPayload = new FormBody.Builder()
.add("grant_type", "access_token")
.add("admin_access_token", tokenRequest.getAdminAccessToken())
.add("scope", tokenRequest.getScope()).build();
break;
default:
appTokenPayload = new FormBody.Builder()
.add("grant_type", tokenRequest.getGrantType())
.add("scope", tokenRequest.getScope()).build();
break;
} }
jsonObject.put("scope", tokenRequest.getScope()); jsonObject.put("scope", tokenRequest.getScope());
RequestBody appTokenPayload = RequestBody.Companion.create(jsonObject.toString(), JSON);
kmConfig = getKeyManagerConfig(); kmConfig = getKeyManagerConfig();
String appTokenEndpoint = kmConfig.getServerUrl() + KeyMgtConstants.OAUTH2_TOKEN_ENDPOINT; String appTokenEndpoint = kmConfig.getServerUrl() + KeyMgtConstants.OAUTH2_TOKEN_ENDPOINT;
Request request = new Request.Builder() Request request = new Request.Builder()
@ -449,12 +479,7 @@ public class KeyMgtServiceImpl implements KeyMgtService {
}; };
return new OkHttpClient.Builder() return new OkHttpClient.Builder()
.sslSocketFactory(getSimpleTrustedSSLSocketFactory(), trustAllCerts) .sslSocketFactory(getSimpleTrustedSSLSocketFactory(), trustAllCerts)
.hostnameVerifier(new HostnameVerifier() { .hostnameVerifier((hostname, sslSession) -> true).build();
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
}).build();
} }
private static SSLSocketFactory getSimpleTrustedSSLSocketFactory() { private static SSLSocketFactory getSimpleTrustedSSLSocketFactory() {

@ -1,3 +1,4 @@
instructions.configure = \ instructions.configure = \
org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../deployment/server/webapps/);\ org.eclipse.equinox.p2.touchpoint.natives.mkdir(path:${installFolder}/../../deployment/server/webapps/);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.apimgt.keymgt.extension_${feature.version}/webapps/api-key-management.war,target:${installFolder}/../../deployment/server/webapps/api-key-management.war,overwrite:true);\ org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.apimgt.keymgt.extension_${feature.version}/webapps/api-key-management.war,target:${installFolder}/../../deployment/server/webapps/api-key-management.war,overwrite:true);\
org.eclipse.equinox.p2.touchpoint.natives.copy(source:${installFolder}/../features/org.wso2.carbon.apimgt.keymgt.extension_${feature.version}/synapse-configs/default/api/_API_Key_Management_.xml,target:${installFolder}/../../deployment/server/synapse-configs/default/api/_API_Key_Management_.xml,overwrite:true);\

@ -0,0 +1,46 @@
<!--
~ /*
~ * Copyright (c) 2022, 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.
~ */
~
-->
<api xmlns="http://ws.apache.org/ns/synapse" name="_API_Key_Management_" context="/api-application-registration/register">
<resource methods="POST" url-mapping="" faultSequence="_api_registration_fault_">
<inSequence>
<property name="uri.var.portnum" expression="get-property('system','iot.core.https.port')"/>
<property name="uri.var.hostname" expression="get-property('system','iot.core.host')"/>
<send>
<endpoint>
<http uri-template="https://{uri.var.hostname}:{uri.var.portnum}/api-key-management/dynamic-client-registration">
<timeout>
<duration>60000</duration>
<responseAction>fault</responseAction>
</timeout>
</http>
</endpoint>
</send>
</inSequence>
<outSequence>
<send/>
</outSequence>
</resource>
<handlers>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.ext.APIManagerCacheExtensionHandler"/>
<handler class="org.wso2.carbon.apimgt.gateway.handlers.common.SynapsePropertiesHandler"/>
</handlers>
</api>
Loading…
Cancel
Save