mirror of
https://github.com/OpenBankProject/OBP-Hydra-Identity-Provider.git
synced 2026-02-06 10:48:13 +00:00
feature/Add utility to list and delete consents
This commit is contained in:
parent
7164fa1970
commit
d6e1991ac8
@ -125,7 +125,9 @@ public class RestTemplateConfig {
|
||||
// Get HTTP body from the response
|
||||
String httpBody = "";
|
||||
try {
|
||||
httpBody = getHttpResponseBody(response.getEntity().getContent()).toString();
|
||||
if(response.getEntity() != null && response.getEntity().getContent() != null) {
|
||||
httpBody = getHttpResponseBody(response.getEntity().getContent()).toString();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package com.openbankproject.oauth2.controller;
|
||||
import com.nimbusds.jose.util.X509CertUtils;
|
||||
import com.openbankproject.oauth2.model.AccessToViewRequest;
|
||||
import com.openbankproject.oauth2.model.Accounts;
|
||||
import com.openbankproject.oauth2.model.ConsentsInfo;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
@ -47,10 +48,14 @@ public class ConsentController {
|
||||
private String getAccountsUrl;
|
||||
@Value("${obp.base_url}/berlin-group/v1.3/consents")
|
||||
private String createBerlinGroupConsentsUrl;
|
||||
@Value("${obp.base_url}/obp/v4.0.0/banks/BANK_ID/my/consents")
|
||||
private String getConsentsUrl;
|
||||
@Value("${obp.base_url}/berlin-group/v1.3/consents/CONSENT_ID/authorisations")
|
||||
private String startConsentAuthorisation;
|
||||
@Value("${obp.base_url}/berlin-group/v1.3/consents/CONSENT_ID/authorisations/AUTHORISATION_ID")
|
||||
private String updateConsentsPsuData;
|
||||
@Value("${obp.base_url}/berlin-group/v1.3/consents/CONSENT_ID")
|
||||
private String deleteConsentBerlinGroup;
|
||||
@Value("${oauth2.admin_url}/keys/${oauth2.broadcast_keys:hydra.jwt.access-token}")
|
||||
private String keySetUrl;
|
||||
@Value("${show_unhandled_errors:false}")
|
||||
@ -94,8 +99,17 @@ public class ConsentController {
|
||||
return "error";
|
||||
}
|
||||
|
||||
String bankId = (String) session.getAttribute("bank_id");
|
||||
String consentId = (String) session.getAttribute("consent_id");
|
||||
if(consentId.equalsIgnoreCase("Utility-List-Consents")) {
|
||||
HttpHeaders headers = buildDirectLoginHeader(session);
|
||||
HttpEntity<String> entity = new HttpEntity<>(headers);
|
||||
ResponseEntity<ConsentsInfo> consents = restTemplate.exchange(getConsentsUrl.replace("BANK_ID", bankId), HttpMethod.GET, entity, ConsentsInfo.class);
|
||||
model.addAttribute("consents", consents.getBody().getConsents());
|
||||
return "consents";
|
||||
}
|
||||
|
||||
{ // prepare account list
|
||||
String bankId = (String) session.getAttribute("bank_id");
|
||||
String apiStandard = (String) session.getAttribute("api_standard");
|
||||
model.addAttribute("apiStandard", apiStandard);
|
||||
HttpHeaders headers = buildDirectLoginHeader(session);
|
||||
@ -169,6 +183,38 @@ public class ConsentController {
|
||||
}
|
||||
|
||||
|
||||
@PostMapping(value="/revoke_consents", params = "consent_challenge")
|
||||
public String revokeConsents(@RequestParam String consent_challenge,
|
||||
@RequestParam(value="consents", required = false) String[] consentIds,
|
||||
@RequestParam(value="deny",required = false) String deny,
|
||||
HttpSession session, Model model) throws NoSuchAlgorithmException, ApiException {
|
||||
if(StringUtils.isNotBlank(deny)) {
|
||||
final RejectRequest rejectRequest = new RejectRequest().error("access_denied").errorDescription("The resource owner denied the request");
|
||||
final CompletedRequest completedRequest = adminApi.rejectConsentRequest(consent_challenge, rejectRequest);
|
||||
return "redirect:" + completedRequest.getRedirectTo();
|
||||
}
|
||||
if(ArrayUtils.isEmpty(consentIds)) {
|
||||
model.addAttribute("errorMsg", "consents field is mandatory!");
|
||||
return "error";
|
||||
}
|
||||
|
||||
try { // Delete all selected consents
|
||||
HttpHeaders headers = buildDirectLoginHeader(session);
|
||||
HttpEntity<String> entity = new HttpEntity<>(headers);
|
||||
for (String consentId : consentIds) {
|
||||
String url = deleteConsentBerlinGroup.replace("CONSENT_ID", consentId);
|
||||
ResponseEntity<Map> deletedConsent = restTemplate.exchange(url, HttpMethod.DELETE, entity, Map.class);
|
||||
logger.debug("ConsentID: " + consentId + " is deleted: " + deletedConsent.getStatusCodeValue());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Cannot delete consents!", e);
|
||||
model.addAttribute("errorMsg", "Cannot delete consents!");
|
||||
return "error";
|
||||
}
|
||||
model.addAttribute("errorMsg", "All selected consents have been deleted!");
|
||||
return "error";
|
||||
}
|
||||
|
||||
@PostMapping(value="/sca1", params = "consent_challenge")
|
||||
public String resetAccessToViews(@RequestParam String consent_challenge,
|
||||
@RequestParam(value="accounts", required = false) String[] accountIs,
|
||||
|
||||
@ -86,32 +86,36 @@ public class LoginController implements ServletContextAware {
|
||||
String requestUrl = loginRequest.getRequestUrl();
|
||||
String consentId = getConsentId(requestUrl);
|
||||
String bankId = getBankId(requestUrl);
|
||||
String iban = getIban(requestUrl);
|
||||
String recurringIndicator = getRecurringIndicator(requestUrl);
|
||||
String frequencyPerDay = getFrequencyPerDay(requestUrl);
|
||||
String expirationTime = getExpirationTime(requestUrl);
|
||||
String apiStandard = getApiStandard(requestUrl);
|
||||
final List<String> acrValues = loginRequest.getOidcContext().getAcrValues();
|
||||
if(bankId == null) {
|
||||
model.addAttribute("errorMsg", "Query parameter `bank_id` is mandatory! ");
|
||||
return "error";
|
||||
}
|
||||
if(consentId == null) {
|
||||
final String createConsentUrl = getConsentUrl.replace("/CONSENT_ID", "");
|
||||
model.addAttribute(
|
||||
"errorMsg", "Query parameter `consent_id` is mandatory! " +
|
||||
"Hint: create client_credentials accessToken, create Account Access Consents by call endpoint `CreateAccountAccessConsents` (" +
|
||||
createConsentUrl +
|
||||
"), " +
|
||||
"with header Authorization: Authorization: Bearer <accessToken>");
|
||||
return "error";
|
||||
}
|
||||
// TODO acr value should do more validation
|
||||
if(consentId.equalsIgnoreCase("Utility-List-Consents")) {
|
||||
session.setAttribute("consent_id", consentId);
|
||||
session.setAttribute("bank_id", bankId);
|
||||
} else {
|
||||
String iban = getIban(requestUrl);
|
||||
String recurringIndicator = getRecurringIndicator(requestUrl);
|
||||
String frequencyPerDay = getFrequencyPerDay(requestUrl);
|
||||
String expirationTime = getExpirationTime(requestUrl);
|
||||
String apiStandard = getApiStandard(requestUrl);
|
||||
final List<String> acrValues = loginRequest.getOidcContext().getAcrValues();
|
||||
if(bankId == null) {
|
||||
model.addAttribute("errorMsg", "Query parameter `bank_id` is mandatory! ");
|
||||
return "error";
|
||||
}
|
||||
if(consentId == null) {
|
||||
final String createConsentUrl = getConsentUrl.replace("/CONSENT_ID", "");
|
||||
model.addAttribute(
|
||||
"errorMsg", "Query parameter `consent_id` is mandatory! " +
|
||||
"Hint: create client_credentials accessToken, create Account Access Consents by call endpoint `CreateAccountAccessConsents` (" +
|
||||
createConsentUrl +
|
||||
"), " +
|
||||
"with header Authorization: Authorization: Bearer <accessToken>");
|
||||
return "error";
|
||||
}
|
||||
// TODO acr value should do more validation
|
||||
// if(CollectionUtils.isEmpty(acrValues)) {
|
||||
// model.addAttribute("errorMsg", "Query parameter `acr_values` is mandatory! ");
|
||||
// return "error";
|
||||
// }
|
||||
// TODO in order make old consumer works, the request and request_uri are optional.
|
||||
// TODO in order make old consumer works, the request and request_uri are optional.
|
||||
// if(!requestUrl.contains("request") && !requestUrl.contains("request_uri")) {
|
||||
// model.addAttribute(
|
||||
// "errorMsg", "Query parameter `request` and `request_uri` at least one must be supplied! " +
|
||||
@ -119,39 +123,39 @@ public class LoginController implements ServletContextAware {
|
||||
// return "error";
|
||||
// }
|
||||
|
||||
try {
|
||||
if(!apiStandard.equalsIgnoreCase("BerlinGroup"))
|
||||
{// validate consentId
|
||||
Map<String, Object> responseBody = idVerifier.apply(getConsentUrl.replace("CONSENT_ID", consentId));
|
||||
Map<String, Object> data = ((Map<String, Object>) responseBody.get("Data"));
|
||||
if(data == null || data.isEmpty()) {
|
||||
model.addAttribute("errorMsg", "Consent content have no required Data field");
|
||||
return "error";
|
||||
}
|
||||
try {
|
||||
if(!apiStandard.equalsIgnoreCase("BerlinGroup"))
|
||||
{// validate consentId
|
||||
Map<String, Object> responseBody = idVerifier.apply(getConsentUrl.replace("CONSENT_ID", consentId));
|
||||
Map<String, Object> data = ((Map<String, Object>) responseBody.get("Data"));
|
||||
if(data == null || data.isEmpty()) {
|
||||
model.addAttribute("errorMsg", "Consent content have no required Data field");
|
||||
return "error";
|
||||
}
|
||||
|
||||
String status = ((String) data.get("Status"));
|
||||
if(!"AWAITINGAUTHORISATION".equals(status)) {
|
||||
model.addAttribute("errorMsg", "The Consent status should be AWAITINGAUTHORISATION, but current status is " + status);
|
||||
return "error";
|
||||
String status = ((String) data.get("Status"));
|
||||
if(!"AWAITINGAUTHORISATION".equals(status)) {
|
||||
model.addAttribute("errorMsg", "The Consent status should be AWAITINGAUTHORISATION, but current status is " + status);
|
||||
return "error";
|
||||
}
|
||||
}
|
||||
{// validate bankId
|
||||
idVerifier.apply(getBankUrl.replace("BANK_ID", bankId));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
model.addAttribute("errorMsg", e.getMessage());
|
||||
return "error";
|
||||
}
|
||||
{// validate bankId
|
||||
idVerifier.apply(getBankUrl.replace("BANK_ID", bankId));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
model.addAttribute("errorMsg", e.getMessage());
|
||||
return "error";
|
||||
|
||||
session.setAttribute("consent_id", consentId);
|
||||
session.setAttribute("bank_id", bankId);
|
||||
session.setAttribute("iban", iban);
|
||||
session.setAttribute("recurring_indicator", recurringIndicator);
|
||||
session.setAttribute("frequency_per_day", frequencyPerDay);
|
||||
session.setAttribute("expiration_time", expirationTime);
|
||||
session.setAttribute("api_standard", apiStandard);
|
||||
session.setAttribute("acr_values", acrValues);
|
||||
}
|
||||
|
||||
session.setAttribute("consent_id", consentId);
|
||||
session.setAttribute("bank_id", bankId);
|
||||
session.setAttribute("iban", iban);
|
||||
session.setAttribute("recurring_indicator", recurringIndicator);
|
||||
session.setAttribute("frequency_per_day", frequencyPerDay);
|
||||
session.setAttribute("expiration_time", expirationTime);
|
||||
session.setAttribute("api_standard", apiStandard);
|
||||
session.setAttribute("acr_values", acrValues);
|
||||
|
||||
// login before and checked rememberMe.
|
||||
if(loginRequest.getSkip() && session.getAttribute("directLoginToken") != null) {
|
||||
AcceptLoginRequest acceptLoginRequest = new AcceptLoginRequest();
|
||||
|
||||
@ -0,0 +1,88 @@
|
||||
package com.openbankproject.oauth2.model;
|
||||
|
||||
public class ConsentsInfo {
|
||||
private ConsentInfo[] consents;
|
||||
|
||||
public ConsentInfo[] getConsents() {
|
||||
return consents;
|
||||
}
|
||||
|
||||
public void setConsents(ConsentInfo[] consents) {
|
||||
this.consents = consents;
|
||||
}
|
||||
}
|
||||
|
||||
class ConsentInfo {
|
||||
private String consent_id;
|
||||
private String consumer_id;
|
||||
private String created_by_user_id;
|
||||
private String last_action_date;
|
||||
private String last_usage_date;
|
||||
private String status;
|
||||
private String api_standard;
|
||||
private String api_version;
|
||||
|
||||
public String getConsent_id() {
|
||||
return consent_id;
|
||||
}
|
||||
|
||||
public void setConsent_id(String consent_id) {
|
||||
this.consent_id = consent_id;
|
||||
}
|
||||
|
||||
public String getConsumer_id() {
|
||||
return consumer_id;
|
||||
}
|
||||
|
||||
public void setConsumer_id(String consumer_id) {
|
||||
this.consumer_id = consumer_id;
|
||||
}
|
||||
|
||||
public String getCreated_by_user_id() {
|
||||
return created_by_user_id;
|
||||
}
|
||||
|
||||
public void setCreated_by_user_id(String created_by_user_id) {
|
||||
this.created_by_user_id = created_by_user_id;
|
||||
}
|
||||
|
||||
public String getLast_action_date() {
|
||||
return last_action_date;
|
||||
}
|
||||
|
||||
public void setLast_action_date(String last_action_date) {
|
||||
this.last_action_date = last_action_date;
|
||||
}
|
||||
|
||||
public String getLast_usage_date() {
|
||||
return last_usage_date;
|
||||
}
|
||||
|
||||
public void setLast_usage_date(String last_usage_date) {
|
||||
this.last_usage_date = last_usage_date;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(String status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getApi_standard() {
|
||||
return api_standard;
|
||||
}
|
||||
|
||||
public void setApi_standard(String api_standard) {
|
||||
this.api_standard = api_standard;
|
||||
}
|
||||
|
||||
public String getApi_version() {
|
||||
return api_version;
|
||||
}
|
||||
|
||||
public void setApi_version(String api_version) {
|
||||
this.api_version = api_version;
|
||||
}
|
||||
}
|
||||
85
src/main/resources/templates/consents.html
Normal file
85
src/main/resources/templates/consents.html
Normal file
@ -0,0 +1,85 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>OBP Identity Provider - List Consents</title>
|
||||
|
||||
<!-- Bootstrap -->
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/css/bootstrap.min.css}" />
|
||||
|
||||
<!--[if lt IE 9]>
|
||||
<script type="text/javascript" th:src="@{/js/html5shiv.min.js}"></script>
|
||||
<script type="text/javascript" th:src="@{/js/respond.min.js}" ></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-light bg-light">
|
||||
<a class="navbar-brand" th:href="@{${application.obp_url}}">
|
||||
<img th:src="@{/images/bank-logo.png}" height="60" class="d-inline-block align-top" alt="">
|
||||
</a>
|
||||
</nav>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-lg-offset-3">
|
||||
<h2>My Consents</h2>
|
||||
<form th:action="@{/revoke_consents}" method="post" id="accept_form">
|
||||
<div class="form-group">
|
||||
<div>
|
||||
<div class="checkbox" th:each="consent : ${consents}">
|
||||
<label>
|
||||
<input type="checkbox" name="consents" th:value="${consent.consent_id}">
|
||||
<span th:text="${consent.consent_id}">Some account</span> - <span th:text="${consent.status}">Some account</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<span class="text-danger" id="accounts_error"></span>
|
||||
</div>
|
||||
<input type="hidden" th:name="consent_challenge" th:value="${consent_challenge}">
|
||||
|
||||
<div class="btn-toolbar">
|
||||
<button type="button" class="btn btn-danger" id="deny_btn">Cancel</button>
|
||||
<button type="submit" class="btn btn-success" name="submit" value="Confirm">Delete</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<form th:action="@{/revoke_consents}" method="post" id="reject_form" class="hidden">
|
||||
<input type="hidden" th:name="consent_challenge" th:value="${consent_challenge}">
|
||||
<input type="hidden" th:name="deny" th:value="deny">
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" th:src="@{/js/jquery-1.12.4.min.js}" ></script>
|
||||
<script type="text/javascript" th:src="@{/js/jquery-validate-1.19.2.min.js}" ></script>
|
||||
<script type="text/javascript" th:src="@{/js/bootstrap.min.js}" ></script>
|
||||
<script type="text/javascript">
|
||||
$(function(){
|
||||
$("#accept_form").validate({
|
||||
rules: {
|
||||
consents: "required",
|
||||
},
|
||||
messages: {
|
||||
consents: "At least select one consent",
|
||||
},
|
||||
errorPlacement: function(error, element) {
|
||||
if (element.attr("name") == "consents") {
|
||||
error.appendTo("#accounts_error");
|
||||
} else {
|
||||
error.insertAfter(element);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$('#deny_btn').click(function(){
|
||||
$('#reject_form').submit();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue
Block a user