Skip to content

Commit cb02c8f

Browse files
authored
Merge pull request #7 from hongwei1/feature/remove-hydra-obp-oidc-only
Berlin Group SCA redirect + consent form wording fix
2 parents 5b38cf8 + bc6aa36 commit cb02c8f

4 files changed

Lines changed: 50 additions & 76 deletions

File tree

src/main/java/com/openbankproject/hydra/auth/controller/IndexController.java

Lines changed: 44 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -575,23 +575,6 @@ public String main(@RequestParam("code") String code,
575575
return "error";
576576
}
577577
}
578-
String apiStandard = SessionData.getApiStandard(session);
579-
if(apiStandard.equalsIgnoreCase("BerlinGroup")){ // fetch Consent information
580-
HttpHeaders headers = new HttpHeaders();
581-
headers.setBearerAuth(SessionData.getAccessToken(session));
582-
HttpEntity<String> entity = new HttpEntity<>(headers);
583-
String consentId = SessionData.getConsentId(session);
584-
ResponseEntity<Map> response = restTemplate.exchange(getConsentInformationBerlinGroup.replace("CONSENT_ID", consentId), HttpMethod.GET, entity, Map.class);
585-
int frequencyPerDay = (int)response.getBody().get("frequencyPerDay");
586-
String consentStatus = (String)response.getBody().get("consentStatus");
587-
String validUntil = (String)response.getBody().get("validUntil");
588-
boolean recurringIndicator = (boolean)response.getBody().get("recurringIndicator");
589-
session.setAttribute("frequencyPerDay", String.valueOf(frequencyPerDay));
590-
session.setAttribute("consentStatus", consentStatus);
591-
session.setAttribute("validUntil", validUntil);
592-
session.setAttribute("recurringIndicator", String.valueOf(recurringIndicator));
593-
}
594-
595578
return "redirect:/main";
596579
}
597580

