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.openid.connect.sdk.claims;
019
020
021import java.net.URI;
022import java.util.Collections;
023import java.util.Date;
024import java.util.HashMap;
025import java.util.LinkedHashSet;
026import java.util.Map;
027import java.util.Set;
028
029import javax.mail.internet.InternetAddress;
030
031import net.minidev.json.JSONObject;
032
033import com.nimbusds.langtag.LangTag;
034
035import com.nimbusds.jwt.JWTClaimsSet;
036
037import com.nimbusds.oauth2.sdk.ParseException;
038import com.nimbusds.oauth2.sdk.id.Subject;
039import com.nimbusds.oauth2.sdk.util.JSONObjectUtils;
040
041
042/**
043 * UserInfo claims set, serialisable to a JSON object.
044 *
045 * <p>Example UserInfo claims set:
046 *
047 * <pre>
048 * {
049 *   "sub"                : "248289761001",
050 *   "name"               : "Jane Doe",
051 *   "given_name"         : "Jane",
052 *   "family_name"        : "Doe",
053 *   "preferred_username" : "j.doe",
054 *   "email"              : "[email protected]",
055 *   "picture"            : "http://example.com/janedoe/me.jpg"
056 * }
057 * </pre>
058 *
059 * <p>Related specifications:
060 *
061 * <ul>
062 *     <li>OpenID Connect Core 1.0, section 5.1.
063 * </ul>
064 */
065public class UserInfo extends ClaimsSet {
066
067
068        /**
069         * The subject claim name.
070         */
071        public static final String SUB_CLAIM_NAME = "sub";
072
073
074        /**
075         * The name claim name.
076         */
077        public static final String NAME_CLAIM_NAME = "name";
078
079
080        /**
081         * The given name claim name.
082         */
083        public static final String GIVEN_NAME_CLAIM_NAME = "given_name";
084
085
086        /**
087         * The family name claim name.
088         */
089        public static final String FAMILY_NAME_CLAIM_NAME = "family_name";
090
091
092        /**
093         * The middle name claim name.
094         */
095        public static final String MIDDLE_NAME_CLAIM_NAME = "middle_name";
096
097
098        /**
099         * The nickname claim name.
100         */
101        public static final String NICKNAME_CLAIM_NAME = "nickname";
102
103
104        /**
105         * The preferred username claim name.
106         */
107        public static final String PREFERRED_USERNAME_CLAIM_NAME = "preferred_username";
108
109
110        /**
111         * The profile claim name.
112         */
113        public static final String PROFILE_CLAIM_NAME = "profile";
114
115
116        /**
117         * The picture claim name.
118         */
119        public static final String PICTURE_CLAIM_NAME = "picture";
120
121
122        /**
123         * The website claim name.
124         */
125        public static final String WEBSITE_CLAIM_NAME = "website";
126
127
128        /**
129         * The email claim name.
130         */
131        public static final String EMAIL_CLAIM_NAME = "email";
132
133
134        /**
135         * The email verified claim name.
136         */
137        public static final String EMAIL_VERIFIED_CLAIM_NAME = "email_verified";
138
139
140        /**
141         * The gender claim name.
142         */
143        public static final String GENDER_CLAIM_NAME = "gender";
144
145
146        /**
147         * The birth date claim name.
148         */
149        public static final String BIRTHDATE_CLAIM_NAME = "birthdate";
150
151
152        /**
153         * The zoneinfo claim name.
154         */
155        public static final String ZONEINFO_CLAIM_NAME = "zoneinfo";
156
157
158        /**
159         * The locale claim name.
160         */
161        public static final String LOCALE_CLAIM_NAME = "locale";
162
163
164        /**
165         * The phone number claim name.
166         */
167        public static final String PHONE_NUMBER_CLAIM_NAME = "phone_number";
168
169
170        /**
171         * The phone number verified claim name.
172         */
173        public static final String PHONE_NUMBER_VERIFIED_CLAIM_NAME = "phone_number_verified";
174
175
176        /**
177         * The address claim name.
178         */
179        public static final String ADDRESS_CLAIM_NAME = "address";
180
181
182        /**
183         * The updated at claim name.
184         */
185        public static final String UPDATED_AT_CLAIM_NAME = "updated_at";
186
187
188        /**
189         * The names of the standard top-level UserInfo claims.
190         */
191        private static final Set<String> stdClaimNames = new LinkedHashSet<>();
192        
193        
194        static {
195                stdClaimNames.add(SUB_CLAIM_NAME);
196                stdClaimNames.add(NAME_CLAIM_NAME);
197                stdClaimNames.add(GIVEN_NAME_CLAIM_NAME);
198                stdClaimNames.add(FAMILY_NAME_CLAIM_NAME);
199                stdClaimNames.add(MIDDLE_NAME_CLAIM_NAME);
200                stdClaimNames.add(NICKNAME_CLAIM_NAME);
201                stdClaimNames.add(PREFERRED_USERNAME_CLAIM_NAME);
202                stdClaimNames.add(PROFILE_CLAIM_NAME);
203                stdClaimNames.add(PICTURE_CLAIM_NAME);
204                stdClaimNames.add(WEBSITE_CLAIM_NAME);
205                stdClaimNames.add(EMAIL_CLAIM_NAME);
206                stdClaimNames.add(EMAIL_VERIFIED_CLAIM_NAME);
207                stdClaimNames.add(GENDER_CLAIM_NAME);
208                stdClaimNames.add(BIRTHDATE_CLAIM_NAME);
209                stdClaimNames.add(ZONEINFO_CLAIM_NAME);
210                stdClaimNames.add(LOCALE_CLAIM_NAME);
211                stdClaimNames.add(PHONE_NUMBER_CLAIM_NAME);
212                stdClaimNames.add(PHONE_NUMBER_VERIFIED_CLAIM_NAME);
213                stdClaimNames.add(ADDRESS_CLAIM_NAME);
214                stdClaimNames.add(UPDATED_AT_CLAIM_NAME);
215        }
216        
217        
218        /**
219         * Gets the names of the standard top-level UserInfo claims.
220         *
221         * @return The names of the standard top-level UserInfo claims 
222         *         (read-only set).
223         */
224        public static Set<String> getStandardClaimNames() {
225        
226                return Collections.unmodifiableSet(stdClaimNames);
227        }
228        
229        
230        /**
231         * Creates a new minimal UserInfo claims set.
232         *
233         * @param sub The subject. Must not be {@code null}.
234         */
235        public UserInfo(final Subject sub) {
236        
237                setClaim(SUB_CLAIM_NAME, sub.getValue());
238        }
239
240
241        /**
242         * Creates a new UserInfo claims set from the specified JSON object.
243         *
244         * @param jsonObject The JSON object. Must not be {@code null}.
245         *
246         * @throws IllegalArgumentException If the JSON object doesn't contain
247         *                                  a subject {@code sub} string claim.
248         */
249        public UserInfo(final JSONObject jsonObject) {
250
251                super(jsonObject);
252
253                if (getStringClaim(SUB_CLAIM_NAME) == null)
254                        throw new IllegalArgumentException("Missing or invalid \"sub\" claim");
255        }
256
257
258        /**
259         * Creates a new UserInfo claims set from the specified JSON Web Token
260         * (JWT) claims set.
261         *
262         * @param jwtClaimsSet The JWT claims set. Must not be {@code null}.
263         *
264         * @throws IllegalArgumentException If the JWT claims set doesn't
265         *                                  contain a subject {@code sub}
266         *                                  string claim.
267         */
268        public UserInfo(final JWTClaimsSet jwtClaimsSet) {
269
270                this(jwtClaimsSet.toJSONObject());
271        }
272
273
274        /**
275         * Puts all claims from the specified other UserInfo claims set.
276         *
277         * @param other The other UserInfo. Must have the same
278         *              {@link #getSubject subject}. Must not be {@code null}.
279         *
280         * @throws IllegalArgumentException If the other UserInfo claims set
281         *                                  doesn't have an identical subject.
282         */
283        public void putAll(final UserInfo other) {
284
285                Subject otherSubject = other.getSubject();
286
287                if (otherSubject == null)
288                        throw new IllegalArgumentException("The subject of the other UserInfo is missing");
289
290                if (! otherSubject.equals(getSubject()))
291                        throw new IllegalArgumentException("The subject of the other UserInfo must be identical");
292
293                putAll((ClaimsSet)other);
294        }
295        
296        
297        /**
298         * Gets the UserInfo subject. Corresponds to the {@code sub} claim.
299         *
300         * @return The subject.
301         */
302        public Subject getSubject() {
303        
304                return new Subject(getStringClaim(SUB_CLAIM_NAME));
305        }
306
307        
308        /**
309         * Gets the full name. Corresponds to the {@code name} claim, with no
310         * language tag.
311         *
312         * @return The full name, {@code null} if not specified.
313         */
314        public String getName() {
315        
316                return getStringClaim(NAME_CLAIM_NAME);
317        }
318        
319        
320        /**
321         * Gets the full name. Corresponds to the {@code name} claim, with an
322         * optional language tag.
323         *
324         * @param langTag The language tag of the entry, {@code null} to get 
325         *                the non-tagged entry.
326         *
327         * @return The full name, {@code null} if not specified.
328         */
329        public String getName(final LangTag langTag) {
330        
331                return getStringClaim(NAME_CLAIM_NAME, langTag);
332        }
333        
334        
335        /**
336         * Gets the full name entries. Correspond to the {@code name} claim.
337         *
338         * @return The full name entries, empty map if none.
339         */
340        public Map<LangTag,String> getNameEntries() {
341        
342                return getLangTaggedClaim(NAME_CLAIM_NAME, String.class);
343        }
344
345
346        /**
347         * Sets the full name. Corresponds to the {@code name} claim, with no
348         * language tag.
349         *
350         * @param name The full name. If {@code null} the claim will be 
351         *             removed.
352         */
353        public void setName(final String name) {
354        
355                setClaim(NAME_CLAIM_NAME, name);
356        }
357        
358        
359        /**
360         * Sets the full name. Corresponds to the {@code name} claim, with an
361         * optional language tag.
362         *
363         * @param name    The full name. If {@code null} the claim will be 
364         *                removed.
365         * @param langTag The language tag, {@code null} if not specified.
366         */
367        public void setName(final String name, final LangTag langTag) {
368        
369                setClaim(NAME_CLAIM_NAME, name, langTag);
370        }       
371        
372        
373        /**
374         * Gets the given or first name. Corresponds to the {@code given_name} 
375         * claim, with no language tag.
376         *
377         * @return The given or first name, {@code null} if not specified.
378         */
379        public String getGivenName() {
380        
381                return getStringClaim(GIVEN_NAME_CLAIM_NAME);
382        }
383        
384        
385        /**
386         * Gets the given or first name. Corresponds to the {@code given_name} 
387         * claim, with an optional language tag.
388         *
389         * @param langTag The language tag of the entry, {@code null} to get 
390         *                the non-tagged entry.
391         *
392         * @return The given or first name, {@code null} if not specified.
393         */
394        public String getGivenName(final LangTag langTag) {
395        
396                return getStringClaim(GIVEN_NAME_CLAIM_NAME, langTag);
397        }
398        
399        
400        /**
401         * Gets the given or first name entries. Correspond to the 
402         * {@code given_name} claim.
403         *
404         * @return The given or first name entries, empty map if none.
405         */
406        public Map<LangTag,String> getGivenNameEntries() {
407        
408                return getLangTaggedClaim(GIVEN_NAME_CLAIM_NAME, String.class);
409        }
410
411
412        /**
413         * Sets the given or first name. Corresponds to the {@code given_name} 
414         * claim, with no language tag.
415         *
416         * @param givenName The given or first name. If {@code null} the claim
417         *                  will be removed.
418         */
419        public void setGivenName(final String givenName) {
420        
421                setClaim(GIVEN_NAME_CLAIM_NAME, givenName);
422        }
423        
424        
425        /**
426         * Sets the given or first name. Corresponds to the {@code given_name}
427         * claim, with an optional language tag.
428         *
429         * @param givenName The given or first full name. If {@code null} the 
430         *                  claim will be removed.
431         * @param langTag   The language tag, {@code null} if not specified.
432         */
433        public void setGivenName(final String givenName, final LangTag langTag) {
434        
435                setClaim(GIVEN_NAME_CLAIM_NAME, givenName, langTag);
436        }
437
438        
439        /**
440         * Gets the surname or last name. Corresponds to the 
441         * {@code family_name} claim, with no language tag.
442         *
443         * @return The surname or last name, {@code null} if not specified.
444         */
445        public String getFamilyName() {
446        
447                return getStringClaim(FAMILY_NAME_CLAIM_NAME);
448        }
449        
450        
451        /**
452         * Gets the surname or last name. Corresponds to the 
453         * {@code family_name} claim, with an optional language tag.
454         *
455         * @param langTag The language tag of the entry, {@code null} to get 
456         *                the non-tagged entry.
457         *
458         * @return The surname or last name, {@code null} if not specified.
459         */
460        public String getFamilyName(final LangTag langTag) {
461        
462                return getStringClaim(FAMILY_NAME_CLAIM_NAME, langTag);
463        }
464        
465        
466        /**
467         * Gets the surname or last name entries. Correspond to the 
468         * @code family_name} claim.
469         *
470         * @return The surname or last name entries, empty map if none.
471         */
472        public Map<LangTag,String> getFamilyNameEntries() {
473        
474                return getLangTaggedClaim(FAMILY_NAME_CLAIM_NAME, String.class);
475        }
476
477
478        /**
479         * Sets the surname or last name. Corresponds to the 
480         * {@code family_name} claim, with no language tag.
481         *
482         * @param familyName The surname or last name. If {@code null} the 
483         *                   claim will be removed.
484         */
485        public void setFamilyName(final String familyName) {
486        
487                setClaim(FAMILY_NAME_CLAIM_NAME, familyName);
488        }
489        
490        
491        /**
492         * Sets the surname or last name. Corresponds to the 
493         * {@code family_name} claim, with an optional language tag.
494         *
495         * @param familyName The surname or last name. If {@code null} the 
496         *                   claim will be removed.
497         * @param langTag    The language tag, {@code null} if not specified.
498         */
499        public void setFamilyName(final String familyName, final LangTag langTag) {
500        
501                setClaim(FAMILY_NAME_CLAIM_NAME, familyName, langTag);
502        }
503
504        
505        /**
506         * Gets the middle name. Corresponds to the {@code middle_name} claim, 
507         * with no language tag.
508         *
509         * @return The middle name, {@code null} if not specified.
510         */
511        public String getMiddleName() {
512        
513                return getStringClaim(MIDDLE_NAME_CLAIM_NAME);
514        }
515        
516        
517        /**
518         * Gets the middle name. Corresponds to the {@code middle_name} claim,
519         * with an optional language tag.
520         *
521         * @param langTag The language tag of the entry, {@code null} to get 
522         *                the non-tagged entry.
523         *
524         * @return The middle name, {@code null} if not specified.
525         */
526        public String getMiddleName(final LangTag langTag) {
527        
528                return getStringClaim(MIDDLE_NAME_CLAIM_NAME, langTag);
529        }
530        
531        
532        /**
533         * Gets the middle name entries. Correspond to the {@code middle_name}
534         * claim.
535         *
536         * @return The middle name entries, empty map if none.
537         */
538        public Map<LangTag,String> getMiddleNameEntries() {
539        
540                return getLangTaggedClaim(MIDDLE_NAME_CLAIM_NAME, String.class);
541        }
542
543
544        /**
545         * Sets the middle name. Corresponds to the {@code middle_name} claim,
546         * with no language tag.
547         *
548         * @param middleName The middle name. If {@code null} the claim will be
549         *                   removed.
550         */
551        public void setMiddleName(final String middleName) {
552        
553                setClaim(MIDDLE_NAME_CLAIM_NAME, middleName);
554        }
555        
556        
557        /**
558         * Sets the middle name. Corresponds to the {@code middle_name} claim, 
559         * with an optional language tag.
560         *
561         * @param middleName The middle name. If {@code null} the claim will be
562         *                   removed.
563         * @param langTag    The language tag, {@code null} if not specified.
564         */
565        public void setMiddleName(final String middleName, final LangTag langTag) {
566        
567                setClaim(MIDDLE_NAME_CLAIM_NAME, middleName, langTag);
568        }
569        
570        
571        /**
572         * Gets the casual name. Corresponds to the {@code nickname} claim, 
573         * with no language tag.
574         *
575         * @return The casual name, {@code null} if not specified.
576         */
577        public String getNickname() {
578        
579                return getStringClaim(NICKNAME_CLAIM_NAME);
580        }
581        
582        
583        /**
584         * Gets the casual name. Corresponds to the {@code nickname} claim, 
585         * with an optional language tag.
586         *
587         * @param langTag The language tag of the entry, {@code null} to get 
588         *                the non-tagged entry.
589         *
590         * @return The casual name, {@code null} if not specified.
591         */
592        public String getNickname(final LangTag langTag) {
593        
594                return getStringClaim(NICKNAME_CLAIM_NAME, langTag);
595        }
596        
597        
598        /**
599         * Gets the casual name entries. Correspond to the {@code nickname} 
600         * claim.
601         *
602         * @return The casual name entries, empty map if none.
603         */
604        public Map<LangTag,String> getNicknameEntries() {
605        
606                return getLangTaggedClaim(NICKNAME_CLAIM_NAME, String.class);
607        }
608
609
610        /**
611         * Sets the casual name. Corresponds to the {@code nickname} claim, 
612         * with no language tag.
613         *
614         * @param nickname The casual name. If {@code null} the claim will be
615         *                 removed.
616         */
617        public void setNickname(final String nickname) {
618        
619                setClaim(NICKNAME_CLAIM_NAME, nickname);
620        }
621        
622        
623        /**
624         * Sets the casual name. Corresponds to the {@code nickname} claim, 
625         * with an optional language tag.
626         *
627         * @param nickname The casual name. If {@code null} the claim will be
628         *                 removed.
629         * @param langTag  The language tag, {@code null} if not specified.
630         */
631        public void setNickname(final String nickname, final LangTag langTag) {
632        
633                setClaim(NICKNAME_CLAIM_NAME, nickname, langTag);
634        }
635        
636        
637        /**
638         * Gets the preferred username. Corresponds to the 
639         * {@code preferred_username} claim.
640         *
641         * @return The preferred username, {@code null} if not specified.
642         */
643        public String getPreferredUsername() {
644        
645                return getStringClaim(PREFERRED_USERNAME_CLAIM_NAME);
646        }
647        
648        
649        /**
650         * Sets the preferred username. Corresponds to the 
651         * {@code preferred_username} claim.
652         *
653         * @param preferredUsername The preferred username. If {@code null} the
654         *                          claim will be removed.
655         */
656        public void setPreferredUsername(final String preferredUsername) {
657        
658                setClaim(PREFERRED_USERNAME_CLAIM_NAME, preferredUsername);
659        }
660        
661        
662        /**
663         * Gets the profile page. Corresponds to the {@code profile} claim.
664         *
665         * @return The profile page URI, {@code null} if not specified.
666         */
667        public URI getProfile() {
668        
669                return getURIClaim(PROFILE_CLAIM_NAME);
670        }
671        
672        
673        /**
674         * Sets the profile page. Corresponds to the {@code profile} claim.
675         *
676         * @param profile The profile page URI. If {@code null} the claim will
677         *                be removed.
678         */
679        public void setProfile(final URI profile) {
680        
681                setURIClaim(PROFILE_CLAIM_NAME, profile);
682        }
683        
684        
685        /**
686         * Gets the picture. Corresponds to the {@code picture} claim.
687         *
688         * @return The picture URI, {@code null} if not specified.
689         */
690        public URI getPicture() {
691        
692                return getURIClaim(PICTURE_CLAIM_NAME);
693        }
694        
695        
696        /**
697         * Sets the picture. Corresponds to the {@code picture} claim.
698         *
699         * @param picture The picture URI. If {@code null} the claim will be
700         *                removed.
701         */
702        public void setPicture(final URI picture) {
703        
704                setURIClaim(PICTURE_CLAIM_NAME, picture);
705        }
706        
707        
708        /**
709         * Gets the web page or blog. Corresponds to the {@code website} claim.
710         *
711         * @return The web page or blog URI, {@code null} if not specified.
712         */
713        public URI getWebsite() {
714        
715                return getURIClaim(WEBSITE_CLAIM_NAME);
716        }
717        
718        
719        /**
720         * Sets the web page or blog. Corresponds to the {@code website} claim.
721         *
722         * @param website The web page or blog URI. If {@code null} the claim
723         *                will be removed.
724         */
725        public void setWebsite(final URI website) {
726        
727                setURIClaim(WEBSITE_CLAIM_NAME, website);
728        }
729        
730        
731        /**
732         * Gets the preferred email address. Corresponds to the {@code email}
733         * claim.
734         *
735         * <p>Use {@link #getEmailAddress()} instead.
736         *
737         * @return The preferred email address, {@code null} if not specified.
738         */
739        @Deprecated
740        public InternetAddress getEmail() {
741        
742                return getEmailClaim(EMAIL_CLAIM_NAME);
743        }
744        
745        
746        /**
747         * Sets the preferred email address. Corresponds to the {@code email}
748         * claim.
749         *
750         * <p>Use {@link #setEmailAddress(String)} instead.
751         *
752         * @param email The preferred email address. If {@code null} the claim
753         *              will be removed.
754         */
755        @Deprecated
756        public void setEmail(final InternetAddress email) {
757        
758                setEmailClaim(EMAIL_CLAIM_NAME, email);
759        }
760        
761        
762        /**
763         * Gets the preferred email address. Corresponds to the {@code email}
764         * claim.
765         *
766         * @return The preferred email address, {@code null} if not specified.
767         */
768        public String getEmailAddress() {
769        
770                return getStringClaim(EMAIL_CLAIM_NAME);
771        }
772        
773        
774        /**
775         * Sets the preferred email address. Corresponds to the {@code email}
776         * claim.
777         *
778         * @param email The preferred email address. If {@code null} the claim
779         *              will be removed.
780         */
781        public void setEmailAddress(final String email) {
782        
783                setClaim(EMAIL_CLAIM_NAME, email);
784        }
785        
786        
787        /**
788         * Gets the email verification status. Corresponds to the 
789         * {@code email_verified} claim.
790         *
791         * @return The email verification status, {@code null} if not 
792         *         specified.
793         */
794        public Boolean getEmailVerified() {
795        
796                return getBooleanClaim(EMAIL_VERIFIED_CLAIM_NAME);
797        }
798        
799        
800        /**
801         * Sets the email verification status. Corresponds to the
802         * {@code email_verified} claim.
803         *
804         * @param emailVerified The email verification status. If {@code null} 
805         *                      the claim will be removed.
806         */
807        public void setEmailVerified(final Boolean emailVerified) {
808        
809                setClaim(EMAIL_VERIFIED_CLAIM_NAME, emailVerified);
810        }
811        
812        
813        /**
814         * Gets the gender. Corresponds to the {@code gender} claim.
815         *
816         * @return The gender, {@code null} if not specified.
817         */
818        public Gender getGender() {
819        
820                String value = getStringClaim(GENDER_CLAIM_NAME);
821                
822                if (value == null)
823                        return null;
824
825                return new Gender(value);
826        }
827        
828        
829        /**
830         * Sets the gender. Corresponds to the {@code gender} claim.
831         *
832         * @param gender The gender. If {@code null} the claim will be removed.
833         */
834        public void setGender(final Gender gender) {
835        
836                if (gender != null)
837                        setClaim(GENDER_CLAIM_NAME, gender.getValue());
838                else
839                        setClaim(GENDER_CLAIM_NAME, null);
840        }
841        
842        
843        /**
844         * Gets the date of birth. Corresponds to the {@code birthdate} claim.
845         *
846         * @return The date of birth, {@code null} if not specified.
847         */
848        public String getBirthdate() {
849        
850                return getStringClaim(BIRTHDATE_CLAIM_NAME);
851        }
852        
853        
854        /**
855         * Sets the date of birth. Corresponds to the {@code birthdate} claim.
856         *
857         * @param birthdate The date of birth. If {@code null} the claim will
858         *                  be removed.
859         */
860        public void setBirthdate(final String birthdate) {
861        
862                setClaim(BIRTHDATE_CLAIM_NAME, birthdate);
863        }
864        
865        
866        /**
867         * Gets the zoneinfo. Corresponds to the {@code zoneinfo} claim.
868         *
869         * @return The zoneinfo, {@code null} if not specified.
870         */
871        public String getZoneinfo() {
872        
873                return getStringClaim(ZONEINFO_CLAIM_NAME);
874        }
875        
876        
877        /**
878         * Sets the zoneinfo. Corresponds to the {@code zoneinfo} claim.
879         *
880         * @param zoneinfo The zoneinfo. If {@code null} the claim will be 
881         *                 removed.
882         */
883        public void setZoneinfo(final String zoneinfo) {
884        
885                setClaim(ZONEINFO_CLAIM_NAME, zoneinfo);
886        }
887        
888        
889        /**
890         * Gets the locale. Corresponds to the {@code locale} claim.
891         *
892         * @return The locale, {@code null} if not specified.
893         */
894        public String getLocale() {
895        
896                return getStringClaim(LOCALE_CLAIM_NAME);
897        }
898        
899        
900        /**
901         * Sets the locale. Corresponds to the {@code locale} claim.
902         *
903         * @param locale The locale. If {@code null} the claim will be 
904         *               removed.
905         */
906        public void setLocale(final String locale) {
907        
908                setClaim(LOCALE_CLAIM_NAME, locale);
909        }
910        
911        
912        /**
913         * Gets the preferred telephone number. Corresponds to the 
914         * {@code phone_number} claim.
915         *
916         * @return The preferred telephone number, {@code null} if not 
917         *         specified.
918         */
919        public String getPhoneNumber() {
920        
921                return getStringClaim(PHONE_NUMBER_CLAIM_NAME);
922        }
923        
924        
925        /**
926         * Sets the preferred telephone number. Corresponds to the 
927         * {@code phone_number} claim.
928         *
929         * @param phoneNumber The preferred telephone number. If {@code null} 
930         *                    the claim will be removed.
931         */
932        public void setPhoneNumber(final String phoneNumber) {
933        
934                setClaim(PHONE_NUMBER_CLAIM_NAME, phoneNumber);
935        }
936        
937        
938        /**
939         * Gets the phone number verification status. Corresponds to the 
940         * {@code phone_number_verified} claim.
941         *
942         * @return The phone number verification status, {@code null} if not 
943         *         specified.
944         */
945        public Boolean getPhoneNumberVerified() {
946        
947                return getBooleanClaim(PHONE_NUMBER_VERIFIED_CLAIM_NAME);
948        }
949        
950        
951        /**
952         * Sets the email verification status. Corresponds to the
953         * {@code phone_number_verified} claim.
954         *
955         * @param phoneNumberVerified The phone number verification status. If 
956         *                            {@code null} the claim will be removed.
957         */
958        public void setPhoneNumberVerified(final Boolean phoneNumberVerified) {
959        
960                setClaim(PHONE_NUMBER_VERIFIED_CLAIM_NAME, phoneNumberVerified);
961        }
962
963
964        /**
965         * Gets the preferred address. Corresponds to the {@code address} 
966         * claim, with no language tag.
967         *
968         * @return The preferred address, {@code null} if not specified.
969         */
970        public Address getAddress() {
971        
972                return getAddress(null);
973        }
974        
975        
976        /**
977         * Gets the preferred address. Corresponds to the {@code address} 
978         * claim, with an optional language tag.
979         *
980         * @param langTag The language tag of the entry, {@code null} to get 
981         *                the non-tagged entry.
982         *
983         * @return The preferred address, {@code null} if not specified.
984         */
985        public Address getAddress(final LangTag langTag) {
986        
987                String name;
988
989                if (langTag!= null)
990                        name = ADDRESS_CLAIM_NAME + "#" + langTag;
991                else
992                        name = ADDRESS_CLAIM_NAME;
993
994                JSONObject jsonObject = getClaim(name, JSONObject.class);
995
996                if (jsonObject == null)
997                        return null;
998
999                return new Address(jsonObject);
1000        }
1001        
1002        
1003        /**
1004         * Gets the preferred address entries. Correspond to the 
1005         * {@code address} claim.
1006         *
1007         * @return The preferred address entries, empty map if none.
1008         */
1009        public Map<LangTag,Address> getAddressEntries() {
1010        
1011                Map<LangTag,JSONObject> entriesIn = getLangTaggedClaim(ADDRESS_CLAIM_NAME, JSONObject.class);
1012
1013                Map<LangTag,Address> entriesOut = new HashMap<>();
1014
1015                for (Map.Entry<LangTag,JSONObject> en: entriesIn.entrySet())
1016                        entriesOut.put(en.getKey(), new Address(en.getValue()));
1017
1018                return entriesOut;
1019        }
1020
1021
1022        /**
1023         * Sets the preferred address. Corresponds to the {@code address} 
1024         * claim, with no language tag.
1025         *
1026         * @param address The preferred address. If {@code null} the claim will
1027         *                be removed.
1028         */
1029        public void setAddress(final Address address) {
1030        
1031                if (address != null)
1032                        setClaim(ADDRESS_CLAIM_NAME, address.toJSONObject());
1033                else
1034                        setClaim(ADDRESS_CLAIM_NAME, null);
1035        }
1036        
1037        
1038        /**
1039         * Sets the preferred address. Corresponds to the {@code address}
1040         * claim, with an optional language tag.
1041         *
1042         * @param address  The preferred address. If {@code null} the claim 
1043         *                 will be removed.
1044         * @param langTag The language tag, {@code null} if not specified.
1045         */
1046        public void setAddress(final Address address, final LangTag langTag) {
1047
1048                String key = langTag == null ? ADDRESS_CLAIM_NAME : ADDRESS_CLAIM_NAME + "#" + langTag;
1049
1050                if (address != null)
1051                        setClaim(key, address.toJSONObject());
1052                else
1053                        setClaim(key, null);
1054        }
1055        
1056        
1057        /**
1058         * Gets the time the end-user information was last updated. Corresponds 
1059         * to the {@code updated_at} claim.
1060         *
1061         * @return The time the end-user information was last updated, 
1062         *         {@code null} if not specified.
1063         */
1064        public Date getUpdatedTime() {
1065        
1066                return getDateClaim(UPDATED_AT_CLAIM_NAME);
1067        }
1068        
1069        
1070        /**
1071         * Sets the time the end-user information was last updated. Corresponds
1072         * to the {@code updated_at} claim.
1073         *
1074         * @param updatedTime The time the end-user information was last 
1075         *                    updated. If {@code null} the claim will be 
1076         *                    removed.
1077         */
1078        public void setUpdatedTime(final Date updatedTime) {
1079        
1080                setDateClaim(UPDATED_AT_CLAIM_NAME, updatedTime);
1081        }
1082
1083
1084        /**
1085         * Parses a UserInfo claims set from the specified JSON object string.
1086         *
1087         * @param json The JSON object string to parse. Must not be
1088         *             {@code null}.
1089         *
1090         * @return The UserInfo claims set.
1091         *
1092         * @throws ParseException If parsing failed.
1093         */
1094        public static UserInfo parse(final String json)
1095                throws ParseException {
1096
1097                JSONObject jsonObject = JSONObjectUtils.parse(json);
1098
1099                try {
1100                        return new UserInfo(jsonObject);
1101
1102                } catch (IllegalArgumentException e) {
1103
1104                        throw new ParseException(e.getMessage(), e);
1105                }
1106        }
1107}