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