@@ -637,6 +620,26 @@ public String main(HttpSession session, Model model) {
637620
model.addAttribute("consentId", consentId);
638621
String consentRequestId = SessionData.getConsentRequestId(session);
639622
model.addAttribute("consentRequestId", consentRequestId);
623+
// Berlin Group has no OAuth token to hang this off (see requestConsentsBerlinGroup), so unlike
624+
// the other flows this can't be captured once at OIDC-callback time — fetch it fresh here,
625+
// authenticating with the Consent-ID header the same way getAccountsBerlinGroup does.
626+
if ("BerlinGroup".equalsIgnoreCase(apiStandard) && StringUtils.isNotBlank(consentId)) {
627+
try {
628+
HttpHeaders consentInfoHeaders = new HttpHeaders();
629+
consentInfoHeaders.add("Consent-ID", consentId);
630+
HttpEntity<String> consentInfoEntity = new HttpEntity<>(consentInfoHeaders);
631+
ResponseEntity<Map> consentInfoResponse = restTemplate.exchange(
632+
getConsentInformationBerlinGroup.replace("CONSENT_ID", consentId),
633+
HttpMethod.GET, consentInfoEntity, Map.class);
634+
Map consentInfoBody = consentInfoResponse.getBody();
635+
session.setAttribute("frequencyPerDay", String.valueOf(consentInfoBody.get("frequencyPerDay")));
636+
session.setAttribute("consentStatus", String.valueOf(consentInfoBody.get("consentStatus")));
637+
session.setAttribute("validUntil", String.valueOf(consentInfoBody.get("validUntil")));
638+
session.setAttribute("recurringIndicator", String.valueOf(consentInfoBody.get("recurringIndicator")));
639+
} catch (RestClientException e) {
640+
logger.warn("Could not fetch Berlin Group consent info for consent_id=" + consentId, e);
641+
}
642+
}
640643
String consentStatus = (String)session.getAttribute("consentStatus");
641644
model.addAttribute("consentStatus", consentStatus);
642645
String frequencyPerDay = (String)session.getAttribute("frequencyPerDay");
@@ -668,6 +671,12 @@ public String requestConsentsBerlinGroup(@RequestParam("bank") String bankId,
668671
String clientCredentialsToken = getClientCredentialsToken();
669672
HttpHeaders headers = new HttpHeaders();
670673
headers.setBearerAuth(clientCredentialsToken);
674+
// OBP-API stores these into the consent's JWT (ConsentUtil.createObpConsentBerlinGroup)
675+
// and Portal's SCA confirmation flow reads TPP-Redirect-URI back out of it to send the
676+
// browser here once the consent is ACCEPTED, so main() (params="!code") can render it
677+
// straight out of session — no OAuth code/token round-trip needed for Berlin Group.
678+
headers.add("TPP-Redirect-URI", redirectUri);
679+
headers.add("TPP-Nok-Redirect-URI", redirectUri);
671680
String recurringIndicator = recurring_indicator;
672681
String expirationDateTime = convertTimeFormat(expiration_time);
673682
// Berlin Group's `validUntil` is validated server-side as a plain yyyy-MM-dd date,
@@ -686,15 +695,28 @@ public String requestConsentsBerlinGroup(@RequestParam("bank") String bankId,
686695
Integer.parseInt(frequencyPerDay),
687696
false
688697
);
689-
String consentId = "";
698+
String consentId;
699+
String scaRedirectUrl;
690700
try {
691701
HttpEntity<PostConsentJson> request = new HttpEntity<>(body, headers);
692702
Map response = restTemplate.postForObject(createBerlinGroupConsentsUrl, request, Map.class);
693703
consentId = ((Map<String, String>) response).get("consentId");
694-
// main() reads this back via SessionData.getConsentId() when it later fetches the
695-
// Berlin Group consent info; a raw session.setAttribute("consent_id", ...) here writes
696-
// to a different storage slot and leaves that read null.
704+
Map links = (Map) response.get("_links");
705+
Map scaRedirect = links == null ? null : (Map) links.get("scaRedirect");
706+
scaRedirectUrl = scaRedirect == null ? null : (String) scaRedirect.get("href");
707+
if (StringUtils.isBlank(scaRedirectUrl)) {
708+
model.addAttribute("errorMsg", "OBP-API did not return a consent._links.scaRedirect URL "
709+
+ "to confirm this consent (response: " + response + "). Without it there is no way "
710+
+ "to complete Berlin Group's SCA step.");
711+
return "error";
712+
}
713+
// main() (params="!code") reads all of this straight out of session when the browser
714+
// lands back on redirectUri after SCA confirmation on Portal — Berlin Group's consent
715+
// is authorized via Consent-ID, not an OAuth token, so there's no code/id_token exchange
716+
// to do here the way the other flows need.
697717
SessionData.setConsentId(session, consentId);
718+
SessionData.setApiStandard(session, "BerlinGroup");
719+
SessionData.setBankId(session, bankId);
698720
} catch (HttpClientErrorException e) {
699721
String error = "Sorry! Cannot create the consent.";
700722
logger.error(error, e);
@@ -706,58 +728,10 @@ public String requestConsentsBerlinGroup(@RequestParam("bank") String bankId,
706728
return "index_bg";
707729
}
708730

709-
710-
//{"client_id", "bank_id", "consent_id", "response_type=code", "scope", "redirect_uri", "state"})
711-
Map<String, String> queryParam = new LinkedHashMap<>();
712-
queryParam.put("client_id", clientId);
713-
queryParam.put("response_type", "code+id_token");
714-
// include OBP scopes, add OAuth2 and OIDC related scope: "openid" and "offline"
715-
consents = ArrayUtils.addAll(new String[]{"openid", "offline"}, consents);
716-
String scope = Stream.of(consents)
717-
.distinct()
718-
.map(this::encodeQueryParam)
719-
.collect(Collectors.joining("+"));
720-
721-
queryParam.put("scope", scope);
722-
String encodeRedirectUri = URLEncoder.encode(redirectUri, "UTF-8");
723-
queryParam.put("redirect_uri", encodeRedirectUri);
724-
final String state = UUID.randomUUID().toString();
725-
final String nonce = UUID.randomUUID().toString();
726-
queryParam.put("state", state);
727-
queryParam.put("nonce", nonce);
728-
SessionData.setState(session, state);
729-
SessionData.setNonce(session, nonce);
730-
731-
// the parameter consent_id and bank_id are mandatory, these two parameter is not standard parameter of OAuth2 and OIDC
732-
queryParam.put("consent_id", consentId);
733-
queryParam.put("bank_id", bankId);
734-
String ibansTrimmed = Arrays.asList(ibans).stream()
735-
.map(n -> String.valueOf(n))
736-
.collect(Collectors.joining(","));
737-
queryParam.put("iban", ibansTrimmed);
738-
queryParam.put("recurring_indicator", recurring_indicator);
739-
queryParam.put("frequency_per_day", frequency_per_day);
740-
queryParam.put("expiration_time", expirationDateTime);
741-
queryParam.put("api_standard", "BerlinGroup");
742-
SessionData.setApiStandard(session, "BerlinGroup");
743-
// TODO the acr_values is just temp example value, can be space split values, need check and supply real values.
744-
//queryParam.put("acr_values", "urn:openbankproject:psd2:sca");
745-
746-
// add code_challenge
747-
final String codeVerifier = PKCEUtil.generateCodeVerifier();
748-
SessionData.setCodeVerifier(session, codeVerifier);
749-
final String codeChallenge = PKCEUtil.generateCodeChallenge(codeVerifier);
750-
queryParam.put("code_challenge_method", "S256");
751-
queryParam.put("code_challenge", codeChallenge);
752-
753-
String queryParamStr = queryParam.entrySet().stream().map(it -> it.getKey() + "=" + it.getValue()).collect(Collectors.joining("&"));
754-
String authorizationEndpoint = openIDConfiguration.getAuthorizationEndpoint();
755-
String redirectUrl = "redirect:" + authorizationEndpoint + "?" + queryParamStr;
756-
757731
// if current user is authenticated, remove user info from session, to do re-authentication
758732
SessionData.remoteUserInfo(session);
759733

760-
return redirectUrl;
734+
return "redirect:" + scaRedirectUrl;
761735
} catch (HttpStatusCodeException httpException) {
762736
logger.error("Error: ", httpException);
763737
String errorDetail = httpException.getStatusCode() + " " + httpException.getStatusText();

src/main/resources/templates/index_bg.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
<div class="row">
3535

3636
<div class="col-sm-6 col-lg-offset-3">
37-
<h2>Give Consent</h2>
37+
<h2>Create Consent</h2>
3838
<form th:action="@{/request_consents_bg}" method="post">
3939
<div class="form-group">
4040
<label for="bank">Select your Bank</label>
@@ -75,7 +75,7 @@ <h2>Give Consent</h2>
7575
checked>
7676
<label for="recurring_indicator">Recurring indicator</label>
7777
</div>
78-
<button type="submit" class="btn btn-danger">Give Consent</button>
78+
<button type="submit" class="btn btn-danger">Create Consent</button>
7979
</form>
8080
<div class="alert alert-info alert-dismissible col-md-12" role="alert" th:if="${errorMsg}">
8181
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>

src/main/resources/templates/index_uk.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
<div class="container">
3030
<div class="row">
3131
<div class="col-sm-6 col-lg-offset-3">
32-
<h2>Give Consent</h2>
32+
<h2>Create Consent</h2>
3333
<form th:action="@{/request_consents}" method="post">
3434
<div class="form-group">
3535
<label for="bank">Select your Bank</label>
@@ -64,7 +64,7 @@ <h2>Give Consent</h2>
6464
<label for="transaction_to_time">Expiration Date Time</label>
6565
<input type="text" name="expiration_time" id="expiration_time" class="form-control" data-date-format="YYYY-MM-DDTHH:mm:ss">
6666
</div>
67-
<button type="submit" class="btn btn-success">Give Consent</button>
67+
<button type="submit" class="btn btn-success">Create Consent</button>
6868
</form>
6969
</div>
7070
</div>

src/main/resources/templates/index_uk4.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
<div class="container">
3030
<div class="row">
3131
<div class="col-sm-6 col-lg-offset-3">
32-
<h2>Give Consent (UK Open Banking v4.0.1)</h2>
32+
<h2>Create Consent (UK Open Banking v4.0.1)</h2>
3333
<form th:action="@{/request_consents_uk4}" method="post">
3434
<div class="form-group">
3535
<label for="bank">Select your Bank</label>
@@ -64,7 +64,7 @@ <h2>Give Consent (UK Open Banking v4.0.1)</h2>
6464
<label for="transaction_to_time">Expiration Date Time</label>
6565
<input type="text" name="expiration_time" id="expiration_time" class="form-control" data-date-format="YYYY-MM-DDTHH:mm:ss">
6666
</div>
67-
<button type="submit" class="btn btn-success">Give Consent</button>
67+
<button type="submit" class="btn btn-success">Create Consent</button>
6868
</form>
6969
</div>
7070
</div>

0 commit comments

Comments
 (0)