From d6e1991ac8fd77cb6ae1e7f98cc4356f2d9ce71d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Mili=C4=87?= Date: Fri, 7 May 2021 13:51:54 +0200 Subject: [PATCH] feature/Add utility to list and delete consents --- .../oauth2/RestTemplateConfig.java | 4 +- .../oauth2/controller/ConsentController.java | 48 +++++++- .../oauth2/controller/LoginController.java | 106 +++++++++--------- .../oauth2/model/ConsentsInfo.java | 88 +++++++++++++++ src/main/resources/templates/consents.html | 85 ++++++++++++++ 5 files changed, 278 insertions(+), 53 deletions(-) create mode 100644 src/main/java/com/openbankproject/oauth2/model/ConsentsInfo.java create mode 100644 src/main/resources/templates/consents.html diff --git a/src/main/java/com/openbankproject/oauth2/RestTemplateConfig.java b/src/main/java/com/openbankproject/oauth2/RestTemplateConfig.java index 7c22f61..6951874 100644 --- a/src/main/java/com/openbankproject/oauth2/RestTemplateConfig.java +++ b/src/main/java/com/openbankproject/oauth2/RestTemplateConfig.java @@ -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(); } diff --git a/src/main/java/com/openbankproject/oauth2/controller/ConsentController.java b/src/main/java/com/openbankproject/oauth2/controller/ConsentController.java index a521770..9b53eb0 100644 --- a/src/main/java/com/openbankproject/oauth2/controller/ConsentController.java +++ b/src/main/java/com/openbankproject/oauth2/controller/ConsentController.java @@ -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 entity = new HttpEntity<>(headers); + ResponseEntity 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 entity = new HttpEntity<>(headers); + for (String consentId : consentIds) { + String url = deleteConsentBerlinGroup.replace("CONSENT_ID", consentId); + ResponseEntity 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, diff --git a/src/main/java/com/openbankproject/oauth2/controller/LoginController.java b/src/main/java/com/openbankproject/oauth2/controller/LoginController.java index e2d7e0d..358c360 100644 --- a/src/main/java/com/openbankproject/oauth2/controller/LoginController.java +++ b/src/main/java/com/openbankproject/oauth2/controller/LoginController.java @@ -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 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 "); - 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 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 "); + 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 responseBody = idVerifier.apply(getConsentUrl.replace("CONSENT_ID", consentId)); - Map data = ((Map) 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 responseBody = idVerifier.apply(getConsentUrl.replace("CONSENT_ID", consentId)); + Map data = ((Map) 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(); diff --git a/src/main/java/com/openbankproject/oauth2/model/ConsentsInfo.java b/src/main/java/com/openbankproject/oauth2/model/ConsentsInfo.java new file mode 100644 index 0000000..912b466 --- /dev/null +++ b/src/main/java/com/openbankproject/oauth2/model/ConsentsInfo.java @@ -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; + } +} diff --git a/src/main/resources/templates/consents.html b/src/main/resources/templates/consents.html new file mode 100644 index 0000000..ee99b9e --- /dev/null +++ b/src/main/resources/templates/consents.html @@ -0,0 +1,85 @@ + + + + + + + OBP Identity Provider - List Consents + + + + + + + + +
+
+
+

My Consents

+
+
+
+
+ +
+
+ +
+ + +
+ + +
+
+ + + +
+
+
+ + + + + + + \ No newline at end of file