-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Validating BNR permission for consent revocation #66
Merged
Merged
Changes from 4 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
8b3a849
Add BNR permission validation for consent revoke
anjuchamantha d604016
Merge branch 'main' into bnr-revoke
anjuchamantha d195dd3
Bug fix - checking can_revoke in consentmgr
anjuchamantha 7d0558a
Remove checking for REVOKED BNR status
anjuchamantha e7670fa
Fixing a comment
anjuchamantha bc8b123
Refactoring handle revoke logic for BNR
anjuchamantha File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,8 +54,10 @@ | |
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.HashMap; | ||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Set; | ||
import java.util.stream.Collectors; | ||
|
||
import static org.wso2.openbanking.cds.consent.extensions.common.CDSConsentExtensionConstants.AUTH_RESOURCE_TYPE_PRIMARY; | ||
|
@@ -110,6 +112,11 @@ public void handleSearch(ConsentAdminData consentAdminData) throws ConsentExcept | |
throw new OpenBankingRuntimeException("Error while adding sharing dates to permissions", e); | ||
} | ||
} | ||
|
||
if (consentAdminData.getQueryParams().containsKey(CDSConsentExtensionConstants.CONSENT_IDS_QUERY_PARAM_NAME)) { | ||
addBNRRevokeStatus(consentAdminData); | ||
} | ||
|
||
} | ||
|
||
@Override | ||
|
@@ -124,6 +131,16 @@ public void handleRevoke(ConsentAdminData consentAdminData) throws ConsentExcept | |
final String userID = validateAndGetQueryParam(queryParams, USER_ID); | ||
DetailedConsentResource detailedConsentResource = this.consentCoreService.getDetailedConsent(consentID); | ||
if (detailedConsentResource != null) { | ||
ArrayList<String> userIDs = (ArrayList<String>) consentAdminData.getQueryParams() | ||
.get(CDSConsentExtensionConstants.USER_ID_KEY_NAME); | ||
// userIDs can be null or empty when the request comes from a CustomerCareOfficer | ||
if (userIDs != null && !userIDs.isEmpty()) { | ||
String userId = userIDs.get(0); | ||
if (!canRevokeByBNR(detailedConsentResource, userId)) { | ||
throw new ConsentException(ResponseStatus.FORBIDDEN, | ||
"User is not authorized to revoke the consent"); | ||
} | ||
} | ||
if (StringUtils.isNotBlank(userID) && !isPrimaryUserRevoking(detailedConsentResource, userID)) { | ||
// Deactivate consent mappings as secondary consent holder | ||
deactivateAccountMappings(detailedConsentResource, userID); | ||
|
@@ -521,6 +538,91 @@ private boolean isActionByPrimaryUser(DetailedConsentResource detailedConsentRes | |
return false; | ||
} | ||
|
||
private void addBNRRevokeStatus(ConsentAdminData consentAdminData) { | ||
|
||
JSONObject responsePayload = consentAdminData.getResponsePayload(); | ||
JSONArray consentData = (JSONArray) responsePayload.get(CDSConsentExtensionConstants.DATA); | ||
ArrayList<String> userIDs = (ArrayList<String>) consentAdminData.getQueryParams() | ||
.get(CDSConsentExtensionConstants.USER_IDS_QUERY_PARAM_NAME); | ||
if (userIDs == null || userIDs.isEmpty()) { | ||
// Customer care officer scenario | ||
consentData.forEach(consent -> { | ||
JSONObject consentObject = (JSONObject) consent; | ||
consentObject.put(CDSConsentExtensionConstants.CAN_REVOKE, true); | ||
}); | ||
} else { | ||
String userId = userIDs.get(0); | ||
consentData.forEach(consent -> { | ||
JSONObject consentObject = (JSONObject) consent; | ||
consentObject.put(CDSConsentExtensionConstants.CAN_REVOKE, canRevokeByBNR(consentAdminData, userId)); | ||
}); | ||
} | ||
} | ||
|
||
private boolean canRevokeByBNR(DetailedConsentResource detailedConsentResource, String userId) { | ||
|
||
Set<String> activeAccountIDs = new HashSet<>(); | ||
for (ConsentMappingResource consentMappingResource : detailedConsentResource.getConsentMappingResources()) { | ||
if (consentMappingResource.getMappingStatus().equals(CDSConsentExtensionConstants.ACTIVE_STATUS)) { | ||
activeAccountIDs.add(consentMappingResource.getAccountID()); | ||
} | ||
} | ||
|
||
return canRevokeByBNR(activeAccountIDs, userId); | ||
} | ||
|
||
private boolean canRevokeByBNR(ConsentAdminData consentAdminData, String userId) { | ||
|
||
Set<String> activeAccountIDs = new HashSet<>(); | ||
|
||
for (Object item : (JSONArray) consentAdminData.getResponsePayload(). | ||
get(CDSConsentExtensionConstants.DATA)) { | ||
JSONObject itemJSONObject = (JSONObject) item; | ||
JSONArray consentMappingResourcesArray = (JSONArray) itemJSONObject. | ||
get(CDSConsentExtensionConstants.CONSENT_MAPPING_RESOURCES); | ||
for (Object consentMappingResource : consentMappingResourcesArray) { | ||
JSONObject consentMappingResourceObject = (JSONObject) consentMappingResource; | ||
if (consentMappingResourceObject.getAsString(CDSConsentExtensionConstants.MAPPING_STATUS). | ||
equals(CDSConsentExtensionConstants.ACTIVE_STATUS)) { | ||
activeAccountIDs.add(consentMappingResourceObject.getAsString( | ||
CDSConsentExtensionConstants.ACCOUNT_ID)); | ||
} | ||
} | ||
} | ||
return canRevokeByBNR(activeAccountIDs, userId); | ||
} | ||
|
||
private boolean canRevokeByBNR(Set<String> activeAccountIDs, String userId) { | ||
|
||
if (activeAccountIDs.isEmpty()) { | ||
return true; | ||
} | ||
|
||
AccountMetadataServiceImpl accountMetadataService = AccountMetadataServiceImpl.getInstance(); | ||
|
||
/* | ||
* For all the active accounts, if the user has AUTHORIZE or REVOKE permission for BNR, then the user can | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. User can revoke the consent only if he has authorize permission. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed with e7670fa |
||
* revoke that consent. (i.e. For any given active account in consent mappings, if the user does not have | ||
* AUTHORIZE or REVOKE permission, he/she cannot revoke the consent) | ||
*/ | ||
for (String accountID : activeAccountIDs) { | ||
try { | ||
String permissionStatus = accountMetadataService.getAccountMetadataByKey(accountID, userId, | ||
CDSConsentExtensionConstants.BNR_PERMISSION); | ||
if (StringUtils.isNotBlank(permissionStatus) && | ||
!(CDSConsentExtensionConstants.BNR_AUTHORIZE_PERMISSION.equals(permissionStatus))) { | ||
|
||
return false; | ||
} | ||
} catch (OpenBankingException e) { | ||
log.error(e.getMessage()); | ||
throw new OpenBankingRuntimeException("Error while getting BNR permissions.", e); | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
|
||
public void updateDOMSStatusForConsentData(ConsentAdminData consentAdminData) { | ||
try { | ||
AccountMetadataService accountMetadataService = AccountMetadataServiceImpl.getInstance(); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when can there be a list of userIDs? because usually revoke is done by a single user right? If there is a scenario when a list of userIDs can come shall we add that as a comment as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is because
consentAdminData.getQueryParams()
returns a Map, and and.get(<key>)
returns an array list. That doesn't mean that we can have multiple userIDs for revoke. SinceConsentAdminData
is a common class we cannot change that behaviour for revoke only.For this scenario (revoking a consent from consent manager) we only have 1 user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was already a
validateAndGetQueryParam
method to get the first element from query params. Modified with bc8b123