001/*
002 * oauth2-oidc-sdk
003 *
004 * Copyright 2012-2020, 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.openid.connect.sdk;
019
020
021import java.util.*;
022
023import net.jcip.annotations.Immutable;
024import net.minidev.json.JSONArray;
025import net.minidev.json.JSONAware;
026import net.minidev.json.JSONObject;
027
028import com.nimbusds.oauth2.sdk.ParseException;
029import com.nimbusds.oauth2.sdk.ResponseType;
030import com.nimbusds.oauth2.sdk.Scope;
031import com.nimbusds.oauth2.sdk.util.JSONArrayUtils;
032import com.nimbusds.oauth2.sdk.util.JSONObjectUtils;
033import com.nimbusds.openid.connect.sdk.assurance.claims.VerifiedClaimsSetRequest;
034import com.nimbusds.openid.connect.sdk.claims.ClaimRequirement;
035import com.nimbusds.openid.connect.sdk.claims.ClaimsSetRequest;
036
037
038/**
039 * Specifies individual OpenID claims to return from the UserInfo endpoint and
040 * / or in the ID Token. Replaces the deprecated {@link ClaimsRequest} class.
041 *
042 * <p>Example:
043 *
044 * <pre>
045 * {
046 *   "userinfo":
047 *    {
048 *     "given_name": {"essential": true},
049 *     "nickname": null,
050 *     "email": {"essential": true},
051 *     "email_verified": {"essential": true},
052 *     "picture": null,
053 *     "http://example.info/claims/groups": null
054 *    },
055 *   "id_token":
056 *    {
057 *     "auth_time": {"essential": true},
058 *     "acr": {"values": ["urn:mace:incommon:iap:silver"] }
059 *    }
060 * }
061 * </pre>
062 *
063 * <p>Related specifications:
064 *
065 * <ul>
066 *     <li>OpenID Connect Core 1.0, section 5.5.
067 *     <li>OpenID Connect for Identity Assurance 1.0.
068 * </ul>
069 */
070@Immutable
071public class OIDCClaimsRequest implements JSONAware {
072        
073        
074        /**
075         * Claims requested in the ID token, {@code null} if not specified.
076         */
077        private final ClaimsSetRequest idToken;
078        
079        
080        /**
081         * Claims requested at the UserInfo endpoint, {@code null} if not
082         * specified.
083         */
084        private final ClaimsSetRequest userInfo;
085        
086        
087        /**
088         * Verified claims requested in the ID token, empty list if not
089         * specified.
090         */
091        private final List<VerifiedClaimsSetRequest> idTokenVerified;
092        
093        
094        /**
095         * Verified claims requested at the UserInfo endpoint, empty list if
096         * not specified.
097         */
098        private final List<VerifiedClaimsSetRequest> userInfoVerified;
099        
100        
101        /**
102         * Creates a new empty OpenID claims request.
103         */
104        public OIDCClaimsRequest() {
105                this(null, null, Collections.<VerifiedClaimsSetRequest>emptyList(), Collections.<VerifiedClaimsSetRequest>emptyList());
106        }
107        
108        
109        private OIDCClaimsRequest(final ClaimsSetRequest idToken,
110                                  final ClaimsSetRequest userInfo,
111                                  final List<VerifiedClaimsSetRequest> idTokenVerified,
112                                  final List<VerifiedClaimsSetRequest> userInfoVerified) {
113                
114                this.idToken = idToken;
115                
116                this.userInfo = userInfo;
117                
118                if (idTokenVerified == null) {
119                        throw new IllegalArgumentException("The ID token verified claims set request list must not be null");
120                }
121                this.idTokenVerified = Collections.unmodifiableList(idTokenVerified);
122                
123                if (userInfoVerified == null) {
124                        throw new IllegalArgumentException("The UserInfo verified claims set request list must not be null");
125                }
126                this.userInfoVerified = Collections.unmodifiableList(userInfoVerified);
127        }
128        
129        
130        /**
131         * Adds the entries from the specified other OpenID claims request.
132         *
133         * @param other The other OpenID claims request. If {@code null} no
134         *              claims request entries will be added to this claims
135         *              request.
136         *
137         * @return The updated OpenID claims request.
138         */
139        public OIDCClaimsRequest add(final OIDCClaimsRequest other) {
140                
141                if (other == null)
142                        return this;
143                
144                // Regular id_token
145                Collection<ClaimsSetRequest.Entry> idTokenEntries = new LinkedList<>();
146                if (idToken != null) {
147                        idTokenEntries.addAll(idToken.getEntries());
148                }
149                if (other.getIDTokenClaimsRequest() != null) {
150                        idTokenEntries.addAll(other.getIDTokenClaimsRequest().getEntries());
151                }
152                
153                // Regular userinfo
154                Collection<ClaimsSetRequest.Entry> userInfoEntries = new LinkedList<>();
155                if (userInfo != null) {
156                        userInfoEntries.addAll(userInfo.getEntries());
157                }
158                if (other.getUserInfoClaimsRequest() != null) {
159                        userInfoEntries.addAll(other.getUserInfoClaimsRequest().getEntries());
160                }
161                
162                // Verified id_token
163                List<VerifiedClaimsSetRequest> idTokenVerifiedList = new LinkedList<>(idTokenVerified);
164                idTokenVerifiedList.addAll(other.getIDTokenVerifiedClaimsRequestList());
165                
166                // Verified userinfo
167                List<VerifiedClaimsSetRequest> userInfoVerifiedList = new LinkedList<>(userInfoVerified);
168                userInfoVerifiedList.addAll(other.getUserInfoVerifiedClaimsRequestList());
169                
170                return new OIDCClaimsRequest(
171                        idTokenEntries.isEmpty() ? null : new ClaimsSetRequest(idTokenEntries),
172                        userInfoEntries.isEmpty() ? null : new ClaimsSetRequest(userInfoEntries),
173                        idTokenVerifiedList,
174                        userInfoVerifiedList
175                );
176        }
177        
178        
179        /**
180         * Returns the claims requested in the ID token.
181         *
182         * @return The ID token claims request, {@code null} if not specified.
183         */
184        public ClaimsSetRequest getIDTokenClaimsRequest() {
185                return idToken;
186        }
187        
188        
189        /**
190         * Sets the claims requested in the ID token.
191         *
192         * @param idToken The ID token claims request, {@code null} if not
193         *                specified.
194         *
195         * @return The updated OpenID claims request.
196         */
197        public OIDCClaimsRequest withIDTokenClaimsRequest(final ClaimsSetRequest idToken) {
198                return new OIDCClaimsRequest(
199                        idToken,
200                        getUserInfoClaimsRequest(),
201                        getIDTokenVerifiedClaimsRequestList(),
202                        getUserInfoVerifiedClaimsRequestList());
203        }
204        
205        
206        /**
207         * Returns the claims requested at the UserInfo endpoint.
208         *
209         * @return The UserInfo claims request, {@code null} if not specified.
210         */
211        public ClaimsSetRequest getUserInfoClaimsRequest() {
212                return userInfo;
213        }
214        
215        
216        /**
217         * Sets the claims requested at the UserInfo endpoint.
218         *
219         * @param userInfo The UserInfo claims request, {@code null} if not
220         *                 specified.
221         *
222         * @return The updated OpenID claims request.
223         */
224        public OIDCClaimsRequest withUserInfoClaimsRequest(final ClaimsSetRequest userInfo) {
225                return new OIDCClaimsRequest(
226                        getIDTokenClaimsRequest(),
227                        userInfo,
228                        getIDTokenVerifiedClaimsRequestList(),
229                        getUserInfoVerifiedClaimsRequestList());
230        }
231        
232        
233        /**
234         * Returns the list of verified claims sets requested in the ID token.
235         *
236         * @return The ID token verified claims request list, empty list if not
237         *         specified.
238         */
239        public List<VerifiedClaimsSetRequest> getIDTokenVerifiedClaimsRequestList() {
240                return idTokenVerified;
241        }
242        
243        
244        /**
245         * Sets the list of verified claims sets requested in the ID token.
246         *
247         * @param idTokenVerifiedList One or more ID token verified claims
248         *                            requests, empty list if not specified.
249         *
250         * @return The updated OpenID claims request.
251         */
252        public OIDCClaimsRequest withIDTokenVerifiedClaimsRequestList(final List<VerifiedClaimsSetRequest> idTokenVerifiedList) {
253                return new OIDCClaimsRequest(
254                        getIDTokenClaimsRequest(),
255                        getUserInfoClaimsRequest(),
256                        idTokenVerifiedList != null ? idTokenVerifiedList : Collections.<VerifiedClaimsSetRequest>emptyList(),
257                        getUserInfoVerifiedClaimsRequestList());
258        }
259        
260        
261        /**
262         * Sets a single verified claims set requested in the ID token.
263         *
264         * @param idTokenVerified The ID token verified claims request,
265         *                        {@code null} if not specified.
266         *
267         * @return The updated OpenID claims request.
268         */
269        public OIDCClaimsRequest withIDTokenVerifiedClaimsRequest(final VerifiedClaimsSetRequest idTokenVerified) {
270                return new OIDCClaimsRequest(
271                        getIDTokenClaimsRequest(),
272                        getUserInfoClaimsRequest(),
273                        idTokenVerified != null ? Collections.singletonList(idTokenVerified) : Collections.<VerifiedClaimsSetRequest>emptyList(),
274                        getUserInfoVerifiedClaimsRequestList());
275        }
276        
277        
278        /**
279         * Returns the list of verified claims sets requested at the UserInfo
280         * endpoint.
281         *
282         * @return The UserInfo verified claims request list, empty list if not
283         *         specified.
284         */
285        public List<VerifiedClaimsSetRequest> getUserInfoVerifiedClaimsRequestList() {
286                return userInfoVerified;
287        }
288        
289        
290        /**
291         * Sets the list of verified claims sets requested at the UserInfo
292         * endpoint.
293         *
294         * @param userInfoVerifiedList One or more UserInfo verified claims
295         *                             requests, empty list if not specified.
296         *
297         * @return The updated OpenID claims request.
298         */
299        public OIDCClaimsRequest withUserInfoVerifiedClaimsRequestList(final List<VerifiedClaimsSetRequest> userInfoVerifiedList) {
300                return new OIDCClaimsRequest(
301                        getIDTokenClaimsRequest(),
302                        getUserInfoClaimsRequest(),
303                        getIDTokenVerifiedClaimsRequestList(),
304                        userInfoVerifiedList != null ? userInfoVerifiedList : Collections.<VerifiedClaimsSetRequest>emptyList());
305        }
306        
307        
308        /**
309         * Sets a single verified claims set requested at the UserInfo
310         * endpoint.
311         *
312         * @param userInfoVerified The UserInfo verified claims request,
313         *                         {@code null} if not specified.
314         *
315         * @return The updated OpenID claims request.
316         */
317        public OIDCClaimsRequest withUserInfoVerifiedClaimsRequest(final VerifiedClaimsSetRequest userInfoVerified) {
318                return new OIDCClaimsRequest(
319                        getIDTokenClaimsRequest(),
320                        getUserInfoClaimsRequest(),
321                        getIDTokenVerifiedClaimsRequestList(),
322                        userInfoVerified != null ? Collections.singletonList(userInfoVerified) : Collections.<VerifiedClaimsSetRequest>emptyList());
323        }
324        
325        
326        private static JSONObject addVerified(final List<VerifiedClaimsSetRequest> verified,
327                                              final JSONObject containingJSONObject) {
328                
329                if (verified != null) {
330                        
331                        if (verified.size() == 1 && verified.get(0) != null) {
332                                JSONObject out = new JSONObject();
333                                if (containingJSONObject != null) {
334                                        out.putAll(containingJSONObject);
335                                }
336                                out.put("verified_claims", verified.get(0).toJSONObject());
337                                return out;
338                        } else if (verified.size() > 1) {
339                                JSONObject out = new JSONObject();
340                                if (containingJSONObject != null) {
341                                        out.putAll(containingJSONObject);
342                                }
343                                JSONArray jsonArray = new JSONArray();
344                                for (VerifiedClaimsSetRequest verifiedClaims: verified) {
345                                        jsonArray.add(verifiedClaims.toJSONObject());
346                                }
347                                out.put("verified_claims", jsonArray);
348                                return out;
349                        }
350                }
351                return containingJSONObject;
352        }
353        
354        
355        /**
356         * Returns the JSON object representation of this OpenID claims
357         * request.
358         *
359         * <p>Example:
360         *
361         * <pre>
362         * {
363         *   "userinfo":
364         *    {
365         *     "given_name": {"essential": true},
366         *     "nickname": null,
367         *     "email": {"essential": true},
368         *     "email_verified": {"essential": true},
369         *     "picture": null,
370         *     "http://example.info/claims/groups": null
371         *    },
372         *   "id_token":
373         *    {
374         *     "auth_time": {"essential": true},
375         *     "acr": {"values": ["urn:mace:incommon:iap:silver"] }
376         *    }
377         * }
378         * </pre>
379         *
380         * @return The JSON object, empty if no ID token and UserInfo claims
381         *         are specified.
382         */
383        public JSONObject toJSONObject() {
384                
385                JSONObject o = new JSONObject();
386                
387                // id_token
388                JSONObject idTokenJSONObject = null;
389                if (idToken != null) {
390                         idTokenJSONObject = idToken.toJSONObject();
391                }
392                idTokenJSONObject = addVerified(idTokenVerified, idTokenJSONObject);
393                if (idTokenJSONObject != null && ! idTokenJSONObject.isEmpty()) {
394                        o.put("id_token", idTokenJSONObject);
395                }
396                
397                // userinfo
398                JSONObject userInfoJSONObject = null;
399                if (userInfo != null) {
400                         userInfoJSONObject = userInfo.toJSONObject();
401                }
402                userInfoJSONObject = addVerified(userInfoVerified, userInfoJSONObject);
403                if (userInfoJSONObject != null && ! userInfoJSONObject.isEmpty()) {
404                        o.put("userinfo", userInfoJSONObject);
405                }
406                
407                return o;
408        }
409        
410        
411        @Override
412        public String toJSONString() {
413                return toJSONObject().toJSONString();
414        }
415        
416        
417        @Override
418        public String toString() {
419                
420                return toJSONString();
421        }
422        
423        
424        /**
425         * Resolves the OpenID claims request for the specified response type
426         * and scope. The scope values that are {@link OIDCScopeValue standard
427         * OpenID scope values} are resolved to their respective individual
428         * claims requests, any other scope values are ignored.
429         *
430         * @param responseType The response type. Must not be {@code null}.
431         * @param scope        The scope, {@code null} if not specified (for a
432         *                     plain OAuth 2.0 authorisation request with no
433         *                     scope explicitly specified).
434         *
435         * @return The OpenID claims request.
436         */
437        public static OIDCClaimsRequest resolve(final ResponseType responseType, final Scope scope) {
438                
439                return resolve(responseType, scope, Collections.<Scope.Value, Set<String>>emptyMap());
440        }
441        
442        
443        /**
444         * Resolves the OpenID claims request for the specified response type
445         * and scope. The scope values that are {@link OIDCScopeValue standard
446         * OpenID scope values} are resolved to their respective individual
447         * claims requests, any other scope values are checked in the specified
448         * custom claims map and resolved accordingly.
449         *
450         * @param responseType The response type. Must not be {@code null}.
451         * @param scope        The scope, {@code null} if not specified (for a
452         *                     plain OAuth 2.0 authorisation request with no
453         *                     scope explicitly specified).
454         * @param customClaims Custom scope value to set of claim names map,
455         *                     {@code null} if not specified.
456         *
457         * @return The OpenID claims request.
458         */
459        public static OIDCClaimsRequest resolve(final ResponseType responseType,
460                                                final Scope scope,
461                                                final Map<Scope.Value, Set<String>> customClaims) {
462                
463                OIDCClaimsRequest claimsRequest = new OIDCClaimsRequest();
464                
465                if (scope == null) {
466                        // Plain OAuth 2.0 mode
467                        return claimsRequest;
468                }
469                
470                List<ClaimsSetRequest.Entry> entries = new LinkedList<>();
471                for (Scope.Value value : scope) {
472                        
473                        if (value.equals(OIDCScopeValue.PROFILE)) {
474                                
475                                entries.addAll(OIDCScopeValue.PROFILE.toClaimsSetRequestEntries());
476                                
477                        } else if (value.equals(OIDCScopeValue.EMAIL)) {
478                                
479                                entries.addAll(OIDCScopeValue.EMAIL.toClaimsSetRequestEntries());
480                                
481                        } else if (value.equals(OIDCScopeValue.PHONE)) {
482                                
483                                entries.addAll(OIDCScopeValue.PHONE.toClaimsSetRequestEntries());
484                                
485                        } else if (value.equals(OIDCScopeValue.ADDRESS)) {
486                                
487                                entries.addAll(OIDCScopeValue.ADDRESS.toClaimsSetRequestEntries());
488                                
489                        } else if (customClaims != null && customClaims.containsKey(value)) {
490                                
491                                // Process custom scope value -> claim names expansion, e.g.
492                                // "corp_profile" -> ["employeeNumber", "dept", "ext"]
493                                Set<String> claimNames = customClaims.get(value);
494                                
495                                if (claimNames == null || claimNames.isEmpty()) {
496                                        continue; // skip
497                                }
498                                
499                                for (String claimName : claimNames) {
500                                        entries.add(new ClaimsSetRequest.Entry(claimName).withClaimRequirement(ClaimRequirement.VOLUNTARY));
501                                }
502                                
503                        }
504                }
505                
506                if (entries.isEmpty()) {
507                        return claimsRequest;
508                }
509                        
510                ClaimsSetRequest claimsSetRequest = new ClaimsSetRequest(entries);
511                
512                // Determine the claims target (ID token or UserInfo)
513                final boolean switchToIDToken =
514                        responseType.contains(OIDCResponseTypeValue.ID_TOKEN) &&
515                                !responseType.contains(ResponseType.Value.CODE) &&
516                                !responseType.contains(ResponseType.Value.TOKEN);
517                        
518                if (switchToIDToken) {
519                        return claimsRequest.withIDTokenClaimsRequest(claimsSetRequest);
520                } else {
521                        return claimsRequest.withUserInfoClaimsRequest(claimsSetRequest);
522                }
523        }
524        
525        
526        /**
527         * Resolves the merged OpenID claims request from the specified OpenID
528         * authentication request parameters. The scope values that are {@link
529         * OIDCScopeValue standard OpenID scope values} are resolved to their
530         * respective individual claims requests, any other scope values are
531         * ignored.
532         *
533         * @param responseType  The response type. Must not be {@code null}.
534         * @param scope         The scope, {@code null} if not specified (for a
535         *                      plain OAuth 2.0 authorisation request with no
536         *                      scope explicitly specified).
537         * @param claimsRequest The OpenID claims request, corresponding to the
538         *                      optional {@code claims} OpenID authentication
539         *                      request parameter, {@code null} if not
540         *                      specified.
541         *
542         * @return The merged OpenID claims request.
543         */
544        public static OIDCClaimsRequest resolve(final ResponseType responseType,
545                                                final Scope scope,
546                                                final OIDCClaimsRequest claimsRequest) {
547                
548                return resolve(responseType, scope, claimsRequest, Collections.<Scope.Value, Set<String>>emptyMap());
549        }
550        
551        
552        /**
553         * Resolves the merged OpenID claims request from the specified OpenID
554         * authentication request parameters. The scope values that are {@link
555         * OIDCScopeValue standard OpenID scope values} are resolved to their
556         * respective individual claims requests, any other scope values are
557         * checked in the specified custom claims map and resolved accordingly.
558         *
559         * @param responseType  The response type. Must not be {@code null}.
560         * @param scope         The scope, {@code null} if not specified (for a
561         *                      plain OAuth 2.0 authorisation request with no
562         *                      scope explicitly specified).
563         * @param claimsRequest The OpenID claims request, corresponding to the
564         *                      optional {@code claims} OpenID authentication
565         *                      request parameter, {@code null} if not
566         *                      specified.
567         * @param customClaims  Custom scope value to set of claim names map,
568         *                      {@code null} if not specified.
569         *
570         * @return The merged OpenID claims request.
571         */
572        public static OIDCClaimsRequest resolve(final ResponseType responseType,
573                                                final Scope scope,
574                                                final OIDCClaimsRequest claimsRequest,
575                                                final Map<Scope.Value, Set<String>> customClaims) {
576                
577                return resolve(responseType, scope, customClaims).add(claimsRequest);
578        }
579        
580        
581        /**
582         * Resolves the merged OpenID claims request for the specified OpenID
583         * authentication request. The scope values that are {@link
584         * OIDCScopeValue standard OpenID scope values} are resolved to their
585         * respective individual claims requests, any other scope values are
586         * ignored.
587         *
588         * @param authRequest The OpenID authentication request. Must not be
589         *                    {@code null}.
590         *
591         * @return The merged OpenID claims request.
592         */
593        public static OIDCClaimsRequest resolve(final AuthenticationRequest authRequest) {
594                
595                return resolve(authRequest.getResponseType(), authRequest.getScope(), authRequest.getOIDCClaims());
596        }
597        
598        
599        private static VerifiedClaimsSetRequest parseVerifiedClaimsSetRequest(final JSONObject jsonObject,
600                                                                              final int position)
601                throws ParseException {
602                
603                try {
604                        return VerifiedClaimsSetRequest.parse(jsonObject);
605                } catch (ParseException e) {
606                        throw new ParseException("Invalid verified claims request" +
607                                (position > -1 ? " at position " + position : "") +
608                                ": " + e.getMessage());
609                }
610        }
611        
612        
613        private static List<VerifiedClaimsSetRequest> parseVerified(final JSONObject containingJSONObject)
614                throws ParseException {
615                
616                if (! containingJSONObject.containsKey("verified_claims")) {
617                        // No verified claims
618                        return Collections.emptyList();
619                }
620                
621                if (containingJSONObject.get("verified_claims") instanceof JSONObject) {
622                        // Single verified claims element
623                        JSONObject vo = JSONObjectUtils.getJSONObject(containingJSONObject, "verified_claims");
624                        return Collections.singletonList(parseVerifiedClaimsSetRequest(vo, -1));
625                        
626                } else {
627                        // Array of one or more verified claims elements
628                        JSONArray va = JSONObjectUtils.getJSONArray(containingJSONObject, "verified_claims");
629                        List<VerifiedClaimsSetRequest> out = new LinkedList<>();
630                        int pos = 0;
631                        for (JSONObject vo: JSONArrayUtils.toJSONObjectList(va)) {
632                                out.add(parseVerifiedClaimsSetRequest(vo, pos++));
633                        }
634                        return out;
635                }
636        }
637        
638        
639        /**
640         * Parses an OpenID claims request from the specified JSON object
641         * representation.
642         *
643         * <p>Example:
644         *
645         * <pre>
646         * {
647         *   "userinfo":
648         *    {
649         *     "given_name": {"essential": true},
650         *     "nickname": null,
651         *     "email": {"essential": true},
652         *     "email_verified": {"essential": true},
653         *     "picture": null,
654         *     "http://example.info/claims/groups": null
655         *    },
656         *   "id_token":
657         *    {
658         *     "auth_time": {"essential": true},
659         *     "acr": {"values": ["urn:mace:incommon:iap:silver"] }
660         *    }
661         * }
662         * </pre>
663         *
664         * @param jsonObject The JSON object to parse. Must not be
665         *                   {@code null}.
666         *
667         * @return The OpenID claims request.
668         *
669         * @throws ParseException If parsing failed.
670         */
671        public static OIDCClaimsRequest parse(final JSONObject jsonObject)
672                throws ParseException {
673                
674                OIDCClaimsRequest claimsRequest = new OIDCClaimsRequest();
675                
676                JSONObject idTokenObject = JSONObjectUtils.getJSONObject(jsonObject, "id_token", null);
677                
678                if (idTokenObject != null) {
679                        ClaimsSetRequest csr = ClaimsSetRequest.parse(idTokenObject);
680                        if (! csr.getEntries().isEmpty()) {
681                                claimsRequest = claimsRequest.withIDTokenClaimsRequest(csr);
682                        }
683                        claimsRequest = claimsRequest.withIDTokenVerifiedClaimsRequestList(parseVerified(idTokenObject));
684                }
685                
686                JSONObject userInfoObject = JSONObjectUtils.getJSONObject(jsonObject, "userinfo", null);
687                
688                if (userInfoObject != null) {
689                        ClaimsSetRequest csr = ClaimsSetRequest.parse(userInfoObject);
690                        if (! csr.getEntries().isEmpty()) {
691                                claimsRequest = claimsRequest.withUserInfoClaimsRequest(ClaimsSetRequest.parse(userInfoObject));
692                        }
693                        claimsRequest = claimsRequest.withUserInfoVerifiedClaimsRequestList(parseVerified(userInfoObject));
694                }
695                
696                return claimsRequest;
697        }
698        
699        
700        /**
701         * Parses an OpenID claims request from the specified JSON object
702         * string representation.
703         *
704         * <p>Example:
705         *
706         * <pre>
707         * {
708         *   "userinfo":
709         *    {
710         *     "given_name": {"essential": true},
711         *     "nickname": null,
712         *     "email": {"essential": true},
713         *     "email_verified": {"essential": true},
714         *     "picture": null,
715         *     "http://example.info/claims/groups": null
716         *    },
717         *   "id_token":
718         *    {
719         *     "auth_time": {"essential": true},
720         *     "acr": {"values": ["urn:mace:incommon:iap:silver"] }
721         *    }
722         * }
723         * </pre>
724         *
725         * @param json The JSON object string to parse. Must not be
726         *             {@code null}.
727         *
728         * @return The OpenID claims request.
729         *
730         * @throws ParseException If parsing failed.
731         */
732        public static OIDCClaimsRequest parse(final String json)
733                throws ParseException {
734                
735                return parse(JSONObjectUtils.parse(json));
736        }
737}