Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ public enum ServiceExtensionTypeEnum {
ENRICH_EVENT_POLLING_RESPONSE("enrich_event_polling_response"),
MAP_ACCELERATOR_ERROR_RESPONSE("map_accelerator_error_response"),
PRE_PROCESS_APPLICATION_CREATION("pre_process_application_creation"),
PRE_PROCESS_APPLICATION_UPDATE("pre_process_application_update");
PRE_PROCESS_APPLICATION_UPDATE("pre_process_application_update"),
PRE_PROCESS_CONSENT_UPDATE("pre_process_consent_update"),
ENRICH_CONSENT_UPDATE_RESPONSE("enrich_consent_update_response");

private final String type;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public String getGetConsentWithConsentAttributesPreparedStatement() {

return "SELECT FS_CONSENT.CONSENT_ID, RECEIPT, CREATED_TIME, UPDATED_TIME, CLIENT_ID, CONSENT_TYPE, " +
"CURRENT_STATUS, CONSENT_FREQUENCY, VALIDITY_TIME, RECURRING_INDICATOR, " +
"FS_CONSENT_ATTRIBUTE.ATT_KEY, FS_CONSENT_ATTRIBUTE.ATT_VALUE FROM FS_CONSENT RIGHT JOIN " +
"FS_CONSENT_ATTRIBUTE.ATT_KEY, FS_CONSENT_ATTRIBUTE.ATT_VALUE FROM FS_CONSENT LEFT JOIN " +
"FS_CONSENT_ATTRIBUTE ON FS_CONSENT.CONSENT_ID = FS_CONSENT_ATTRIBUTE.CONSENT_ID WHERE FS_CONSENT" +
Comment on lines +44 to 45
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Handle null attribute rows before switching this query to LEFT JOIN.

With this join, a consent that has no rows in FS_CONSENT_ATTRIBUTE now comes back as a single row with ATT_KEY/ATT_VALUE = NULL. ConsentCoreDAOImpl.getConsentResourceWithAttributes(...) passes that ResultSet straight into ConsentManagementDAOUtil.setDataToConsentResourceWithAttributes(...), and that mapper currently does an unconditional put(getString(ATT_KEY), getString(ATT_VALUE)). The result is a malformed attributes map ({null=null}) instead of an empty one for attribute-less consents. Please either guard null/blank keys in the mapper or keep the old join semantics until that mapper is fixed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@financial-services-accelerator/components/org.wso2.financial.services.accelerator.consent.mgt.dao/src/main/java/org/wso2/financial/services/accelerator/consent/mgt/dao/queries/ConsentMgtCommonDBQueries.java`
around lines 44 - 45, The LEFT JOIN change can produce rows with
ATT_KEY/ATT_VALUE = NULL and the mapper
ConsentManagementDAOUtil.setDataToConsentResourceWithAttributes currently
unconditionally does put(getString(ATT_KEY), getString(ATT_VALUE)), producing
{null=null}; update the mapper to guard against null/blank keys (and optionally
null values) by skipping any ResultSet row where ATT_KEY is null/blank before
calling put, so ConsentCoreDAOImpl.getConsentResourceWithAttributes can safely
use the LEFT JOIN SQL in ConsentMgtCommonDBQueries without creating malformed
attribute entries.

".CONSENT_ID = ?";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,34 @@ public static JSONObject getInitiationResponse(Object responseObj, DetailedConse
return response;
}

/**
* Method to construct Initiation response.
*
* @param responseObj Response of the request
* @param createdConsent Consent response received from service layer
* @return JSONObject Initiation Response
*/
public static JSONObject getInitiationResponse(Object responseObj, ConsentResource createdConsent) {

JSONObject response = (JSONObject) responseObj;
JSONObject dataObject = response.getJSONObject(ConsentExtensionConstants.DATA);
dataObject.put(ConsentExtensionConstants.CONSENT_ID, createdConsent.getConsentID());
dataObject.put(ConsentExtensionConstants.CREATION_DATE_TIME, convertToISO8601(createdConsent.getCreatedTime()));
dataObject.put(ConsentExtensionConstants.STATUS_UPDATE_DATE_TIME,
convertToISO8601(createdConsent.getUpdatedTime()));
dataObject.put(ConsentExtensionConstants.STATUS, createdConsent.getCurrentStatus());

response.remove(ConsentExtensionConstants.DATA);
response.put(ConsentExtensionConstants.DATA, dataObject);

if (log.isDebugEnabled()) {
log.debug(String.format("Initiation response constructed for consent ID: %s with status: %s",
createdConsent.getConsentID().replaceAll("[\r\n]", ""),
createdConsent.getCurrentStatus().replaceAll("[\r\n]", "")));
}
return response;
}

/**
* Method to construct Retrieval Initiation response.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.wso2.financial.services.accelerator.consent.mgt.extensions.authorize.model.ConsentPersistData;
import org.wso2.financial.services.accelerator.consent.mgt.extensions.authorize.model.ExternalAPIPreConsentPersistRequestDTO;
import org.wso2.financial.services.accelerator.consent.mgt.extensions.authorize.model.ExternalAPIPreConsentPersistResponseDTO;
import org.wso2.financial.services.accelerator.consent.mgt.extensions.common.model.ExternalAPIBasicConsentResourceResponseDTO;
import org.wso2.financial.services.accelerator.consent.mgt.extensions.common.model.ExternalAPIConsentResourceResponseDTO;

import java.util.ArrayList;
Expand Down Expand Up @@ -439,4 +440,24 @@ private static ConsentMappingResource constructAmendedMappingResource(
return resource;
}

/**
* Combines all resolved data into a final {@link ConsentResource}.
*
* @param basicConsentResource The consent resource received from the external API pre-consent-update step.
* @param consentID Consent ID.
* @param clientID Client ID.
* @param createTime Consent Created timestamp.
* @return A fully constructed {@link ConsentResource}.
*/
public static ConsentResource buildConsentResource(ExternalAPIBasicConsentResourceResponseDTO basicConsentResource,
String consentID, String clientID, long createTime) {

String receipt = basicConsentResource.getReceipt() != null ?
new JSONObject(basicConsentResource.getReceipt()).toString() : "{}";
return new ConsentResource(consentID, clientID, receipt, basicConsentResource.getType(),
basicConsentResource.getFrequency(), basicConsentResource.getValidityTime(),
basicConsentResource.getRecurringIndicator(), basicConsentResource.getStatus(),
createTime, 0);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/**
* Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com).
* <p>
* WSO2 LLC. 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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 org.wso2.financial.services.accelerator.consent.mgt.extensions.common.model;

import org.json.JSONObject;
import org.wso2.financial.services.accelerator.consent.mgt.dao.models.ConsentResource;

import java.util.Collections;
import java.util.Map;

/**
* Basic Consent resource model for the API extension consent management.
*/
public class ExternalAPIBasicConsentResourceRequestDTO {

private String id;
private String clientId;
private String type;
private String status;
private int frequency;
private long validityTime;
private long createdTime;
private long updatedTime;
private boolean recurringIndicator;
private Map<String, Object> receipt;
private Map<String, String> attributes;

public ExternalAPIBasicConsentResourceRequestDTO(ConsentResource consentResource) {

this.id = consentResource.getConsentID();
this.clientId = consentResource.getClientID();
this.type = consentResource.getConsentType();
this.status = consentResource.getCurrentStatus();
this.frequency = consentResource.getConsentFrequency();
this.validityTime = consentResource.getValidityPeriod();
this.createdTime = consentResource.getCreatedTime();
this.updatedTime = consentResource.getUpdatedTime();
this.recurringIndicator = consentResource.isRecurringIndicator();

if (consentResource.getReceipt() != null && !consentResource.getReceipt().isEmpty()) {
JSONObject receiptJson = new JSONObject(consentResource.getReceipt());
this.receipt = receiptJson.toMap();
} else {
this.receipt = Collections.emptyMap();
}
this.attributes = consentResource.getConsentAttributes();
}

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getClientId() {
return clientId;
}

public void setClientId(String clientId) {
this.clientId = clientId;
}

public String getType() {
return type;
}

public void setType(String type) {
this.type = type;
}

public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}

public int getFrequency() {
return frequency;
}

public void setFrequency(int frequency) {
this.frequency = frequency;
}

public long getValidityTime() {
return validityTime;
}

public void setValidityTime(long validityTime) {
this.validityTime = validityTime;
}

public long getCreatedTime() {
return createdTime;
}

public void setCreatedTime(long createdTime) {
this.createdTime = createdTime;
}

public long getUpdatedTime() {
return updatedTime;
}

public void setUpdatedTime(long updatedTime) {
this.updatedTime = updatedTime;
}

public boolean getRecurringIndicator() {
return recurringIndicator;
}

public void setRecurringIndicator(boolean recurringIndicator) {
this.recurringIndicator = recurringIndicator;
}

public Map<String, Object> getReceipt() {
return receipt;
}

public void setReceipt(Map<String, Object> receipt) {
this.receipt = receipt;
}

public Map<String, String> getAttributes() {
return attributes;
}

public void setAttributes(Map<String, String> attributes) {
this.attributes = attributes;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/**
* Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com).
* <p>
* WSO2 LLC. 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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 org.wso2.financial.services.accelerator.consent.mgt.extensions.common.model;

import java.util.Map;

/**
* Basic Consent resource response model for the API extension consent management.
*/
public class ExternalAPIBasicConsentResourceResponseDTO {

private String type;
private String status;
private Integer frequency;
private Long validityTime;
private Boolean recurringIndicator;
private Map<String, Object> receipt;
private Map<String, String> attributes;

public String getType() {
return type;
}

public void setType(String type) {
this.type = type;
}

public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}

public Integer getFrequency() {
return frequency;
}

public void setFrequency(Integer frequency) {
this.frequency = frequency;
}

public Long getValidityTime() {
return validityTime;
}

public void setValidityTime(Long validityTime) {
this.validityTime = validityTime;
}

public Boolean getRecurringIndicator() {
return recurringIndicator;
}

public void setRecurringIndicator(Boolean recurringIndicator) {
this.recurringIndicator = recurringIndicator;
}

public Map<String, Object> getReceipt() {
return receipt;
}

public void setReceipt(Map<String, Object> receipt) {
this.receipt = receipt;
}

public Map<String, String> getAttributes() {
return attributes;
}

public void setAttributes(Map<String, String> attributes) {
this.attributes = attributes;
}
}
Loading