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