Skip to content

Commit

Permalink
Modify DCR Flow to make SSA an optional parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
VenukshiMendis committed May 14, 2024
1 parent e874db6 commit b02ea52
Show file tree
Hide file tree
Showing 14 changed files with 216 additions and 134 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
Expand All @@ -49,6 +50,7 @@
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;


import static java.util.Map.Entry.comparingByKey;

/**
Expand Down Expand Up @@ -582,6 +584,9 @@ private void buildAllowedSubscriptions() {
.collect(Collectors.toList());
allowedAPIs.put(scopeName, rolesList);
}
else if(StringUtils.isEmpty(rolesStr)) {
allowedAPIs.put(scopeName, Collections.emptyList());
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ public class OpenBankingConstants {
public static final String REGULATORY_API = "API";
public static final String SOFTWARE_ROLES = "software_roles";
public static final String SOFTWARE_STATEMENT = "software_statement";
public static final String SOFTWARE_ID = "software_id";
public static final String SOFTWARE_ENVIRONMENT = "software_environment";
public static final String TOKEN_ENDPOINT = "DCR.TokenEndpoint";
public static final String STORE_HOSTNAME = "PublisherURL";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,17 @@ public static String getSoftwareEnvironmentFromSSA(String softwareStatement) thr
String prodEnvIdentificationValue = OpenBankingConfigParser.getInstance()
.getSoftwareEnvIdentificationSSAPropertyValueForProduction();
String softwareEnvironment = IdentityConstants.PRODUCTION;
// decode software statement and get softwareEnvironment
JSONObject softwareStatementBody = JWTUtils.decodeRequestJWT(softwareStatement, "body");
Object softwareEnvironmentValue = softwareStatementBody.get(sandboxEnvIdentificationPropertyName);
if (softwareEnvironmentValue != null &&
softwareEnvironmentValue.toString().equalsIgnoreCase(sandboxEnvIdentificationValue)) {
softwareEnvironment = IdentityConstants.SANDBOX;
} else if (softwareEnvironmentValue != null &&
softwareEnvironmentValue.toString().equalsIgnoreCase(prodEnvIdentificationValue)) {
softwareEnvironment = IdentityConstants.PRODUCTION;
if (softwareStatement != null) {
// decode software statement and get softwareEnvironment
JSONObject softwareStatementBody = JWTUtils.decodeRequestJWT(softwareStatement, "body");
Object softwareEnvironmentValue = softwareStatementBody.get(sandboxEnvIdentificationPropertyName);
if (softwareEnvironmentValue != null &&
softwareEnvironmentValue.toString().equalsIgnoreCase(sandboxEnvIdentificationValue)) {
softwareEnvironment = IdentityConstants.SANDBOX;
} else if (softwareEnvironmentValue != null &&
softwareEnvironmentValue.toString().equalsIgnoreCase(prodEnvIdentificationValue)) {
softwareEnvironment = IdentityConstants.PRODUCTION;
}
}
return softwareEnvironment;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* specific language governing permissions and limitations
* under the License.
*/

package com.wso2.openbanking.accelerator.gateway.executor.dcr;

