001/* 002 * oauth2-oidc-sdk 003 * 004 * Copyright 2012-2016, Connect2id Ltd and contributors. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 007 * this file except in compliance with the License. You may obtain a copy of the 008 * License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software distributed 013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 015 * specific language governing permissions and limitations under the License. 016 */ 017 018package com.nimbusds.oauth2.sdk.ciba; 019 020 021import com.nimbusds.common.contenttype.ContentType; 022import com.nimbusds.jose.JWSObject; 023import com.nimbusds.jwt.JWT; 024import com.nimbusds.jwt.JWTClaimsSet; 025import com.nimbusds.jwt.JWTParser; 026import com.nimbusds.jwt.SignedJWT; 027import com.nimbusds.langtag.LangTag; 028import com.nimbusds.langtag.LangTagException; 029import com.nimbusds.langtag.LangTagUtils; 030import com.nimbusds.oauth2.sdk.AbstractAuthenticatedRequest; 031import com.nimbusds.oauth2.sdk.ParseException; 032import com.nimbusds.oauth2.sdk.Scope; 033import com.nimbusds.oauth2.sdk.SerializeException; 034import com.nimbusds.oauth2.sdk.auth.ClientAuthentication; 035import com.nimbusds.oauth2.sdk.auth.Secret; 036import com.nimbusds.oauth2.sdk.http.HTTPRequest; 037import com.nimbusds.oauth2.sdk.id.Identifier; 038import com.nimbusds.oauth2.sdk.rar.AuthorizationDetail; 039import com.nimbusds.oauth2.sdk.token.BearerAccessToken; 040import com.nimbusds.oauth2.sdk.util.*; 041import com.nimbusds.openid.connect.sdk.OIDCClaimsRequest; 042import com.nimbusds.openid.connect.sdk.claims.ACR; 043import net.jcip.annotations.Immutable; 044import net.minidev.json.JSONObject; 045 046import java.net.URI; 047import java.util.*; 048 049 050/** 051 * <p>CIBA request to an OpenID provider / OAuth 2.0 authorisation server 052 * backend authentication endpoint. Supports plan as well as signed (JWT) 053 * requests. 054 * 055 * <p>Example HTTP request: 056 * 057 * <pre> 058 * POST /bc-authorize HTTP/1.1 059 * Host: server.example.com 060 * Content-Type: application/x-www-form-urlencoded 061 * 062 * scope=openid%20email%20example-scope& 063 * client_notification_token=8d67dc78-7faa-4d41-aabd-67707b374255& 064 * binding_message=W4SCT& 065 * login_hint_token=eyJraWQiOiJsdGFjZXNidyIsImFsZyI6IkVTMjU2In0.eyJ 066 * zdWJfaWQiOnsic3ViamVjdF90eXBlIjoicGhvbmUiLCJwaG9uZSI6IisxMzMwMjg 067 * xODAwNCJ9fQ.Kk8jcUbHjJAQkRSHyDuFQr3NMEOSJEZc85VfER74tX6J9CuUllr8 068 * 9WKUHUR7MA0-mWlptMRRhdgW1ZDt7g1uwQ& 069 * client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3A 070 * client-assertion-type%3Ajwt-bearer& 071 * client_assertion=eyJraWQiOiJsdGFjZXNidyIsImFsZyI6IkVTMjU2In0.eyJ 072 * pc3MiOiJzNkJoZFJrcXQzIiwic3ViIjoiczZCaGRSa3F0MyIsImF1ZCI6Imh0dHB 073 * zOi8vc2VydmVyLmV4YW1wbGUuY29tIiwianRpIjoiYmRjLVhzX3NmLTNZTW80RlN 074 * 6SUoyUSIsImlhdCI6MTUzNzgxOTQ4NiwiZXhwIjoxNTM3ODE5Nzc3fQ.Ybr8mg_3 075 * E2OptOSsA8rnelYO_y1L-yFaF_j1iemM3ntB61_GN3APe5cl_-5a6cvGlP154XAK 076 * 7fL-GaZSdnd9kg 077 * </pre> 078 * 079 * <p>Related specifications: 080 * 081 * <ul> 082 * <li>OpenID Connect CIBA Flow - Core 1.0 083 * <li>Financial-grade API: Client Initiated Backchannel Authentication 084 * Profile (draft 02) 085 * </ul> 086 */ 087@Immutable 088public class CIBARequest extends AbstractAuthenticatedRequest { 089 090 091 /** 092 * The maximum allowed length of a client notification token. 093 */ 094 public static final int CLIENT_NOTIFICATION_TOKEN_MAX_LENGTH = 1024; 095 096 097 /** 098 * The registered parameter names. 099 */ 100 private static final Set<String> REGISTERED_PARAMETER_NAMES; 101 102 static { 103 Set<String> p = new HashSet<>(); 104 105 // Plain 106 p.add("scope"); 107 p.add("client_notification_token"); 108 p.add("acr_values"); 109 p.add("login_hint_token"); 110 p.add("id_token_hint"); 111 p.add("login_hint"); 112 p.add("binding_message"); 113 p.add("user_code"); 114 p.add("requested_expiry"); 115 p.add("claims"); 116 p.add("claims_locales"); 117 p.add("purpose"); 118 p.add("authorization_details"); 119 p.add("resource"); 120 p.add("request_context"); 121 122 // Signed JWT 123 p.add("request"); 124 125 REGISTERED_PARAMETER_NAMES = Collections.unmodifiableSet(p); 126 } 127 128 129 /** 130 * The scope (required), must contain {@code openid}. 131 */ 132 private final Scope scope; 133 134 135 /** 136 * The client notification token, required for the CIBA ping and push 137 * token delivery modes. 138 */ 139 private final BearerAccessToken clientNotificationToken; 140 141 142 /** 143 * Requested Authentication Context Class Reference values (optional). 144 */ 145 private final List<ACR> acrValues; 146 147 148 /** 149 * A token containing information identifying the end-user for whom 150 * authentication is being requested (optional). 151 */ 152 private final LoginHintToken loginHintToken; 153 154 155 /** 156 * Previously issued ID token passed as a hint to identify the end-user 157 * for whom authentication is being requested (optional). 158 */ 159 private final JWT idTokenHint; 160 161 162 /** 163 * Login hint (email address, phone number, etc.) about the end-user 164 * for whom authentication is being requested (optional). 165 */ 166 private final String loginHint; 167 168 169 /** 170 * Human-readable binding message for the display at the consumption 171 * and authentication devices (optional). 172 */ 173 private final String bindingMessage; 174 175 176 /** 177 * User secret code (password, PIN, etc.) to authorise the CIBA request 178 * with the authentication device (optional). 179 */ 180 private final Secret userCode; 181 182 183 /** 184 * Requested expiration for the {@code auth_req_id} (optional). 185 */ 186 private final Integer requestedExpiry; 187 188 189 /** 190 * Individual claims to be returned (optional). 191 */ 192 private final OIDCClaimsRequest claims; 193 194 195 /** 196 * The end-user's preferred languages and scripts for claims being 197 * returned (optional). 198 */ 199 private final List<LangTag> claimsLocales; 200 201 202 /** 203 * The transaction specific purpose, for use in OpenID Connect Identity 204 * Assurance (optional). 205 */ 206 private final String purpose; 207 208 209 /** 210 * The RAR details (optional). 211 */ 212 private final List<AuthorizationDetail> authorizationDetails; 213 214 215 /** 216 * The resource URI(s) (optional). 217 */ 218 private final List<URI> resources; 219 220 221 /** 222 * The request context (optional). 223 */ 224 private final JSONObject requestContext; 225 226 227 /** 228 * Custom parameters. 229 */ 230 private final Map<String,List<String>> customParams; 231 232 233 /** 234 * The JWT for a signed request. 235 */ 236 private final SignedJWT signedRequest; 237 238 239 /** 240 * Builder for constructing CIBA requests. 241 */ 242 public static class Builder { 243 244 245 /** 246 * The endpoint URI (optional). 247 */ 248 private URI endpoint; 249 250 251 /** 252 * The client authentication (required). 253 */ 254 private final ClientAuthentication clientAuth; 255 256 257 /** 258 * The scope (required). 259 */ 260 private final Scope scope; 261 262 263 /** 264 * The client notification type, required for the CIBA ping and 265 * push token delivery modes. 266 */ 267 private BearerAccessToken clientNotificationToken; 268 269 270 /** 271 * Requested Authentication Context Class Reference values 272 * (optional). 273 */ 274 private List<ACR> acrValues; 275 276 277 /** 278 * A token containing information identifying the end-user for 279 * whom authentication is being requested (optional). 280 */ 281 private LoginHintToken loginHintToken; 282 283 284 /** 285 * Previously issued ID token passed as a hint to identify the 286 * end-user for whom authentication is being requested 287 * (optional). 288 */ 289 private JWT idTokenHint; 290 291 292 /** 293 * Identity hint (email address, phone number, etc.) about the 294 * end-user for whom authentication is being requested 295 * (optional). 296 */ 297 private String loginHint; 298 299 300 /** 301 * Human-readable binding message for the display at the 302 * consumption and authentication devices (optional). 303 */ 304 private String bindingMessage; 305 306 307 /** 308 * User secret code (password, PIN, etc.) to authorise the CIBA 309 * request with the authentication device (optional). 310 */ 311 private Secret userCode; 312 313 314 /** 315 * Requested expiration for the {@code auth_req_id} (optional). 316 */ 317 private Integer requestedExpiry; 318 319 320 /** 321 * Individual claims to be returned (optional). 322 */ 323 private OIDCClaimsRequest claims; 324 325 326 /** 327 * The end-user's preferred languages and scripts for claims 328 * being returned (optional). 329 */ 330 private List<LangTag> claimsLocales; 331 332 333 /** 334 * The transaction specific purpose (optional). 335 */ 336 private String purpose; 337 338 339 /** 340 * The RAR details (optional). 341 */ 342 private List<AuthorizationDetail> authorizationDetails; 343 344 345 /** 346 * The resource URI(s) (optional). 347 */ 348 private List<URI> resources; 349 350 351 /** 352 * The request context (optional). 353 */ 354 private JSONObject requestContext; 355 356 357 /** 358 * Custom parameters. 359 */ 360 private Map<String,List<String>> customParams = new HashMap<>(); 361 362 363 /** 364 * The JWT for a signed request. 365 */ 366 private final SignedJWT signedRequest; 367 368 369 /** 370 * Creates a new CIBA request builder. 371 * 372 * @param clientAuth The client authentication. Must not be 373 * {@code null}. 374 * @param scope The requested scope, {@code null} if not 375 * specified. 376 */ 377 public Builder(final ClientAuthentication clientAuth, 378 final Scope scope) { 379 380 this.clientAuth = Objects.requireNonNull(clientAuth); 381 this.scope = scope; 382 signedRequest = null; 383 } 384 385 386 /** 387 * Creates a new CIBA signed request builder. 388 * 389 * @param clientAuth The client authentication. Must not be 390 * {@code null}. 391 * @param signedRequest The signed request JWT. Must not be 392 * {@code null}. 393 */ 394 public Builder(final ClientAuthentication clientAuth, 395 final SignedJWT signedRequest) { 396 397 this.clientAuth = Objects.requireNonNull(clientAuth); 398 this.signedRequest = Objects.requireNonNull(signedRequest); 399 scope = null; 400 } 401 402 403 /** 404 * Creates a new CIBA request builder from the specified 405 * request. 406 * 407 * @param request The CIBA request. Must not be {@code null}. 408 */ 409 public Builder(final CIBARequest request) { 410 411 endpoint = request.getEndpointURI(); 412 clientAuth = request.getClientAuthentication(); 413 scope = request.getScope(); 414 clientNotificationToken = request.getClientNotificationToken(); 415 acrValues = request.getACRValues(); 416 loginHintToken = request.getLoginHintToken(); 417 idTokenHint = request.getIDTokenHint(); 418 loginHint = request.getLoginHint(); 419 bindingMessage = request.getBindingMessage(); 420 userCode = request.getUserCode(); 421 requestedExpiry = request.getRequestedExpiry(); 422 claims = request.getOIDCClaims(); 423 claimsLocales = request.getClaimsLocales(); 424 purpose = request.getPurpose(); 425 authorizationDetails = request.getAuthorizationDetails(); 426 resources = request.getResources(); 427 requestContext = request.getContext(); 428 customParams = request.getCustomParameters(); 429 signedRequest = request.getRequestJWT(); 430 } 431 432 433 /** 434 * Sets the client notification token, required for the CIBA 435 * ping and push token delivery modes. Corresponds to the 436 * {@code client_notification_token} parameter. 437 * 438 * @param token The client notification token, {@code null} if 439 * not specified. 440 * 441 * @return This builder. 442 */ 443 public Builder clientNotificationToken(final BearerAccessToken token) { 444 this.clientNotificationToken = token; 445 return this; 446 } 447 448 449 /** 450 * Sets the requested Authentication Context Class Reference 451 * values. Corresponds to the optional {@code acr_values} 452 * parameter. 453 * 454 * @param acrValues The requested ACR values, {@code null} if 455 * not specified. 456 * 457 * @return This builder. 458 */ 459 public Builder acrValues(final List<ACR> acrValues) { 460 this.acrValues = acrValues; 461 return this; 462 } 463 464 465 /** 466 * Sets the login hint token, containing information 467 * identifying the end-user for whom authentication is being 468 * requested. Corresponds to the {@code login_hint_token} 469 * parameter. 470 * 471 * @param loginHintToken The login hint token, {@code null} if 472 * not specified. 473 * 474 * @return This builder. 475 */ 476 public Builder loginHintToken(final LoginHintToken loginHintToken) { 477 this.loginHintToken = loginHintToken; 478 return this; 479 } 480 481 482 /** 483 * Sets the login hint token string, containing information 484 * identifying the end-user for whom authentication is being 485 * requested. Corresponds to the {@code login_hint_token} 486 * parameter. 487 * 488 * @param loginHintTokenString The login hint token string, 489 * {@code null} if not specified. 490 * 491 * @return This builder. 492 */ 493 @Deprecated 494 public Builder loginHintTokenString(final String loginHintTokenString) { 495 if (loginHintTokenString != null) { 496 this.loginHintToken = new LoginHintToken(loginHintTokenString); 497 } else { 498 this.loginHintToken = null; 499 } 500 return this; 501 } 502 503 504 /** 505 * Sets the ID Token hint, passed as a hint to identify the 506 * end-user for whom authentication is being requested. 507 * Corresponds to the {@code id_token_hint} parameter. 508 * 509 * @param idTokenHint The ID Token hint, {@code null} if not 510 * specified. 511 * 512 * @return This builder. 513 */ 514 public Builder idTokenHint(final JWT idTokenHint) { 515 this.idTokenHint = idTokenHint; 516 return this; 517 } 518 519 520 /** 521 * Sets the login hint (email address, phone number, etc.), 522 * about the end-user for whom authentication is being 523 * requested. Corresponds to the {@code login_hint} parameter. 524 * 525 * @param loginHint The login hint, {@code null} if not 526 * specified. 527 * 528 * @return This builder. 529 */ 530 public Builder loginHint(final String loginHint) { 531 this.loginHint = loginHint; 532 return this; 533 } 534 535 536 /** 537 * Sets the human-readable binding message for the display at 538 * the consumption and authentication devices. Corresponds to 539 * the {@code binding_message} parameter. 540 * 541 * @param bindingMessage The binding message, {@code null} if 542 * not specified. 543 * 544 * @return This builder. 545 */ 546 public Builder bindingMessage(final String bindingMessage) { 547 this.bindingMessage = bindingMessage; 548 return this; 549 } 550 551 552 /** 553 * Gets the user secret code (password, PIN, etc.) to authorise 554 * the CIBA request with the authentication device. Corresponds 555 * to the {@code user_code} parameter. 556 * 557 * @param userCode The user code, {@code null} if not 558 * specified. 559 * 560 * @return This builder. 561 */ 562 public Builder userCode(final Secret userCode) { 563 this.userCode = userCode; 564 return this; 565 } 566 567 568 /** 569 * Sets the requested expiration for the {@code auth_req_id}. 570 * Corresponds to the {@code requested_expiry} parameter. 571 * 572 * @param requestedExpiry The required expiry (as positive 573 * integer), {@code null} if not 574 * specified. 575 * 576 * @return This builder. 577 */ 578 public Builder requestedExpiry(final Integer requestedExpiry) { 579 this.requestedExpiry = requestedExpiry; 580 return this; 581 } 582 583 584 /** 585 * Sets the individual OpenID claims to be returned. 586 * Corresponds to the optional {@code claims} parameter. 587 * 588 * @param claims The individual OpenID claims to be returned, 589 * {@code null} if not specified. 590 * 591 * @return This builder. 592 */ 593 public Builder claims(final OIDCClaimsRequest claims) { 594 595 this.claims = claims; 596 return this; 597 } 598 599 600 /** 601 * Sets the end-user's preferred languages and scripts for the 602 * claims being returned, ordered by preference. Corresponds to 603 * the optional {@code claims_locales} parameter. 604 * 605 * @param claimsLocales The preferred claims locales, 606 * {@code null} if not specified. 607 * 608 * @return This builder. 609 */ 610 public Builder claimsLocales(final List<LangTag> claimsLocales) { 611 612 this.claimsLocales = claimsLocales; 613 return this; 614 } 615 616 617 /** 618 * Sets the transaction specific purpose. Corresponds to the 619 * optional {@code purpose} parameter. 620 * 621 * @param purpose The purpose, {@code null} if not specified. 622 * 623 * @return This builder. 624 */ 625 public Builder purpose(final String purpose) { 626 627 this.purpose = purpose; 628 return this; 629 } 630 631 632 /** 633 * Sets the Rich Authorisation Request (RAR) details. 634 * 635 * @param authorizationDetails The authorisation details, 636 * {@code null} if not specified. 637 * 638 * @return This builder. 639 */ 640 public Builder authorizationDetails(final List<AuthorizationDetail> authorizationDetails) { 641 this.authorizationDetails = authorizationDetails; 642 return this; 643 } 644 645 646 /** 647 * Sets the resource server URI. 648 * 649 * @param resource The resource URI, {@code null} if not 650 * specified. 651 * 652 * @return This builder. 653 */ 654 public Builder resource(final URI resource) { 655 if (resource != null) { 656 this.resources = Collections.singletonList(resource); 657 } else { 658 this.resources = null; 659 } 660 return this; 661 } 662 663 664 /** 665 * Sets the resource server URI(s). 666 * 667 * @param resources The resource URI(s), {@code null} if not 668 * specified. 669 * 670 * @return This builder. 671 */ 672 public Builder resources(final URI ... resources) { 673 if (resources != null) { 674 this.resources = Arrays.asList(resources); 675 } else { 676 this.resources = null; 677 } 678 return this; 679 } 680 681 682 /** 683 * Sets the request context. 684 * 685 * @param requestContext The request context, {@code null} if 686 * not specified. 687 * 688 * @return This builder. 689 */ 690 public Builder context(final JSONObject requestContext) { 691 this.requestContext = requestContext; 692 return this; 693 } 694 695 696 /** 697 * Sets a custom parameter. 698 * 699 * @param name The parameter name. Must not be {@code null}. 700 * @param values The parameter values, {@code null} if not 701 * specified. 702 * 703 * @return This builder. 704 */ 705 public Builder customParameter(final String name, final String ... values) { 706 707 if (values == null || values.length == 0) { 708 customParams.remove(name); 709 } else { 710 customParams.put(name, Arrays.asList(values)); 711 } 712 713 return this; 714 } 715 716 717 /** 718 * Sets the URI of the CIBA endpoint. 719 * 720 * @param endpoint The URI of the CIBA endpoint. May be 721 * {@code null} if the {@link #toHTTPRequest()} 722 * method is not going to be used. 723 * 724 * @return This builder. 725 */ 726 public Builder endpointURI(final URI endpoint) { 727 728 this.endpoint = endpoint; 729 return this; 730 } 731 732 733 /** 734 * Builds a new CIBA request. 735 * 736 * @return The CIBA request. 737 */ 738 public CIBARequest build() { 739 740 try { 741 if (signedRequest != null) { 742 return new CIBARequest( 743 endpoint, 744 clientAuth, 745 signedRequest 746 ); 747 } 748 749 // Plain request 750 return new CIBARequest( 751 endpoint, 752 clientAuth, 753 scope, 754 clientNotificationToken, 755 acrValues, 756 loginHintToken, 757 idTokenHint, 758 loginHint, 759 bindingMessage, 760 userCode, 761 requestedExpiry, 762 claims, 763 claimsLocales, 764 purpose, 765 authorizationDetails, 766 resources, 767 requestContext, 768 customParams 769 ); 770 } catch (IllegalArgumentException e) { 771 throw new IllegalArgumentException(e.getMessage(), e); 772 } 773 } 774 } 775 776 777 /** 778 * Creates a new CIBA request. 779 * 780 * @param endpoint The URI of the CIBA endpoint. May be 781 * {@code null} if the 782 * {@link #toHTTPRequest()} method is 783 * not going to be used. 784 * @param clientAuth The client authentication. Must not 785 * be {@code null}. 786 * @param scope The requested scope. Must not be 787 * empty or {@code null}. 788 * @param clientNotificationToken The client notification token, 789 * {@code null} if not specified. 790 * @param acrValues The requested ACR values, 791 * {@code null} if not specified. 792 * @param loginHintTokenString The login hint token string, 793 * {@code null} if not specified. 794 * @param idTokenHint The ID Token hint, {@code null} if 795 * not specified. 796 * @param loginHint The login hint, {@code null} if not 797 * specified. 798 * @param bindingMessage The binding message, {@code null} if 799 * not specified. 800 * @param userCode The user code, {@code null} if not 801 * specified. 802 * @param requestedExpiry The required expiry (as positive 803 * integer), {@code null} if not 804 * specified. 805 * @param customParams Custom parameters, empty or 806 * {@code null} if not specified. 807 */ 808 @Deprecated 809 public CIBARequest(final URI endpoint, 810 final ClientAuthentication clientAuth, 811 final Scope scope, 812 final BearerAccessToken clientNotificationToken, 813 final List<ACR> acrValues, 814 final String loginHintTokenString, 815 final JWT idTokenHint, 816 final String loginHint, 817 final String bindingMessage, 818 final Secret userCode, 819 final Integer requestedExpiry, 820 final Map<String, List<String>> customParams) { 821 822 this(endpoint, clientAuth, 823 scope, clientNotificationToken, acrValues, 824 loginHintTokenString, idTokenHint, loginHint, 825 bindingMessage, userCode, requestedExpiry, 826 null, customParams); 827 } 828 829 830 /** 831 * Creates a new CIBA request. 832 * 833 * @param endpoint The URI of the CIBA endpoint. May be 834 * {@code null} if the 835 * {@link #toHTTPRequest()} method is 836 * not going to be used. 837 * @param clientAuth The client authentication. Must not 838 * be {@code null}. 839 * @param scope The requested scope. Must not be 840 * empty or {@code null}. 841 * @param clientNotificationToken The client notification token, 842 * {@code null} if not specified. 843 * @param acrValues The requested ACR values, 844 * {@code null} if not specified. 845 * @param loginHintTokenString The login hint token string, 846 * {@code null} if not specified. 847 * @param idTokenHint The ID Token hint, {@code null} if 848 * not specified. 849 * @param loginHint The login hint, {@code null} if not 850 * specified. 851 * @param bindingMessage The binding message, {@code null} if 852 * not specified. 853 * @param userCode The user code, {@code null} if not 854 * specified. 855 * @param requestedExpiry The required expiry (as positive 856 * integer), {@code null} if not 857 * specified. 858 * @param claims The individual claims to be returned, 859 * {@code null} if not specified. 860 * @param customParams Custom parameters, empty or 861 * {@code null} if not specified. 862 */ 863 @Deprecated 864 public CIBARequest(final URI endpoint, 865 final ClientAuthentication clientAuth, 866 final Scope scope, 867 final BearerAccessToken clientNotificationToken, 868 final List<ACR> acrValues, 869 final String loginHintTokenString, 870 final JWT idTokenHint, 871 final String loginHint, 872 final String bindingMessage, 873 final Secret userCode, 874 final Integer requestedExpiry, 875 final OIDCClaimsRequest claims, 876 final Map<String, List<String>> customParams) { 877 878 this(endpoint, clientAuth, 879 scope, clientNotificationToken, acrValues, 880 loginHintTokenString, idTokenHint, loginHint, 881 bindingMessage, userCode, requestedExpiry, 882 claims, null, null, 883 null, 884 customParams); 885 } 886 887 888 /** 889 * Creates a new CIBA request. 890 * 891 * @param endpoint The URI of the CIBA endpoint. May be 892 * {@code null} if the 893 * {@link #toHTTPRequest()} method is 894 * not going to be used. 895 * @param clientAuth The client authentication. Must not 896 * be {@code null}. 897 * @param scope The requested scope. Must not be 898 * empty or {@code null}. 899 * @param clientNotificationToken The client notification token, 900 * {@code null} if not specified. 901 * @param acrValues The requested ACR values, 902 * {@code null} if not specified. 903 * @param loginHintTokenString The login hint token string, 904 * {@code null} if not specified. 905 * @param idTokenHint The ID Token hint, {@code null} if 906 * not specified. 907 * @param loginHint The login hint, {@code null} if not 908 * specified. 909 * @param bindingMessage The binding message, {@code null} if 910 * not specified. 911 * @param userCode The user code, {@code null} if not 912 * specified. 913 * @param requestedExpiry The required expiry (as positive 914 * integer), {@code null} if not 915 * specified. 916 * @param claims The individual claims to be 917 * returned, {@code null} if not 918 * specified. 919 * @param claimsLocales The preferred languages and scripts 920 * for claims being returned, 921 * {@code null} if not specified. 922 * @param purpose The transaction specific purpose, 923 * {@code null} if not specified. 924 * @param resources The resource URI(s), {@code null} if 925 * not specified. 926 * @param customParams Custom parameters, empty or 927 * {@code null} if not specified. 928 */ 929 @Deprecated 930 public CIBARequest(final URI endpoint, 931 final ClientAuthentication clientAuth, 932 final Scope scope, 933 final BearerAccessToken clientNotificationToken, 934 final List<ACR> acrValues, 935 final String loginHintTokenString, 936 final JWT idTokenHint, 937 final String loginHint, 938 final String bindingMessage, 939 final Secret userCode, 940 final Integer requestedExpiry, 941 final OIDCClaimsRequest claims, 942 final List<LangTag> claimsLocales, 943 final String purpose, 944 final List<URI> resources, 945 final Map<String, List<String>> customParams) { 946 947 this(endpoint, clientAuth, 948 scope, clientNotificationToken, acrValues, 949 loginHintTokenString, idTokenHint, loginHint, 950 bindingMessage, userCode, requestedExpiry, 951 claims, claimsLocales, purpose, null, resources, 952 customParams); 953 } 954 955 956 /** 957 * Creates a new CIBA request. 958 * 959 * @param endpoint The URI of the CIBA endpoint. May be 960 * {@code null} if the 961 * {@link #toHTTPRequest()} method is 962 * not going to be used. 963 * @param clientAuth The client authentication. Must not 964 * be {@code null}. 965 * @param scope The requested scope. Must not be 966 * empty or {@code null}. 967 * @param clientNotificationToken The client notification token, 968 * {@code null} if not specified. 969 * @param acrValues The requested ACR values, 970 * {@code null} if not specified. 971 * @param loginHintTokenString The login hint token string, 972 * {@code null} if not specified. 973 * @param idTokenHint The ID Token hint, {@code null} if 974 * not specified. 975 * @param loginHint The login hint, {@code null} if not 976 * specified. 977 * @param bindingMessage The binding message, {@code null} if 978 * not specified. 979 * @param userCode The user code, {@code null} if not 980 * specified. 981 * @param requestedExpiry The required expiry (as positive 982 * integer), {@code null} if not 983 * specified. 984 * @param claims The individual claims to be 985 * returned, {@code null} if not 986 * specified. 987 * @param claimsLocales The preferred languages and scripts 988 * for claims being returned, 989 * {@code null} if not specified. 990 * @param purpose The transaction specific purpose, 991 * {@code null} if not specified. 992 * @param authorizationDetails The Rich Authorisation Request (RAR) 993 * details, {@code null} if not 994 * specified. 995 * @param resources The resource URI(s), {@code null} if 996 * not specified. 997 * @param customParams Custom parameters, empty or 998 * {@code null} if not specified. 999 */ 1000 @Deprecated 1001 public CIBARequest(final URI endpoint, 1002 final ClientAuthentication clientAuth, 1003 final Scope scope, 1004 final BearerAccessToken clientNotificationToken, 1005 final List<ACR> acrValues, 1006 final String loginHintTokenString, 1007 final JWT idTokenHint, 1008 final String loginHint, 1009 final String bindingMessage, 1010 final Secret userCode, 1011 final Integer requestedExpiry, 1012 final OIDCClaimsRequest claims, 1013 final List<LangTag> claimsLocales, 1014 final String purpose, 1015 final List<AuthorizationDetail> authorizationDetails, 1016 final List<URI> resources, 1017 final Map<String, List<String>> customParams) { 1018 1019 this(endpoint, clientAuth, 1020 scope, clientNotificationToken, acrValues, 1021 loginHintTokenString != null ? new LoginHintToken(loginHintTokenString) : null, idTokenHint, loginHint, 1022 bindingMessage, userCode, requestedExpiry, 1023 claims, claimsLocales, purpose, authorizationDetails, resources, null, 1024 customParams); 1025 } 1026 1027 1028 /** 1029 * Creates a new CIBA request. 1030 * 1031 * @param endpoint The URI of the CIBA endpoint. May be 1032 * {@code null} if the 1033 * {@link #toHTTPRequest()} method is 1034 * not going to be used. 1035 * @param clientAuth The client authentication. Must not 1036 * be {@code null}. 1037 * @param scope The requested scope. Must not be 1038 * empty or {@code null}. 1039 * @param clientNotificationToken The client notification token, 1040 * {@code null} if not specified. 1041 * @param acrValues The requested ACR values, 1042 * {@code null} if not specified. 1043 * @param loginHintToken The login hint token, {@code null} if 1044 * not specified. 1045 * @param idTokenHint The ID Token hint, {@code null} if 1046 * not specified. 1047 * @param loginHint The login hint, {@code null} if not 1048 * specified. 1049 * @param bindingMessage The binding message, {@code null} if 1050 * not specified. 1051 * @param userCode The user code, {@code null} if not 1052 * specified. 1053 * @param requestedExpiry The required expiry (as positive 1054 * integer), {@code null} if not 1055 * specified. 1056 * @param claims The individual claims to be 1057 * returned, {@code null} if not 1058 * specified. 1059 * @param claimsLocales The preferred languages and scripts 1060 * for claims being returned, 1061 * {@code null} if not specified. 1062 * @param purpose The transaction specific purpose, 1063 * {@code null} if not specified. 1064 * @param authorizationDetails The Rich Authorisation Request (RAR) 1065 * details, {@code null} if not 1066 * specified. 1067 * @param resources The resource URI(s), {@code null} if 1068 * not specified. 1069 * @param requestContext The request context, {@code null} if 1070 * not specified. 1071 * @param customParams Custom parameters, empty or 1072 * {@code null} if not specified. 1073 */ 1074 public CIBARequest(final URI endpoint, 1075 final ClientAuthentication clientAuth, 1076 final Scope scope, 1077 final BearerAccessToken clientNotificationToken, 1078 final List<ACR> acrValues, 1079 final LoginHintToken loginHintToken, 1080 final JWT idTokenHint, 1081 final String loginHint, 1082 final String bindingMessage, 1083 final Secret userCode, 1084 final Integer requestedExpiry, 1085 final OIDCClaimsRequest claims, 1086 final List<LangTag> claimsLocales, 1087 final String purpose, 1088 final List<AuthorizationDetail> authorizationDetails, 1089 final List<URI> resources, 1090 final JSONObject requestContext, 1091 final Map<String, List<String>> customParams) { 1092 1093 super(endpoint, clientAuth); 1094 1095 this.scope = scope; 1096 1097 if (clientNotificationToken != null && clientNotificationToken.getValue().length() > CLIENT_NOTIFICATION_TOKEN_MAX_LENGTH) { 1098 throw new IllegalArgumentException("The client notification token must not exceed " + CLIENT_NOTIFICATION_TOKEN_MAX_LENGTH + " chars"); 1099 } 1100 this.clientNotificationToken = clientNotificationToken; 1101 1102 this.acrValues = acrValues; 1103 1104 // https://openid.net/specs/openid-client-initiated-backchannel-authentication-core-1_0-03.html#rfc.section.7.1 1105 // As in the CIBA flow the OP does not have an interaction with 1106 // the end-user through the consumption device, it is REQUIRED 1107 // that the Client provides one (and only one) of the hints 1108 // specified above in the authentication request, that is 1109 // "login_hint_token", "id_token_hint" or "login_hint". 1110 int numHints = 0; 1111 1112 if (loginHintToken != null) numHints++; 1113 this.loginHintToken = loginHintToken; 1114 1115 if (idTokenHint != null) numHints++; 1116 this.idTokenHint = idTokenHint; 1117 1118 if (loginHint != null) numHints++; 1119 this.loginHint = loginHint; 1120 1121 if (numHints != 1) { 1122 throw new IllegalArgumentException("One user identity hist must be provided (login_hint_token, id_token_hint or login_hint)"); 1123 } 1124 1125 this.bindingMessage = bindingMessage; 1126 1127 this.userCode = userCode; 1128 1129 if (requestedExpiry != null && requestedExpiry < 1) { 1130 throw new IllegalArgumentException("The requested expiry must be a positive integer"); 1131 } 1132 this.requestedExpiry = requestedExpiry; 1133 1134 this.claims = claims; 1135 1136 if (claimsLocales != null) { 1137 this.claimsLocales = Collections.unmodifiableList(claimsLocales); 1138 } else { 1139 this.claimsLocales = null; 1140 } 1141 1142 this.purpose = purpose; 1143 1144 this.authorizationDetails = authorizationDetails; 1145 1146 this.resources = ResourceUtils.ensureLegalResourceURIs(resources); 1147 1148 this.requestContext = requestContext; 1149 1150 this.customParams = customParams != null ? customParams : Collections.<String, List<String>>emptyMap(); 1151 1152 signedRequest = null; 1153 } 1154 1155 1156 /** 1157 * Creates a new CIBA signed request. 1158 * 1159 * @param endpoint The URI of the CIBA endpoint. May be 1160 * {@code null} if the {@link #toHTTPRequest()} 1161 * method is not going to be used. 1162 * @param clientAuth The client authentication. Must not be 1163 * {@code null}. 1164 * @param signedRequest The signed request JWT. Must not be 1165 * {@code null}. 1166 */ 1167 public CIBARequest(final URI endpoint, 1168 final ClientAuthentication clientAuth, 1169 final SignedJWT signedRequest) { 1170 1171 super(endpoint, clientAuth); 1172 1173 if (JWSObject.State.UNSIGNED.equals(signedRequest.getState())) { 1174 throw new IllegalArgumentException("The request JWT must be in a signed state"); 1175 } 1176 this.signedRequest = signedRequest; 1177 1178 scope = null; 1179 clientNotificationToken = null; 1180 acrValues = null; 1181 loginHintToken = null; 1182 idTokenHint = null; 1183 loginHint = null; 1184 bindingMessage = null; 1185 userCode = null; 1186 requestedExpiry = null; 1187 claims = null; 1188 claimsLocales = null; 1189 authorizationDetails = null; 1190 purpose = null; 1191 resources = null; 1192 requestContext = null; 1193 customParams = Collections.emptyMap(); 1194 } 1195 1196 1197 /** 1198 * Returns the registered (standard) CIBA request parameter names. 1199 * 1200 * @return The registered CIBA request parameter names, as an 1201 * unmodifiable set. 1202 */ 1203 public static Set<String> getRegisteredParameterNames() { 1204 1205 return REGISTERED_PARAMETER_NAMES; 1206 } 1207 1208 1209 /** 1210 * Returns the scope. Corresponds to the optional {@code scope} 1211 * parameter. 1212 * 1213 * @return The scope, {@code null} if not specified. 1214 */ 1215 public Scope getScope() { 1216 1217 return scope; 1218 } 1219 1220 1221 /** 1222 * Returns the client notification token, required for the CIBA ping 1223 * and push token delivery modes. Corresponds to the 1224 * {@code client_notification_token} parameter. 1225 * 1226 * @return The client notification token, {@code null} if not 1227 * specified. 1228 */ 1229 public BearerAccessToken getClientNotificationToken() { 1230 1231 return clientNotificationToken; 1232 } 1233 1234 1235 /** 1236 * Returns the requested Authentication Context Class Reference values. 1237 * Corresponds to the optional {@code acr_values} parameter. 1238 * 1239 * @return The requested ACR values, {@code null} if not specified. 1240 */ 1241 public List<ACR> getACRValues() { 1242 1243 return acrValues; 1244 } 1245 1246 1247 /** 1248 * Returns the hint type. 1249 * 1250 * @return The hint type. 1251 */ 1252 public CIBAHintType getHintType() { 1253 1254 if (getLoginHintTokenString() != null) { 1255 return CIBAHintType.LOGIN_HINT_TOKEN; 1256 } else if (getIDTokenHint() != null) { 1257 return CIBAHintType.ID_TOKEN_HINT; 1258 } else { 1259 return CIBAHintType.LOGIN_HINT; 1260 } 1261 } 1262 1263 1264 /** 1265 * Returns the login hint token, containing information identifying the 1266 * end-user for whom authentication is being requested. Corresponds to 1267 * the {@code login_hint_token} parameter. 1268 * 1269 * @return The login hint token, {@code null} if not specified. 1270 */ 1271 public LoginHintToken getLoginHintToken() { 1272 1273 return loginHintToken; 1274 } 1275 1276 1277 /** 1278 * Returns the login hint token string, containing information 1279 * identifying the end-user for whom authentication is being requested. 1280 * Corresponds to the {@code login_hint_token} parameter. 1281 * 1282 * @return The login hint token string, {@code null} if not 1283 * specified. 1284 */ 1285 @Deprecated 1286 public String getLoginHintTokenString() { 1287 1288 return loginHintToken != null ? loginHintToken.getValue() : null; 1289 } 1290 1291 1292 /** 1293 * Returns the ID Token hint, passed as a hint to identify the end-user 1294 * for whom authentication is being requested. Corresponds to the 1295 * {@code id_token_hint} parameter. 1296 * 1297 * @return The ID Token hint, {@code null} if not specified. 1298 */ 1299 public JWT getIDTokenHint() { 1300 1301 return idTokenHint; 1302 } 1303 1304 1305 /** 1306 * Returns the login hint (email address, phone number, etc), about the 1307 * end-user for whom authentication is being requested. Corresponds to 1308 * the {@code login_hint} parameter. 1309 * 1310 * @return The login hint, {@code null} if not specified. 1311 */ 1312 public String getLoginHint() { 1313 1314 return loginHint; 1315 } 1316 1317 1318 /** 1319 * Returns the human-readable binding message for the display at the 1320 * consumption and authentication devices. Corresponds to the 1321 * {@code binding_message} parameter. 1322 * 1323 * @return The binding message, {@code null} if not specified. 1324 */ 1325 public String getBindingMessage() { 1326 1327 return bindingMessage; 1328 } 1329 1330 1331 /** 1332 * Returns the user secret code (password, PIN, etc.) to authorise the 1333 * CIBA request with the authentication device. Corresponds to the 1334 * {@code user_code} parameter. 1335 * 1336 * @return The user code, {@code null} if not specified. 1337 */ 1338 public Secret getUserCode() { 1339 1340 return userCode; 1341 } 1342 1343 1344 /** 1345 * Returns the requested expiration for the {@code auth_req_id}. 1346 * Corresponds to the {@code requested_expiry} parameter. 1347 * 1348 * @return The required expiry (as positive integer), {@code null} if 1349 * not specified. 1350 */ 1351 public Integer getRequestedExpiry() { 1352 1353 return requestedExpiry; 1354 } 1355 1356 1357 /** 1358 * Returns the individual claims to be returned. Corresponds to the 1359 * optional {@code claims} parameter. 1360 * 1361 * @return The individual claims to be returned, {@code null} if not 1362 * specified. 1363 */ 1364 public OIDCClaimsRequest getOIDCClaims() { 1365 1366 return claims; 1367 } 1368 1369 1370 /** 1371 * Returns the end-user's preferred languages and scripts for the 1372 * claims being returned, ordered by preference. Corresponds to the 1373 * optional {@code claims_locales} parameter. 1374 * 1375 * @return The preferred claims locales, {@code null} if not specified. 1376 */ 1377 public List<LangTag> getClaimsLocales() { 1378 1379 return claimsLocales; 1380 } 1381 1382 1383 /** 1384 * Returns the transaction specific purpose. Corresponds to the 1385 * optional {@code purpose} parameter. 1386 * 1387 * @return The purpose, {@code null} if not specified. 1388 */ 1389 public String getPurpose() { 1390 1391 return purpose; 1392 } 1393 1394 1395 /** 1396 * Returns the Rich Authorisation Request (RAR) details. 1397 * 1398 * @return The authorisation details, {@code null} if not specified. 1399 */ 1400 public List<AuthorizationDetail> getAuthorizationDetails() { 1401 1402 return authorizationDetails; 1403 } 1404 1405 1406 /** 1407 * Returns the resource server URI. 1408 * 1409 * @return The resource URI(s), {@code null} if not specified. 1410 */ 1411 public List<URI> getResources() { 1412 1413 return resources; 1414 } 1415 1416 1417 /** 1418 * Returns the request context. 1419 * 1420 * @return The request context, {@code null} if not specified. 1421 */ 1422 public JSONObject getContext() { 1423 1424 return requestContext; 1425 } 1426 1427 /** 1428 * Returns the additional custom parameters. 1429 * 1430 * @return The additional custom parameters as an unmodifiable map, 1431 * empty map if none. 1432 */ 1433 public Map<String, List<String>> getCustomParameters() { 1434 1435 return customParams; 1436 } 1437 1438 1439 /** 1440 * Returns the specified custom parameter. 1441 * 1442 * @param name The parameter name. Must not be {@code null}. 1443 * 1444 * @return The parameter value(s), {@code null} if not specified. 1445 */ 1446 public List<String> getCustomParameter(final String name) { 1447 1448 return customParams.get(name); 1449 } 1450 1451 1452 /** 1453 * Returns {@code true} if this request is signed. 1454 * 1455 * @return {@code true} for a signed request, {@code false} for a plain 1456 * request. 1457 */ 1458 public boolean isSigned() { 1459 1460 return signedRequest != null; 1461 } 1462 1463 1464 /** 1465 * Returns the JWT for a signed request. 1466 * 1467 * @return The request JWT. 1468 */ 1469 public SignedJWT getRequestJWT() { 1470 1471 return signedRequest; 1472 } 1473 1474 1475 /** 1476 * Returns the for parameters for this CIBA request. Parameters which 1477 * are part of the client authentication are not included. 1478 * 1479 * @return The parameters. 1480 */ 1481 public Map<String, List<String>> toParameters() { 1482 1483 // Put custom params first, so they may be overwritten by std params 1484 Map<String, List<String>> params = new LinkedHashMap<>(getCustomParameters()); 1485 1486 if (isSigned()) { 1487 params.put("request", Collections.singletonList(signedRequest.serialize())); 1488 return params; 1489 } 1490 1491 if (CollectionUtils.isNotEmpty(getScope())) { 1492 params.put("scope", Collections.singletonList(getScope().toString())); 1493 } 1494 1495 if (getClientNotificationToken() != null) { 1496 params.put("client_notification_token", Collections.singletonList(getClientNotificationToken().getValue())); 1497 } 1498 if (getACRValues() != null) { 1499 params.put("acr_values", Identifier.toStringList(getACRValues())); 1500 } 1501 if (getLoginHintToken() != null) { 1502 params.put("login_hint_token", Collections.singletonList(getLoginHintToken().getValue())); 1503 } 1504 if (getIDTokenHint() != null) { 1505 params.put("id_token_hint", Collections.singletonList(getIDTokenHint().serialize())); 1506 } 1507 if (getLoginHint() != null) { 1508 params.put("login_hint", Collections.singletonList(getLoginHint())); 1509 } 1510 if (getBindingMessage() != null) { 1511 params.put("binding_message", Collections.singletonList(getBindingMessage())); 1512 } 1513 if (getUserCode() != null) { 1514 params.put("user_code", Collections.singletonList(getUserCode().getValue())); 1515 } 1516 if (getRequestedExpiry() != null) { 1517 params.put("requested_expiry", Collections.singletonList(getRequestedExpiry().toString())); 1518 } 1519 if (getOIDCClaims() != null) { 1520 params.put("claims", Collections.singletonList(getOIDCClaims().toJSONString())); 1521 } 1522 if (CollectionUtils.isNotEmpty(getClaimsLocales())) { 1523 params.put("claims_locales", Collections.singletonList(LangTagUtils.concat(getClaimsLocales()))); 1524 } 1525 if (getPurpose() != null) { 1526 params.put("purpose", Collections.singletonList(purpose)); 1527 } 1528 if (getAuthorizationDetails() != null) { 1529 params.put("authorization_details", Collections.singletonList(AuthorizationDetail.toJSONString(getAuthorizationDetails()))); 1530 } 1531 if (getContext() != null) { 1532 params.put("request_context", Collections.singletonList(getContext().toJSONString())); 1533 } 1534 if (CollectionUtils.isNotEmpty(getResources())) { 1535 params.put("resource", URIUtils.toStringList(getResources(), true)); 1536 } 1537 1538 return params; 1539 } 1540 1541 1542 /** 1543 * Returns the parameters for this CIBA request as a JSON Web Token 1544 * (JWT) claims set. Intended for creating a signed CIBA request. 1545 * 1546 * @return The parameters as JWT claim set. 1547 */ 1548 public JWTClaimsSet toJWTClaimsSet() { 1549 1550 if (isSigned()) { 1551 throw new IllegalStateException(); 1552 } 1553 1554 return JWTClaimsSetUtils.toJWTClaimsSet(toParameters()); 1555 } 1556 1557 1558 /** 1559 * Returns the matching HTTP request. 1560 * 1561 * @return The HTTP request. 1562 */ 1563 @Override 1564 public HTTPRequest toHTTPRequest() { 1565 1566 if (getEndpointURI() == null) 1567 throw new SerializeException("The endpoint URI is not specified"); 1568 1569 HTTPRequest httpRequest = new HTTPRequest(HTTPRequest.Method.POST, getEndpointURI()); 1570 httpRequest.setEntityContentType(ContentType.APPLICATION_URLENCODED); 1571 1572 getClientAuthentication().applyTo(httpRequest); 1573 1574 Map<String, List<String>> params; 1575 try { 1576 params = new LinkedHashMap<>(httpRequest.getBodyAsFormParameters()); 1577 } catch (ParseException e) { 1578 throw new SerializeException(e.getMessage(), e); 1579 } 1580 params.putAll(toParameters()); 1581 httpRequest.setBody(URLUtils.serializeParameters(params)); 1582 1583 return httpRequest; 1584 } 1585 1586 1587 /** 1588 * Parses a CIBA request from the specified HTTP request. 1589 * 1590 * @param httpRequest The HTTP request. Must not be {@code null}. 1591 * 1592 * @return The CIBA request. 1593 * 1594 * @throws ParseException If parsing failed. 1595 */ 1596 public static CIBARequest parse(final HTTPRequest httpRequest) throws ParseException { 1597 1598 // Only HTTP POST accepted 1599 URI uri = httpRequest.getURI(); 1600 httpRequest.ensureMethod(HTTPRequest.Method.POST); 1601 httpRequest.ensureEntityContentType(ContentType.APPLICATION_URLENCODED); 1602 1603 ClientAuthentication clientAuth = ClientAuthentication.parse(httpRequest); 1604 1605 if (clientAuth == null) { 1606 throw new ParseException("Missing required client authentication"); 1607 } 1608 1609 Map<String, List<String>> params = httpRequest.getBodyAsFormParameters(); 1610 1611 String v; 1612 1613 if (params.containsKey("request")) { 1614 // Signed request 1615 v = MultivaluedMapUtils.getFirstValue(params, "request"); 1616 1617 if (StringUtils.isBlank(v)) { 1618 throw new ParseException("Empty request parameter"); 1619 } 1620 1621 SignedJWT signedRequest; 1622 try { 1623 signedRequest = SignedJWT.parse(v); 1624 } catch (java.text.ParseException e) { 1625 throw new ParseException("Invalid request JWT: " + e.getMessage(), e); 1626 } 1627 1628 try { 1629 return new CIBARequest(uri, clientAuth, signedRequest); 1630 } catch (IllegalArgumentException e) { 1631 throw new ParseException(e.getMessage(), e); 1632 } 1633 } 1634 1635 1636 // Plain request 1637 1638 // Parse required scope 1639 v = MultivaluedMapUtils.getFirstValue(params, "scope"); 1640 Scope scope = Scope.parse(v); 1641 1642 v = MultivaluedMapUtils.getFirstValue(params, "client_notification_token"); 1643 BearerAccessToken clientNotificationToken = null; 1644 if (StringUtils.isNotBlank(v)) { 1645 clientNotificationToken = new BearerAccessToken(v); 1646 } 1647 1648 v = MultivaluedMapUtils.getFirstValue(params, "acr_values"); 1649 List<ACR> acrValues = null; 1650 if (StringUtils.isNotBlank(v)) { 1651 acrValues = new LinkedList<>(); 1652 StringTokenizer st = new StringTokenizer(v, " "); 1653 while (st.hasMoreTokens()) { 1654 acrValues.add(new ACR(st.nextToken())); 1655 } 1656 } 1657 1658 v = MultivaluedMapUtils.getFirstValue(params, "login_hint_token"); 1659 LoginHintToken loginHintToken = null; 1660 if (StringUtils.isNotBlank(v)) { 1661 loginHintToken = new LoginHintToken(v); 1662 } 1663 1664 v = MultivaluedMapUtils.getFirstValue(params, "id_token_hint"); 1665 JWT idTokenHint = null; 1666 if (StringUtils.isNotBlank(v)) { 1667 try { 1668 idTokenHint = JWTParser.parse(v); 1669 } catch (java.text.ParseException e) { 1670 throw new ParseException("Invalid id_token_hint parameter: " + e.getMessage()); 1671 } 1672 } 1673 1674 String loginHint = MultivaluedMapUtils.getFirstValue(params, "login_hint"); 1675 1676 v = MultivaluedMapUtils.getFirstValue(params, "user_code"); 1677 1678 Secret userCode = null; 1679 if (StringUtils.isNotBlank(v)) { 1680 userCode = new Secret(v); 1681 } 1682 1683 String bindingMessage = MultivaluedMapUtils.getFirstValue(params, "binding_message"); 1684 1685 v = MultivaluedMapUtils.getFirstValue(params, "requested_expiry"); 1686 1687 Integer requestedExpiry = null; 1688 if (StringUtils.isNotBlank(v)) { 1689 try { 1690 requestedExpiry = Integer.valueOf(v); 1691 } catch (NumberFormatException e) { 1692 throw new ParseException("The requested_expiry parameter must be an integer"); 1693 } 1694 } 1695 1696 v = MultivaluedMapUtils.getFirstValue(params, "claims"); 1697 OIDCClaimsRequest claims = null; 1698 if (StringUtils.isNotBlank(v)) { 1699 try { 1700 claims = OIDCClaimsRequest.parse(v); 1701 } catch (ParseException e) { 1702 throw new ParseException("Invalid claims parameter: " + e.getMessage(), e); 1703 } 1704 } 1705 1706 1707 List<LangTag> claimsLocales; 1708 try { 1709 claimsLocales = LangTagUtils.parseLangTagList(MultivaluedMapUtils.getFirstValue(params, "claims_locales")); 1710 } catch (LangTagException e) { 1711 throw new ParseException("Invalid claims_locales parameter: " + e.getMessage(), e); 1712 } 1713 1714 String purpose = MultivaluedMapUtils.getFirstValue(params, "purpose"); 1715 1716 List<AuthorizationDetail> authorizationDetails = null; 1717 v = MultivaluedMapUtils.getFirstValue(params, "authorization_details"); 1718 if (StringUtils.isNotBlank(v)) { 1719 authorizationDetails = AuthorizationDetail.parseList(v); 1720 } 1721 1722 List<URI> resources = ResourceUtils.parseResourceURIs(params.get("resource")); 1723 1724 JSONObject requestContext = null; 1725 v = MultivaluedMapUtils.getFirstValue(params, "request_context"); 1726 if (StringUtils.isNotBlank(v)) { 1727 try { 1728 requestContext = JSONObjectUtils.parse(v); 1729 } catch (ParseException e) { 1730 throw new ParseException("Invalid request_context parameter", e); 1731 } 1732 } 1733 1734 // Parse additional custom parameters 1735 Map<String,List<String>> customParams = null; 1736 1737 for (Map.Entry<String,List<String>> p: params.entrySet()) { 1738 1739 if (! REGISTERED_PARAMETER_NAMES.contains(p.getKey()) && ! clientAuth.getFormParameterNames().contains(p.getKey())) { 1740 // We have a custom parameter 1741 if (customParams == null) { 1742 customParams = new HashMap<>(); 1743 } 1744 customParams.put(p.getKey(), p.getValue()); 1745 } 1746 } 1747 1748 try { 1749 return new CIBARequest( 1750 uri, clientAuth, 1751 scope, clientNotificationToken, acrValues, 1752 loginHintToken, idTokenHint, loginHint, 1753 bindingMessage, userCode, requestedExpiry, 1754 claims, claimsLocales, purpose, authorizationDetails, 1755 resources, requestContext, 1756 customParams); 1757 } catch (IllegalArgumentException e) { 1758 throw new ParseException(e.getMessage()); 1759 } 1760 } 1761}