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