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 String loginHintTokenString; 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 for 164 * 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 String loginHintTokenString; 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 loginHintTokenString = request.getLoginHintTokenString(); 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 string, containing information 467 * identifying the end-user for whom authentication is being requested. 468 * Corresponds to the {@code login_hint_token} parameter. 469 * 470 * @param loginHintTokenString The login hint token string, 471 * {@code null} if not specified. 472 * 473 * @return This builder. 474 */ 475 public Builder loginHintTokenString(final String loginHintTokenString) { 476 this.loginHintTokenString = loginHintTokenString; 477 return this; 478 } 479 480 481 /** 482 * Sets the ID Token hint, passed as a hint to identify the 483 * end-user for whom authentication is being requested. 484 * Corresponds to the {@code id_token_hint} parameter. 485 * 486 * @param idTokenHint The ID Token hint, {@code null} if not 487 * specified. 488 * 489 * @return This builder. 490 */ 491 public Builder idTokenHint(final JWT idTokenHint) { 492 this.idTokenHint = idTokenHint; 493 return this; 494 } 495 496 497 /** 498 * Sets the login hint (email address, phone number, etc), 499 * about the end-user for whom authentication is being 500 * requested. Corresponds to the {@code login_hint} parameter. 501 * 502 * @param loginHint The login hint, {@code null} if not 503 * specified. 504 * 505 * @return This builder. 506 */ 507 public Builder loginHint(final String loginHint) { 508 this.loginHint = loginHint; 509 return this; 510 } 511 512 513 /** 514 * Sets the human-readable binding message for the display at 515 * the consumption and authentication devices. Corresponds to 516 * the {@code binding_message} parameter. 517 * 518 * @param bindingMessage The binding message, {@code null} if 519 * not specified. 520 * 521 * @return This builder. 522 */ 523 public Builder bindingMessage(final String bindingMessage) { 524 this.bindingMessage = bindingMessage; 525 return this; 526 } 527 528 529 /** 530 * Gets the user secret code (password, PIN, etc) to authorise 531 * the CIBA request with the authentication device. Corresponds 532 * to the {@code user_code} parameter. 533 * 534 * @param userCode The user code, {@code null} if not 535 * specified. 536 * 537 * @return This builder. 538 */ 539 public Builder userCode(final Secret userCode) { 540 this.userCode = userCode; 541 return this; 542 } 543 544 545 /** 546 * Sets the requested expiration for the {@code auth_req_id}. 547 * Corresponds to the {@code requested_expiry} parameter. 548 * 549 * @param requestedExpiry The required expiry (as positive 550 * integer), {@code null} if not 551 * specified. 552 * 553 * @return This builder. 554 */ 555 public Builder requestedExpiry(final Integer requestedExpiry) { 556 this.requestedExpiry = requestedExpiry; 557 return this; 558 } 559 560 561 /** 562 * Sets the individual OpenID claims to be returned. 563 * Corresponds to the optional {@code claims} parameter. 564 * 565 * @param claims The individual OpenID claims to be returned, 566 * {@code null} if not specified. 567 * 568 * @return This builder. 569 */ 570 public Builder claims(final OIDCClaimsRequest claims) { 571 572 this.claims = claims; 573 return this; 574 } 575 576 577 /** 578 * Sets the end-user's preferred languages and scripts for the 579 * claims being returned, ordered by preference. Corresponds to 580 * the optional {@code claims_locales} parameter. 581 * 582 * @param claimsLocales The preferred claims locales, 583 * {@code null} if not specified. 584 * 585 * @return This builder. 586 */ 587 public Builder claimsLocales(final List<LangTag> claimsLocales) { 588 589 this.claimsLocales = claimsLocales; 590 return this; 591 } 592 593 594 /** 595 * Sets the transaction specific purpose. Corresponds to the 596 * optional {@code purpose} parameter. 597 * 598 * @param purpose The purpose, {@code null} if not specified. 599 * 600 * @return This builder. 601 */ 602 public Builder purpose(final String purpose) { 603 604 this.purpose = purpose; 605 return this; 606 } 607 608 609 /** 610 * Sets the Rich Authorisation Request (RAR) details. 611 * 612 * @param authorizationDetails The authorisation details, 613 * {@code null} if not specified. 614 * 615 * @return This builder. 616 */ 617 public Builder authorizationDetails(final List<AuthorizationDetail> authorizationDetails) { 618 this.authorizationDetails = authorizationDetails; 619 return this; 620 } 621 622 623 /** 624 * Sets the resource server URI. 625 * 626 * @param resource The resource URI, {@code null} if not 627 * specified. 628 * 629 * @return This builder. 630 */ 631 public Builder resource(final URI resource) { 632 if (resource != null) { 633 this.resources = Collections.singletonList(resource); 634 } else { 635 this.resources = null; 636 } 637 return this; 638 } 639 640 641 /** 642 * Sets the resource server URI(s). 643 * 644 * @param resources The resource URI(s), {@code null} if not 645 * specified. 646 * 647 * @return This builder. 648 */ 649 public Builder resources(final URI ... resources) { 650 if (resources != null) { 651 this.resources = Arrays.asList(resources); 652 } else { 653 this.resources = null; 654 } 655 return this; 656 } 657 658 659 /** 660 * Sets the request context. 661 * 662 * @param requestContext The request context, {@code null} if 663 * not specified. 664 * 665 * @return This builder. 666 */ 667 public Builder context(final JSONObject requestContext) { 668 this.requestContext = requestContext; 669 return this; 670 } 671 672 673 /** 674 * Sets a custom parameter. 675 * 676 * @param name The parameter name. Must not be {@code null}. 677 * @param values The parameter values, {@code null} if not 678 * specified. 679 * 680 * @return This builder. 681 */ 682 public Builder customParameter(final String name, final String ... values) { 683 684 if (values == null || values.length == 0) { 685 customParams.remove(name); 686 } else { 687 customParams.put(name, Arrays.asList(values)); 688 } 689 690 return this; 691 } 692 693 694 /** 695 * Sets the URI of the CIBA endpoint. 696 * 697 * @param endpoint The URI of the CIBA endpoint. May be 698 * {@code null} if the {@link #toHTTPRequest()} 699 * method is not going to be used. 700 * 701 * @return This builder. 702 */ 703 public Builder endpointURI(final URI endpoint) { 704 705 this.endpoint = endpoint; 706 return this; 707 } 708 709 710 /** 711 * Builds a new CIBA request. 712 * 713 * @return The CIBA request. 714 */ 715 public CIBARequest build() { 716 717 try { 718 if (signedRequest != null) { 719 return new CIBARequest( 720 endpoint, 721 clientAuth, 722 signedRequest 723 ); 724 } 725 726 // Plain request 727 return new CIBARequest( 728 endpoint, 729 clientAuth, 730 scope, 731 clientNotificationToken, 732 acrValues, 733 loginHintTokenString, 734 idTokenHint, 735 loginHint, 736 bindingMessage, 737 userCode, 738 requestedExpiry, 739 claims, 740 claimsLocales, 741 purpose, 742 authorizationDetails, 743 resources, 744 requestContext, 745 customParams 746 ); 747 } catch (IllegalArgumentException e) { 748 throw new IllegalArgumentException(e.getMessage(), e); 749 } 750 } 751 } 752 753 754 /** 755 * Creates a new CIBA request. 756 * 757 * @param endpoint The URI of the CIBA endpoint. May be 758 * {@code null} if the 759 * {@link #toHTTPRequest()} method is 760 * not going to be used. 761 * @param clientAuth The client authentication. Must not 762 * be {@code null}. 763 * @param scope The requested scope. Must not be 764 * empty or {@code null}. 765 * @param clientNotificationToken The client notification token, 766 * {@code null} if not specified. 767 * @param acrValues The requested ACR values, 768 * {@code null} if not specified. 769 * @param loginHintTokenString The login hint token string, 770 * {@code null} if not specified. 771 * @param idTokenHint The ID Token hint, {@code null} if 772 * not specified. 773 * @param loginHint The login hint, {@code null} if not 774 * specified. 775 * @param bindingMessage The binding message, {@code null} if 776 * not specified. 777 * @param userCode The user code, {@code null} if not 778 * specified. 779 * @param requestedExpiry The required expiry (as positive 780 * integer), {@code null} if not 781 * specified. 782 * @param customParams Custom parameters, empty or 783 * {@code null} if not specified. 784 */ 785 @Deprecated 786 public CIBARequest(final URI endpoint, 787 final ClientAuthentication clientAuth, 788 final Scope scope, 789 final BearerAccessToken clientNotificationToken, 790 final List<ACR> acrValues, 791 final String loginHintTokenString, 792 final JWT idTokenHint, 793 final String loginHint, 794 final String bindingMessage, 795 final Secret userCode, 796 final Integer requestedExpiry, 797 final Map<String, List<String>> customParams) { 798 799 this(endpoint, clientAuth, 800 scope, clientNotificationToken, acrValues, 801 loginHintTokenString, idTokenHint, loginHint, 802 bindingMessage, userCode, requestedExpiry, 803 null, customParams); 804 } 805 806 807 /** 808 * Creates a new CIBA request. 809 * 810 * @param endpoint The URI of the CIBA endpoint. May be 811 * {@code null} if the 812 * {@link #toHTTPRequest()} method is 813 * not going to be used. 814 * @param clientAuth The client authentication. Must not 815 * be {@code null}. 816 * @param scope The requested scope. Must not be 817 * empty or {@code null}. 818 * @param clientNotificationToken The client notification token, 819 * {@code null} if not specified. 820 * @param acrValues The requested ACR values, 821 * {@code null} if not specified. 822 * @param loginHintTokenString The login hint token string, 823 * {@code null} if not specified. 824 * @param idTokenHint The ID Token hint, {@code null} if 825 * not specified. 826 * @param loginHint The login hint, {@code null} if not 827 * specified. 828 * @param bindingMessage The binding message, {@code null} if 829 * not specified. 830 * @param userCode The user code, {@code null} if not 831 * specified. 832 * @param requestedExpiry The required expiry (as positive 833 * integer), {@code null} if not 834 * specified. 835 * @param claims The individual claims to be returned, 836 * {@code null} if not specified. 837 * @param customParams Custom parameters, empty or 838 * {@code null} if not specified. 839 */ 840 @Deprecated 841 public CIBARequest(final URI endpoint, 842 final ClientAuthentication clientAuth, 843 final Scope scope, 844 final BearerAccessToken clientNotificationToken, 845 final List<ACR> acrValues, 846 final String loginHintTokenString, 847 final JWT idTokenHint, 848 final String loginHint, 849 final String bindingMessage, 850 final Secret userCode, 851 final Integer requestedExpiry, 852 final OIDCClaimsRequest claims, 853 final Map<String, List<String>> customParams) { 854 855 this(endpoint, clientAuth, 856 scope, clientNotificationToken, acrValues, 857 loginHintTokenString, idTokenHint, loginHint, 858 bindingMessage, userCode, requestedExpiry, 859 claims, null, null, 860 null, 861 customParams); 862 } 863 864 865 /** 866 * Creates a new CIBA request. 867 * 868 * @param endpoint The URI of the CIBA endpoint. May be 869 * {@code null} if the 870 * {@link #toHTTPRequest()} method is 871 * not going to be used. 872 * @param clientAuth The client authentication. Must not 873 * be {@code null}. 874 * @param scope The requested scope. Must not be 875 * empty or {@code null}. 876 * @param clientNotificationToken The client notification token, 877 * {@code null} if not specified. 878 * @param acrValues The requested ACR values, 879 * {@code null} if not specified. 880 * @param loginHintTokenString The login hint token string, 881 * {@code null} if not specified. 882 * @param idTokenHint The ID Token hint, {@code null} if 883 * not specified. 884 * @param loginHint The login hint, {@code null} if not 885 * specified. 886 * @param bindingMessage The binding message, {@code null} if 887 * not specified. 888 * @param userCode The user code, {@code null} if not 889 * specified. 890 * @param requestedExpiry The required expiry (as positive 891 * integer), {@code null} if not 892 * specified. 893 * @param claims The individual claims to be 894 * returned, {@code null} if not 895 * specified. 896 * @param claimsLocales The preferred languages and scripts 897 * for claims being returned, 898 * {@code null} if not specified. 899 * @param purpose The transaction specific purpose, 900 * {@code null} if not specified. 901 * @param resources The resource URI(s), {@code null} if 902 * not specified. 903 * @param customParams Custom parameters, empty or 904 * {@code null} if not specified. 905 */ 906 @Deprecated 907 public CIBARequest(final URI endpoint, 908 final ClientAuthentication clientAuth, 909 final Scope scope, 910 final BearerAccessToken clientNotificationToken, 911 final List<ACR> acrValues, 912 final String loginHintTokenString, 913 final JWT idTokenHint, 914 final String loginHint, 915 final String bindingMessage, 916 final Secret userCode, 917 final Integer requestedExpiry, 918 final OIDCClaimsRequest claims, 919 final List<LangTag> claimsLocales, 920 final String purpose, 921 final List<URI> resources, 922 final Map<String, List<String>> customParams) { 923 924 this(endpoint, clientAuth, 925 scope, clientNotificationToken, acrValues, 926 loginHintTokenString, idTokenHint, loginHint, 927 bindingMessage, userCode, requestedExpiry, 928 claims, claimsLocales, purpose, null, resources, 929 customParams); 930 } 931 932 933 /** 934 * Creates a new CIBA request. 935 * 936 * @param endpoint The URI of the CIBA endpoint. May be 937 * {@code null} if the 938 * {@link #toHTTPRequest()} method is 939 * not going to be used. 940 * @param clientAuth The client authentication. Must not 941 * be {@code null}. 942 * @param scope The requested scope. Must not be 943 * empty or {@code null}. 944 * @param clientNotificationToken The client notification token, 945 * {@code null} if not specified. 946 * @param acrValues The requested ACR values, 947 * {@code null} if not specified. 948 * @param loginHintTokenString The login hint token string, 949 * {@code null} if not specified. 950 * @param idTokenHint The ID Token hint, {@code null} if 951 * not specified. 952 * @param loginHint The login hint, {@code null} if not 953 * specified. 954 * @param bindingMessage The binding message, {@code null} if 955 * not specified. 956 * @param userCode The user code, {@code null} if not 957 * specified. 958 * @param requestedExpiry The required expiry (as positive 959 * integer), {@code null} if not 960 * specified. 961 * @param claims The individual claims to be 962 * returned, {@code null} if not 963 * specified. 964 * @param claimsLocales The preferred languages and scripts 965 * for claims being returned, 966 * {@code null} if not specified. 967 * @param purpose The transaction specific purpose, 968 * {@code null} if not specified. 969 * @param authorizationDetails The Rich Authorisation Request (RAR) 970 * details, {@code null} if not 971 * specified. 972 * @param resources The resource URI(s), {@code null} if 973 * not specified. 974 * @param customParams Custom parameters, empty or 975 * {@code null} if not specified. 976 */ 977 @Deprecated 978 public CIBARequest(final URI endpoint, 979 final ClientAuthentication clientAuth, 980 final Scope scope, 981 final BearerAccessToken clientNotificationToken, 982 final List<ACR> acrValues, 983 final String loginHintTokenString, 984 final JWT idTokenHint, 985 final String loginHint, 986 final String bindingMessage, 987 final Secret userCode, 988 final Integer requestedExpiry, 989 final OIDCClaimsRequest claims, 990 final List<LangTag> claimsLocales, 991 final String purpose, 992 final List<AuthorizationDetail> authorizationDetails, 993 final List<URI> resources, 994 final Map<String, List<String>> customParams) { 995 996 this(endpoint, clientAuth, 997 scope, clientNotificationToken, acrValues, 998 loginHintTokenString, idTokenHint, loginHint, 999 bindingMessage, userCode, requestedExpiry, 1000 claims, claimsLocales, purpose, authorizationDetails, resources, null, 1001 customParams); 1002 } 1003 1004 1005 /** 1006 * Creates a new CIBA request. 1007 * 1008 * @param endpoint The URI of the CIBA endpoint. May be 1009 * {@code null} if the 1010 * {@link #toHTTPRequest()} method is 1011 * not going to be used. 1012 * @param clientAuth The client authentication. Must not 1013 * be {@code null}. 1014 * @param scope The requested scope. Must not be 1015 * empty or {@code null}. 1016 * @param clientNotificationToken The client notification token, 1017 * {@code null} if not specified. 1018 * @param acrValues The requested ACR values, 1019 * {@code null} if not specified. 1020 * @param loginHintTokenString The login hint token string, 1021 * {@code null} if not specified. 1022 * @param idTokenHint The ID Token hint, {@code null} if 1023 * not specified. 1024 * @param loginHint The login hint, {@code null} if not 1025 * specified. 1026 * @param bindingMessage The binding message, {@code null} if 1027 * not specified. 1028 * @param userCode The user code, {@code null} if not 1029 * specified. 1030 * @param requestedExpiry The required expiry (as positive 1031 * integer), {@code null} if not 1032 * specified. 1033 * @param claims The individual claims to be 1034 * returned, {@code null} if not 1035 * specified. 1036 * @param claimsLocales The preferred languages and scripts 1037 * for claims being returned, 1038 * {@code null} if not specified. 1039 * @param purpose The transaction specific purpose, 1040 * {@code null} if not specified. 1041 * @param authorizationDetails The Rich Authorisation Request (RAR) 1042 * details, {@code null} if not 1043 * specified. 1044 * @param resources The resource URI(s), {@code null} if 1045 * not specified. 1046 * @param requestContext The request context, {@code null} if 1047 * not specified. 1048 * @param customParams Custom parameters, empty or 1049 * {@code null} if not specified. 1050 */ 1051 public CIBARequest(final URI endpoint, 1052 final ClientAuthentication clientAuth, 1053 final Scope scope, 1054 final BearerAccessToken clientNotificationToken, 1055 final List<ACR> acrValues, 1056 final String loginHintTokenString, 1057 final JWT idTokenHint, 1058 final String loginHint, 1059 final String bindingMessage, 1060 final Secret userCode, 1061 final Integer requestedExpiry, 1062 final OIDCClaimsRequest claims, 1063 final List<LangTag> claimsLocales, 1064 final String purpose, 1065 final List<AuthorizationDetail> authorizationDetails, 1066 final List<URI> resources, 1067 final JSONObject requestContext, 1068 final Map<String, List<String>> customParams) { 1069 1070 super(endpoint, clientAuth); 1071 1072 this.scope = scope; 1073 1074 if (clientNotificationToken != null && clientNotificationToken.getValue().length() > CLIENT_NOTIFICATION_TOKEN_MAX_LENGTH) { 1075 throw new IllegalArgumentException("The client notification token must not exceed " + CLIENT_NOTIFICATION_TOKEN_MAX_LENGTH + " chars"); 1076 } 1077 this.clientNotificationToken = clientNotificationToken; 1078 1079 this.acrValues = acrValues; 1080 1081 // https://openid.net/specs/openid-client-initiated-backchannel-authentication-core-1_0-03.html#rfc.section.7.1 1082 // As in the CIBA flow the OP does not have an interaction with 1083 // the end-user through the consumption device, it is REQUIRED 1084 // that the Client provides one (and only one) of the hints 1085 // specified above in the authentication request, that is 1086 // "login_hint_token", "id_token_hint" or "login_hint". 1087 int numHints = 0; 1088 1089 if (loginHintTokenString != null) numHints++; 1090 this.loginHintTokenString = loginHintTokenString; 1091 1092 if (idTokenHint != null) numHints++; 1093 this.idTokenHint = idTokenHint; 1094 1095 if (loginHint != null) numHints++; 1096 this.loginHint = loginHint; 1097 1098 if (numHints != 1) { 1099 throw new IllegalArgumentException("One user identity hist must be provided (login_hint_token, id_token_hint or login_hint)"); 1100 } 1101 1102 this.bindingMessage = bindingMessage; 1103 1104 this.userCode = userCode; 1105 1106 if (requestedExpiry != null && requestedExpiry < 1) { 1107 throw new IllegalArgumentException("The requested expiry must be a positive integer"); 1108 } 1109 this.requestedExpiry = requestedExpiry; 1110 1111 this.claims = claims; 1112 1113 if (claimsLocales != null) { 1114 this.claimsLocales = Collections.unmodifiableList(claimsLocales); 1115 } else { 1116 this.claimsLocales = null; 1117 } 1118 1119 this.purpose = purpose; 1120 1121 this.authorizationDetails = authorizationDetails; 1122 1123 this.resources = ResourceUtils.ensureLegalResourceURIs(resources); 1124 1125 this.requestContext = requestContext; 1126 1127 this.customParams = customParams != null ? customParams : Collections.<String, List<String>>emptyMap(); 1128 1129 signedRequest = null; 1130 } 1131 1132 1133 /** 1134 * Creates a new CIBA signed request. 1135 * 1136 * @param endpoint The URI of the CIBA endpoint. May be 1137 * {@code null} if the {@link #toHTTPRequest()} 1138 * method is not going to be used. 1139 * @param clientAuth The client authentication. Must not be 1140 * {@code null}. 1141 * @param signedRequest The signed request JWT. Must not be 1142 * {@code null}. 1143 */ 1144 public CIBARequest(final URI endpoint, 1145 final ClientAuthentication clientAuth, 1146 final SignedJWT signedRequest) { 1147 1148 super(endpoint, clientAuth); 1149 1150 if (JWSObject.State.UNSIGNED.equals(signedRequest.getState())) { 1151 throw new IllegalArgumentException("The request JWT must be in a signed state"); 1152 } 1153 this.signedRequest = signedRequest; 1154 1155 scope = null; 1156 clientNotificationToken = null; 1157 acrValues = null; 1158 loginHintTokenString = null; 1159 idTokenHint = null; 1160 loginHint = null; 1161 bindingMessage = null; 1162 userCode = null; 1163 requestedExpiry = null; 1164 claims = null; 1165 claimsLocales = null; 1166 authorizationDetails = null; 1167 purpose = null; 1168 resources = null; 1169 requestContext = null; 1170 customParams = Collections.emptyMap(); 1171 } 1172 1173 1174 /** 1175 * Returns the registered (standard) CIBA request parameter names. 1176 * 1177 * @return The registered CIBA request parameter names, as an 1178 * unmodifiable set. 1179 */ 1180 public static Set<String> getRegisteredParameterNames() { 1181 1182 return REGISTERED_PARAMETER_NAMES; 1183 } 1184 1185 1186 /** 1187 * Returns the scope. Corresponds to the optional {@code scope} 1188 * parameter. 1189 * 1190 * @return The scope, {@code null} if not specified. 1191 */ 1192 public Scope getScope() { 1193 1194 return scope; 1195 } 1196 1197 1198 /** 1199 * Returns the client notification token, required for the CIBA ping 1200 * and push token delivery modes. Corresponds to the 1201 * {@code client_notification_token} parameter. 1202 * 1203 * @return The client notification token, {@code null} if not 1204 * specified. 1205 */ 1206 public BearerAccessToken getClientNotificationToken() { 1207 1208 return clientNotificationToken; 1209 } 1210 1211 1212 /** 1213 * Returns the requested Authentication Context Class Reference values. 1214 * Corresponds to the optional {@code acr_values} parameter. 1215 * 1216 * @return The requested ACR values, {@code null} if not specified. 1217 */ 1218 public List<ACR> getACRValues() { 1219 1220 return acrValues; 1221 } 1222 1223 1224 /** 1225 * Returns the hint type. 1226 * 1227 * @return The hint type. 1228 */ 1229 public CIBAHintType getHintType() { 1230 1231 if (getLoginHintTokenString() != null) { 1232 return CIBAHintType.LOGIN_HINT_TOKEN; 1233 } else if (getIDTokenHint() != null) { 1234 return CIBAHintType.ID_TOKEN_HINT; 1235 } else { 1236 return CIBAHintType.LOGIN_HINT; 1237 } 1238 } 1239 1240 1241 /** 1242 * Returns the login hint token string, containing information 1243 * identifying the end-user for whom authentication is being requested. 1244 * Corresponds to the {@code login_hint_token} parameter. 1245 * 1246 * @return The login hint token string, {@code null} if not 1247 * specified. 1248 */ 1249 public String getLoginHintTokenString() { 1250 1251 return loginHintTokenString; 1252 } 1253 1254 1255 /** 1256 * Returns the ID Token hint, passed as a hint to identify the end-user 1257 * for whom authentication is being requested. Corresponds to the 1258 * {@code id_token_hint} parameter. 1259 * 1260 * @return The ID Token hint, {@code null} if not specified. 1261 */ 1262 public JWT getIDTokenHint() { 1263 1264 return idTokenHint; 1265 } 1266 1267 1268 /** 1269 * Returns the login hint (email address, phone number, etc), about the 1270 * end-user for whom authentication is being requested. Corresponds to 1271 * the {@code login_hint} parameter. 1272 * 1273 * @return The login hint, {@code null} if not specified. 1274 */ 1275 public String getLoginHint() { 1276 1277 return loginHint; 1278 } 1279 1280 1281 /** 1282 * Returns the human-readable binding message for the display at the 1283 * consumption and authentication devices. Corresponds to the 1284 * {@code binding_message} parameter. 1285 * 1286 * @return The binding message, {@code null} if not specified. 1287 */ 1288 public String getBindingMessage() { 1289 1290 return bindingMessage; 1291 } 1292 1293 1294 /** 1295 * Returns the user secret code (password, PIN, etc) to authorise the 1296 * CIBA request with the authentication device. Corresponds to the 1297 * {@code user_code} parameter. 1298 * 1299 * @return The user code, {@code null} if not specified. 1300 */ 1301 public Secret getUserCode() { 1302 1303 return userCode; 1304 } 1305 1306 1307 /** 1308 * Returns the requested expiration for the {@code auth_req_id}. 1309 * Corresponds to the {@code requested_expiry} parameter. 1310 * 1311 * @return The required expiry (as positive integer), {@code null} if 1312 * not specified. 1313 */ 1314 public Integer getRequestedExpiry() { 1315 1316 return requestedExpiry; 1317 } 1318 1319 1320 /** 1321 * Returns the individual claims to be returned. Corresponds to the 1322 * optional {@code claims} parameter. 1323 * 1324 * @return The individual claims to be returned, {@code null} if not 1325 * specified. 1326 */ 1327 public OIDCClaimsRequest getOIDCClaims() { 1328 1329 return claims; 1330 } 1331 1332 1333 /** 1334 * Returns the end-user's preferred languages and scripts for the 1335 * claims being returned, ordered by preference. Corresponds to the 1336 * optional {@code claims_locales} parameter. 1337 * 1338 * @return The preferred claims locales, {@code null} if not specified. 1339 */ 1340 public List<LangTag> getClaimsLocales() { 1341 1342 return claimsLocales; 1343 } 1344 1345 1346 /** 1347 * Returns the transaction specific purpose. Corresponds to the 1348 * optional {@code purpose} parameter. 1349 * 1350 * @return The purpose, {@code null} if not specified. 1351 */ 1352 public String getPurpose() { 1353 1354 return purpose; 1355 } 1356 1357 1358 /** 1359 * Returns the Rich Authorisation Request (RAR) details. 1360 * 1361 * @return The authorisation details, {@code null} if not specified. 1362 */ 1363 public List<AuthorizationDetail> getAuthorizationDetails() { 1364 1365 return authorizationDetails; 1366 } 1367 1368 1369 /** 1370 * Returns the resource server URI. 1371 * 1372 * @return The resource URI(s), {@code null} if not specified. 1373 */ 1374 public List<URI> getResources() { 1375 1376 return resources; 1377 } 1378 1379 1380 /** 1381 * Returns the request context. 1382 * 1383 * @return The request context, {@code null} if not specified. 1384 */ 1385 public JSONObject getContext() { 1386 1387 return requestContext; 1388 } 1389 1390 /** 1391 * Returns the additional custom parameters. 1392 * 1393 * @return The additional custom parameters as an unmodifiable map, 1394 * empty map if none. 1395 */ 1396 public Map<String, List<String>> getCustomParameters() { 1397 1398 return customParams; 1399 } 1400 1401 1402 /** 1403 * Returns the specified custom parameter. 1404 * 1405 * @param name The parameter name. Must not be {@code null}. 1406 * 1407 * @return The parameter value(s), {@code null} if not specified. 1408 */ 1409 public List<String> getCustomParameter(final String name) { 1410 1411 return customParams.get(name); 1412 } 1413 1414 1415 /** 1416 * Returns {@code true} if this request is signed. 1417 * 1418 * @return {@code true} for a signed request, {@code false} for a plain 1419 * request. 1420 */ 1421 public boolean isSigned() { 1422 1423 return signedRequest != null; 1424 } 1425 1426 1427 /** 1428 * Returns the JWT for a signed request. 1429 * 1430 * @return The request JWT. 1431 */ 1432 public SignedJWT getRequestJWT() { 1433 1434 return signedRequest; 1435 } 1436 1437 1438 /** 1439 * Returns the for parameters for this CIBA request. Parameters which 1440 * are part of the client authentication are not included. 1441 * 1442 * @return The parameters. 1443 */ 1444 public Map<String, List<String>> toParameters() { 1445 1446 // Put custom params first, so they may be overwritten by std params 1447 Map<String, List<String>> params = new LinkedHashMap<>(getCustomParameters()); 1448 1449 if (isSigned()) { 1450 params.put("request", Collections.singletonList(signedRequest.serialize())); 1451 return params; 1452 } 1453 1454 if (CollectionUtils.isNotEmpty(getScope())) { 1455 params.put("scope", Collections.singletonList(getScope().toString())); 1456 } 1457 1458 if (getClientNotificationToken() != null) { 1459 params.put("client_notification_token", Collections.singletonList(getClientNotificationToken().getValue())); 1460 } 1461 if (getACRValues() != null) { 1462 params.put("acr_values", Identifier.toStringList(getACRValues())); 1463 } 1464 if (getLoginHintTokenString() != null) { 1465 params.put("login_hint_token", Collections.singletonList(getLoginHintTokenString())); 1466 } 1467 if (getIDTokenHint() != null) { 1468 params.put("id_token_hint", Collections.singletonList(getIDTokenHint().serialize())); 1469 } 1470 if (getLoginHint() != null) { 1471 params.put("login_hint", Collections.singletonList(getLoginHint())); 1472 } 1473 if (getBindingMessage() != null) { 1474 params.put("binding_message", Collections.singletonList(getBindingMessage())); 1475 } 1476 if (getUserCode() != null) { 1477 params.put("user_code", Collections.singletonList(getUserCode().getValue())); 1478 } 1479 if (getRequestedExpiry() != null) { 1480 params.put("requested_expiry", Collections.singletonList(getRequestedExpiry().toString())); 1481 } 1482 if (getOIDCClaims() != null) { 1483 params.put("claims", Collections.singletonList(getOIDCClaims().toJSONString())); 1484 } 1485 if (CollectionUtils.isNotEmpty(getClaimsLocales())) { 1486 params.put("claims_locales", Collections.singletonList(LangTagUtils.concat(getClaimsLocales()))); 1487 } 1488 if (getPurpose() != null) { 1489 params.put("purpose", Collections.singletonList(purpose)); 1490 } 1491 if (getAuthorizationDetails() != null) { 1492 params.put("authorization_details", Collections.singletonList(AuthorizationDetail.toJSONString(getAuthorizationDetails()))); 1493 } 1494 if (getContext() != null) { 1495 params.put("request_context", Collections.singletonList(getContext().toJSONString())); 1496 } 1497 if (CollectionUtils.isNotEmpty(getResources())) { 1498 params.put("resource", URIUtils.toStringList(getResources(), true)); 1499 } 1500 1501 return params; 1502 } 1503 1504 1505 /** 1506 * Returns the parameters for this CIBA request as a JSON Web Token 1507 * (JWT) claims set. Intended for creating a signed CIBA request. 1508 * 1509 * @return The parameters as JWT claim set. 1510 */ 1511 public JWTClaimsSet toJWTClaimsSet() { 1512 1513 if (isSigned()) { 1514 throw new IllegalStateException(); 1515 } 1516 1517 return JWTClaimsSetUtils.toJWTClaimsSet(toParameters()); 1518 } 1519 1520 1521 /** 1522 * Returns the matching HTTP request. 1523 * 1524 * @return The HTTP request. 1525 */ 1526 @Override 1527 public HTTPRequest toHTTPRequest() { 1528 1529 if (getEndpointURI() == null) 1530 throw new SerializeException("The endpoint URI is not specified"); 1531 1532 HTTPRequest httpRequest = new HTTPRequest(HTTPRequest.Method.POST, getEndpointURI()); 1533 httpRequest.setEntityContentType(ContentType.APPLICATION_URLENCODED); 1534 1535 getClientAuthentication().applyTo(httpRequest); 1536 1537 Map<String, List<String>> params; 1538 try { 1539 params = new LinkedHashMap<>(httpRequest.getBodyAsFormParameters()); 1540 } catch (ParseException e) { 1541 throw new SerializeException(e.getMessage(), e); 1542 } 1543 params.putAll(toParameters()); 1544 httpRequest.setBody(URLUtils.serializeParameters(params)); 1545 1546 return httpRequest; 1547 } 1548 1549 1550 /** 1551 * Parses a CIBA request from the specified HTTP request. 1552 * 1553 * @param httpRequest The HTTP request. Must not be {@code null}. 1554 * 1555 * @return The CIBA request. 1556 * 1557 * @throws ParseException If parsing failed. 1558 */ 1559 public static CIBARequest parse(final HTTPRequest httpRequest) throws ParseException { 1560 1561 // Only HTTP POST accepted 1562 URI uri = httpRequest.getURI(); 1563 httpRequest.ensureMethod(HTTPRequest.Method.POST); 1564 httpRequest.ensureEntityContentType(ContentType.APPLICATION_URLENCODED); 1565 1566 ClientAuthentication clientAuth = ClientAuthentication.parse(httpRequest); 1567 1568 if (clientAuth == null) { 1569 throw new ParseException("Missing required client authentication"); 1570 } 1571 1572 Map<String, List<String>> params = httpRequest.getQueryParameters(); 1573 1574 String v; 1575 1576 if (params.containsKey("request")) { 1577 // Signed request 1578 v = MultivaluedMapUtils.getFirstValue(params, "request"); 1579 1580 if (StringUtils.isBlank(v)) { 1581 throw new ParseException("Empty request parameter"); 1582 } 1583 1584 SignedJWT signedRequest; 1585 try { 1586 signedRequest = SignedJWT.parse(v); 1587 } catch (java.text.ParseException e) { 1588 throw new ParseException("Invalid request JWT: " + e.getMessage(), e); 1589 } 1590 1591 try { 1592 return new CIBARequest(uri, clientAuth, signedRequest); 1593 } catch (IllegalArgumentException e) { 1594 throw new ParseException(e.getMessage(), e); 1595 } 1596 } 1597 1598 1599 // Plain request 1600 1601 // Parse required scope 1602 v = MultivaluedMapUtils.getFirstValue(params, "scope"); 1603 Scope scope = Scope.parse(v); 1604 1605 v = MultivaluedMapUtils.getFirstValue(params, "client_notification_token"); 1606 BearerAccessToken clientNotificationToken = null; 1607 if (StringUtils.isNotBlank(v)) { 1608 clientNotificationToken = new BearerAccessToken(v); 1609 } 1610 1611 v = MultivaluedMapUtils.getFirstValue(params, "acr_values"); 1612 List<ACR> acrValues = null; 1613 if (StringUtils.isNotBlank(v)) { 1614 acrValues = new LinkedList<>(); 1615 StringTokenizer st = new StringTokenizer(v, " "); 1616 while (st.hasMoreTokens()) { 1617 acrValues.add(new ACR(st.nextToken())); 1618 } 1619 } 1620 1621 String loginHintTokenString = MultivaluedMapUtils.getFirstValue(params, "login_hint_token"); 1622 1623 v = MultivaluedMapUtils.getFirstValue(params, "id_token_hint"); 1624 JWT idTokenHint = null; 1625 if (StringUtils.isNotBlank(v)) { 1626 try { 1627 idTokenHint = JWTParser.parse(v); 1628 } catch (java.text.ParseException e) { 1629 throw new ParseException("Invalid id_token_hint parameter: " + e.getMessage()); 1630 } 1631 } 1632 1633 String loginHint = MultivaluedMapUtils.getFirstValue(params, "login_hint"); 1634 1635 v = MultivaluedMapUtils.getFirstValue(params, "user_code"); 1636 1637 Secret userCode = null; 1638 if (StringUtils.isNotBlank(v)) { 1639 userCode = new Secret(v); 1640 } 1641 1642 String bindingMessage = MultivaluedMapUtils.getFirstValue(params, "binding_message"); 1643 1644 v = MultivaluedMapUtils.getFirstValue(params, "requested_expiry"); 1645 1646 Integer requestedExpiry = null; 1647 if (StringUtils.isNotBlank(v)) { 1648 try { 1649 requestedExpiry = Integer.valueOf(v); 1650 } catch (NumberFormatException e) { 1651 throw new ParseException("The requested_expiry parameter must be an integer"); 1652 } 1653 } 1654 1655 v = MultivaluedMapUtils.getFirstValue(params, "claims"); 1656 OIDCClaimsRequest claims = null; 1657 if (StringUtils.isNotBlank(v)) { 1658 try { 1659 claims = OIDCClaimsRequest.parse(v); 1660 } catch (ParseException e) { 1661 throw new ParseException("Invalid claims parameter: " + e.getMessage(), e); 1662 } 1663 } 1664 1665 1666 List<LangTag> claimsLocales; 1667 try { 1668 claimsLocales = LangTagUtils.parseLangTagList(MultivaluedMapUtils.getFirstValue(params, "claims_locales")); 1669 } catch (LangTagException e) { 1670 throw new ParseException("Invalid claims_locales parameter: " + e.getMessage(), e); 1671 } 1672 1673 String purpose = MultivaluedMapUtils.getFirstValue(params, "purpose"); 1674 1675 List<AuthorizationDetail> authorizationDetails = null; 1676 v = MultivaluedMapUtils.getFirstValue(params, "authorization_details"); 1677 if (StringUtils.isNotBlank(v)) { 1678 authorizationDetails = AuthorizationDetail.parseList(v); 1679 } 1680 1681 List<URI> resources = ResourceUtils.parseResourceURIs(params.get("resource")); 1682 1683 JSONObject requestContext = null; 1684 v = MultivaluedMapUtils.getFirstValue(params, "request_context"); 1685 if (StringUtils.isNotBlank(v)) { 1686 try { 1687 requestContext = JSONObjectUtils.parse(v); 1688 } catch (ParseException e) { 1689 throw new ParseException("Invalid request_context parameter", e); 1690 } 1691 } 1692 1693 // Parse additional custom parameters 1694 Map<String,List<String>> customParams = null; 1695 1696 for (Map.Entry<String,List<String>> p: params.entrySet()) { 1697 1698 if (! REGISTERED_PARAMETER_NAMES.contains(p.getKey()) && ! clientAuth.getFormParameterNames().contains(p.getKey())) { 1699 // We have a custom parameter 1700 if (customParams == null) { 1701 customParams = new HashMap<>(); 1702 } 1703 customParams.put(p.getKey(), p.getValue()); 1704 } 1705 } 1706 1707 try { 1708 return new CIBARequest( 1709 uri, clientAuth, 1710 scope, clientNotificationToken, acrValues, 1711 loginHintTokenString, idTokenHint, loginHint, 1712 bindingMessage, userCode, requestedExpiry, 1713 claims, claimsLocales, purpose, authorizationDetails, 1714 resources, requestContext, 1715 customParams); 1716 } catch (IllegalArgumentException e) { 1717 throw new ParseException(e.getMessage()); 1718 } 1719 } 1720}