import com.google.gson.JsonArray;
Expand All @@ -27,6 +28,7 @@
import com.wso2.openbanking.accelerator.common.constant.OpenBankingConstants;
import com.wso2.openbanking.accelerator.common.error.OpenBankingErrorCodes;
import com.wso2.openbanking.accelerator.common.exception.OpenBankingException;
import com.wso2.openbanking.accelerator.common.identity.IdentityConstants;
import com.wso2.openbanking.accelerator.common.util.Generated;
import com.wso2.openbanking.accelerator.common.util.HTTPClientUtils;
import com.wso2.openbanking.accelerator.common.util.JWTUtils;
Expand Down Expand Up @@ -70,6 +72,7 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.text.ParseException;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
Expand Down Expand Up @@ -157,8 +160,10 @@ public void postProcessResponse(OBAPIResponseContext obapiResponseContext) {
JsonParser jsonParser = new JsonParser();
JsonObject createdDCRAppDetails = ((JsonObject) jsonParser
.parse(obapiResponseContext.getResponsePayload()));
String softwareStatement = createdDCRAppDetails.get(OpenBankingConstants.SOFTWARE_STATEMENT)
.getAsString();

JsonElement softwareStatementJson = createdDCRAppDetails.get(OpenBankingConstants.SOFTWARE_STATEMENT);
String softwareStatement = (softwareStatementJson != null) ? softwareStatementJson.toString() : null;

//call IS DCR endpoint to create application for obtaining a token to invoke devportal REST APIs
JsonElement registrationResponse = createServiceProvider(basicAuthHeader,
createdDCRAppDetails.get("software_id").getAsString());
Expand Down Expand Up @@ -275,9 +280,14 @@ public void postProcessResponse(OBAPIResponseContext obapiResponseContext) {
}

List<String> apiIDList = new ArrayList<>();
if (regulatoryAPIs != null) {
apiIDList = filterRegulatorAPIs(regulatoryAPIs, publishedAPIsResponse.getAsJsonObject()
.get("list").getAsJsonArray(), getRolesFromSSA(softwareStatement));
if (regulatoryAPIs != null ) {
if (softwareStatement != null) {
apiIDList = filterRegulatorAPIs(regulatoryAPIs, publishedAPIsResponse.getAsJsonObject()
.get("list").getAsJsonArray(), getRolesFromSSA(softwareStatement));
} else {
apiIDList = filterRegulatorAPIs(regulatoryAPIs, publishedAPIsResponse.getAsJsonObject()
.get("list").getAsJsonArray());
}
} else {
log.warn("No regulatory APIs configured. Application will be subscribed to all published APIs");
//subscribe to all APIs if there are no configured regulatory APIs
Expand Down Expand Up @@ -387,29 +397,32 @@ public void postProcessResponse(OBAPIResponseContext obapiResponseContext) {
handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_UPDATE_ERROR);
return;
}
List<String> allowedRoles = getRolesFromSSA(createdDCRAppDetails
.get(OpenBankingConstants.SOFTWARE_STATEMENT).getAsString());
List<String> subscribedAPIIdList = new ArrayList<>();
for (JsonElement subscribedAPI : subscribedAPIsResponse.getAsJsonObject().get("list")
.getAsJsonArray()) {
String apiId = subscribedAPI.getAsJsonObject().get("apiId").getAsString();
subscribedAPIIdList.add(apiId);
}
//check whether the ssa still contains the roles related to the subscribed APIs
List<String> unsubscribedAPIs = getUnAuthorizedAPIs(subscribedAPIsResponse.getAsJsonObject()
.get("list").getAsJsonArray(), regulatoryAPIs, allowedRoles);
if (!unsubscribedAPIs.isEmpty()) {
//unsubscribe from the apis
for (String subscriptionId : unsubscribedAPIs) {
if (!callDelete(urlMap.get(GatewayConstants.API_GET_SUBSCRIBED).toString()
.concat("/").concat(subscriptionId), GatewayConstants.BEARER_TAG.concat(token))) {
log.error("Error while unsubscribing from APIs");
//delete SP created to call dev portal REST APIs
callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/")
.concat(clientId), basicAuthHeader);
handleInternalServerError(obapiResponseContext,
OpenBankingErrorCodes.REGISTRATION_INTERNAL_ERROR);
return;

JsonElement softwareStatementJson = createdDCRAppDetails.get(OpenBankingConstants.SOFTWARE_STATEMENT);
if (softwareStatementJson != null) {
String softwareStatement = softwareStatementJson.getAsString();
List<String> allowedRoles = getRolesFromSSA(softwareStatement);
List<String> unsubscribedAPIs = getUnAuthorizedAPIs(subscribedAPIsResponse.getAsJsonObject()
.get("list").getAsJsonArray(), regulatoryAPIs, allowedRoles);
if (!unsubscribedAPIs.isEmpty()) {
//unsubscribe from the apis
for (String subscriptionId : unsubscribedAPIs) {
if (!callDelete(urlMap.get(GatewayConstants.API_GET_SUBSCRIBED).toString()
.concat("/").concat(subscriptionId), GatewayConstants.BEARER_TAG.concat(token))) {
log.error("Error while unsubscribing from APIs");
//delete SP created to call dev portal REST APIs
callDelete(urlMap.get(GatewayConstants.IAM_DCR_URL).toString().concat("/")
.concat(clientId), basicAuthHeader);
handleInternalServerError(obapiResponseContext,
OpenBankingErrorCodes.REGISTRATION_INTERNAL_ERROR);
return;
}
}
}
}
Expand All @@ -425,8 +438,12 @@ public void postProcessResponse(OBAPIResponseContext obapiResponseContext) {
handleInternalServerError(obapiResponseContext, OpenBankingErrorCodes.REGISTRATION_UPDATE_ERROR);
return;
}
List<String> apiIDList = filterRegulatorAPIs(regulatoryAPIs, publishedAPIsResponse.getAsJsonObject()
.get("list").getAsJsonArray(), allowedRoles);
List<String> apiIDList = (softwareStatementJson == null) ?
filterRegulatorAPIs(regulatoryAPIs, publishedAPIsResponse.getAsJsonObject()
.get("list").getAsJsonArray()) :
filterRegulatorAPIs(regulatoryAPIs, publishedAPIsResponse.getAsJsonObject()
.get("list").getAsJsonArray(), getRolesFromSSA(softwareStatementJson.toString()));

List<String> newApisListToSubscribe = getNewAPIsToSubscribe(apiIDList, subscribedAPIIdList);
if (!newApisListToSubscribe.isEmpty()) {
JsonArray subscribeAPIsPayload = getAPISubscriptionPayload(applicationId, newApisListToSubscribe);
Expand Down Expand Up @@ -736,6 +753,17 @@ protected List<String> filterRegulatorAPIs(Map<String, List<String>> regulatoryA
return filteredAPIs;
}

protected List<String> filterRegulatorAPIs(Map<String, List<String>> regulatoryAPINames, JsonArray publishedAPIs) {

List<String> filteredAPIs = new ArrayList<>();
for (JsonElement apiInfo : publishedAPIs) {
if(regulatoryAPINames.containsKey(apiInfo.getAsJsonObject().get("name").getAsString())) {
filteredAPIs.add(apiInfo.getAsJsonObject().get("id").getAsString());
}
}
return filteredAPIs;
}

@Generated(message = "Excluding from test coverage since it is an HTTP call")
protected JsonElement callGet(String endpoint, String authHeader, String queryParamKey, String paramValue)
throws IOException, OpenBankingException, URISyntaxException {
Expand Down Expand Up @@ -876,26 +904,25 @@ protected String getApplicationName(String responsePayload, Map<String, Object>
.get(OpenBankingConstants.DCR_USE_SOFTWAREID_AS_APPNAME).toString());
String applicationNameKey = configurations
.get(OpenBankingConstants.DCR_APPLICATION_NAME_KEY).toString();
String applicationName = "";
JsonParser jsonParser = new JsonParser();
JsonObject createdDCRAppDetails = ((JsonObject) jsonParser.parse(responsePayload));
String softwareStatement = createdDCRAppDetails.get(OpenBankingConstants.SOFTWARE_STATEMENT)
.getAsString();
JsonElement softwareStatementJson = createdDCRAppDetails.get(OpenBankingConstants.SOFTWARE_STATEMENT);

if(softwareStatementJson == null) {
return createdDCRAppDetails.get(OpenBankingConstants.SOFTWARE_ID).getAsString();
}
String softwareStatement = softwareStatementJson.getAsString();
JSONObject softwareStatementBody = JWTUtils.decodeRequestJWT(softwareStatement, "body");
//get application Name
if (isSoftwareIdAppName) {
if (softwareStatementBody.containsKey("software_id")) {
applicationName = softwareStatementBody.get("software_id").toString();
}
} else {
if (softwareStatementBody.containsKey(applicationNameKey)) {
applicationName = softwareStatementBody.get(applicationNameKey).toString();
} else {
applicationName = createdDCRAppDetails.get(applicationNameKey).toString();
if (softwareStatementBody.containsKey(OpenBankingConstants.SOFTWARE_ID)) {
return softwareStatementBody.get(OpenBankingConstants.SOFTWARE_ID).toString();
}
return null;
}

return applicationName;
return softwareStatementBody.containsKey(applicationNameKey) ?
softwareStatementBody.get(applicationNameKey).toString() :
createdDCRAppDetails.get(applicationNameKey).getAsString();
}

protected List<String> getUnAuthorizedAPIs(JsonArray subscribedAPIs, Map<String, List<String>> configuredAPIs,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,9 @@ public OBAPIRequestContext(RequestContextDTO requestContextDTO,
Map<String, String> contextProps, Map<String, Object> analyticsData) {

this.requestContextDTO = requestContextDTO;
this.contextProps = contextProps;
this.addedHeaders = new HashMap<>();
this.errors = new ArrayList<>();
this.contextProps = new HashMap<>();
this.contextProps = contextProps;
this.analyticsData = analyticsData;

Map<String, String> headers = requestContextDTO.getMsgInfo().getHeaders();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ public class RegistrationRequest {
@SerializedName("token_endpoint_auth_method")
private String tokenEndPointAuthMethod;

@SerializedName("jwks_uri")
private String jwksURI;

@SerializedName("grant_types")
private List<String> grantTypes;

Expand Down Expand Up @@ -108,6 +111,8 @@ public class RegistrationRequest {
@SerializedName("backchannel_user_code_parameter_supported")
private boolean backchannelUserCodeParameterSupported;



private SoftwareStatementBody softwareStatementBody;

private Map<String, Object> requestParameters;
Expand Down Expand Up @@ -353,4 +358,11 @@ public void setJti(String jti) {
this.jti = jti;
}

public String getJwksURI() {
return jwksURI;
}

public void setJwksURI(String jwksURI) {
this.jwksURI = jwksURI;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ public void setToken(String token) {
@SerializedName("software_id")
protected String softwareId = null;

@SerializedName("jwks_uri")
private String jwksURI;

@SerializedName("token_endpoint_auth_method")
protected String tokenEndpointAuthMethod = null;

Expand Down Expand Up @@ -206,4 +209,12 @@ public String getRegistrationClientURI() {
public void setRegistrationClientURI(String registrationClientURI) {
this.registrationClientURI = registrationClientURI;
}

public String getJwksURI() {
return jwksURI;
}

public void setJwksURI(String jwksURI) {
this.jwksURI = jwksURI;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.wso2.openbanking.accelerator.common.util.JWTUtils;
import com.wso2.openbanking.accelerator.identity.dcr.validation.annotation.ValidateIssuer;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

Expand Down Expand Up @@ -52,13 +53,14 @@ public boolean isValid(Object registrationRequest,

try {
String issuer = BeanUtils.getProperty(registrationRequest, issuerPath);
if (issuer != null) {
String softwareStatement = BeanUtils.getProperty(registrationRequest, ssaPath);
String softwareStatement = BeanUtils.getProperty(registrationRequest, ssaPath);
if (issuer != null && softwareStatement != null) {
String softwareId = JWTUtils.decodeRequestJWT(softwareStatement, "body")
.getAsString(DCRCommonConstants.SOFTWARE_ID);
if (softwareId != null && softwareId.equals(issuer)) {
return true;
}

} else {
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public boolean isValid(Object registrationRequestObject, ConstraintValidatorCont
.addConstraintViolation();
return false;
}
//validate string type required parameters
//validate list type required parameters
if (requestParameterMap.get(camelCaseConfigParam) instanceof List) {
List param = (List) requestParameterMap.get(camelCaseConfigParam);
if (param.isEmpty()) {
Expand Down
Loading

0 comments on commit b02ea52

Please sign in to comment.