001package com.nimbusds.oauth2.sdk.client;
002
003
004import java.net.MalformedURLException;
005import java.net.URL;
006import java.util.HashMap;
007import java.util.HashSet;
008import java.util.LinkedHashSet;
009import java.util.LinkedList;
010import java.util.List;
011import java.util.Map;
012import java.util.Set;
013
014import javax.mail.internet.AddressException;
015import javax.mail.internet.InternetAddress;
016
017import net.minidev.json.JSONArray;
018import net.minidev.json.JSONObject;
019
020import com.nimbusds.langtag.LangTag;
021import com.nimbusds.langtag.LangTagUtil;
022
023import com.nimbusds.oauth2.sdk.GrantType;
024import com.nimbusds.oauth2.sdk.ParseException;
025import com.nimbusds.oauth2.sdk.ResponseType;
026import com.nimbusds.oauth2.sdk.Scope;
027import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod;
028import com.nimbusds.oauth2.sdk.util.JSONObjectUtils;
029
030
031/**
032 * Client metadata.
033 * 
034 * <p>Example client metadata, serialised to a JSON object:
035 * 
036 * <pre>
037 * {
038 *  "redirect_uris"             : ["https://client.example.org/callback",
039 *                                 "https://client.example.org/callback2"],
040 *  "client_name"                : "My Example Client",
041 *  "client_name#ja-Jpan-JP"     : "\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8\u540D",
042 *  "token_endpoint_auth_method" : "client_secret_basic",
043 *  "scope"                      : "read write dolphin",
044 *  "logo_uri"                   : "https://client.example.org/logo.png",
045 *  "jwks_uri"                   : "https://client.example.org/my_public_keys.jwks"
046 * }
047 * </pre>
048 * 
049 * <p>Related specifications:
050 *
051 * <ul>
052 *     <li>OAuth 2.0 Dynamic Client Registration Protocol 
053 *         (draft-ietf-oauth-dyn-reg-12), section 2.
054 * </ul>
055 * 
056 * @author Vladimir Dzhuvinov
057 */
058public class ClientMetadata {
059        
060        
061        /**
062         * Redirect URIs.
063         */
064        private Set<URL> redirectURIs;
065        
066        
067        /**
068         * The client OAuth 2.0 scope.
069         */
070        private Scope scope;
071        
072        
073        /**
074         * The expected OAuth 2.0 response types.
075         */
076        private Set<ResponseType> responseTypes;
077        
078        
079        /**
080         * The expected OAuth 2.0 grant types.
081         */
082        private Set<GrantType> grantTypes;
083        
084        
085        /**
086         * Administrator contacts for the client.
087         */
088        private List<InternetAddress> contacts;
089
090
091        /**
092         * The client name.
093         */
094        private Map<LangTag,String> nameEntries;
095
096
097        /**
098         * The client application logo.
099         */
100        private Map<LangTag,URL> logoURIEntries;
101        
102        
103        /**
104         * The client URI entries.
105         */
106        private Map<LangTag,URL> uriEntries;
107
108
109        /**
110         * The client policy for use of end-user data.
111         */
112        private Map<LangTag,URL> policyURIEntries;
113
114
115        /**
116         * The client terms of service.
117         */
118        private Map<LangTag,URL> tosURIEntries;
119        
120        
121        /**
122         * Token endpoint authentication method.
123         */
124        private ClientAuthenticationMethod authMethod;
125        
126        
127        /**
128         * URI for this client's JSON Web Key (JWK) set containing key(s) that
129         * are used in signing requests to the server and key(s) for encrypting
130         * responses.
131         */
132        private URL jwkSetURI;
133        
134        
135        /** 
136         * Creates a new OAuth 2.0 client metadata instance.
137         */
138        public ClientMetadata() {
139
140                nameEntries = new HashMap<LangTag,String>();
141                logoURIEntries = new HashMap<LangTag,URL>();
142                uriEntries = new HashMap<LangTag,URL>();
143                policyURIEntries = new HashMap<LangTag,URL>();
144                policyURIEntries = new HashMap<LangTag,URL>();
145                tosURIEntries = new HashMap<LangTag,URL>();
146        }
147        
148        
149        /**
150         * Creates a shallow copy of the specified OAuth 2.0 client metadata
151         * instance.
152         * 
153         * @param metadata The client metadata to copy. Must not be 
154         *                 {@code null}.
155         */
156        public ClientMetadata(final ClientMetadata metadata) {
157                
158                redirectURIs = metadata.redirectURIs;
159                scope = metadata.scope;
160                responseTypes = metadata.responseTypes;
161                grantTypes = metadata.grantTypes;
162                contacts = metadata.contacts;
163                nameEntries = metadata.nameEntries;
164                logoURIEntries = metadata.logoURIEntries;
165                uriEntries = metadata.uriEntries;
166                policyURIEntries = metadata.policyURIEntries;
167                tosURIEntries = metadata.tosURIEntries;
168                authMethod = metadata.authMethod;
169                jwkSetURI = metadata.jwkSetURI;
170        }
171        
172        
173        /**
174         * Gets the redirect URIs for this client. Corresponds to the
175         * {@code redirect_uris} client metadata field.
176         *
177         * @return The redirect URIs, {@code null} if not specified.
178         */
179        public Set<URL> getRedirectURIs() {
180        
181                return redirectURIs;
182        }
183        
184        
185        /**
186         * Sets the redirect URIs for this client. Corresponds to the
187         * {@code redirect_uris} client metadata field.
188         *
189         * @param redirectURIs The redirect URIs, {@code null} if not 
190         *                     specified.
191         */
192        public void setRedirectURIs(final Set<URL> redirectURIs) {
193        
194                this.redirectURIs = redirectURIs;
195        }
196        
197        
198        /**
199         * Gets the scope values that the client can use when requesting access 
200         * tokens. Corresponds to the {@code scope} client metadata field.
201         * 
202         * @return The scope, {@code null} if not specified.
203         */
204        public Scope getScope() {
205                
206                return scope;
207        }
208        
209        
210        /**
211         * Sets the scope values that the client can use when requesting access 
212         * tokens. Corresponds to the {@code scope} client metadata field.
213         * 
214         * @param scope The scope, {@code null} if not specified.
215         */
216        public void setScope(final Scope scope) {
217                
218                this.scope = scope;
219        }
220        
221        
222        /**
223         * Gets the expected OAuth 2.0 response types. Corresponds to the
224         * {@code response_types} client metadata field.
225         * 
226         * @return The response types, {@code null} if not specified.
227         */
228        public Set<ResponseType> getResponseTypes() {
229                
230                return responseTypes;
231        }
232        
233        
234        /**
235         * Sets the expected OAuth 2.0 response types. Corresponds to the
236         * {@code response_types} client metadata field.
237         * 
238         * @param responseTypes The response types, {@code null} if not 
239         *                      specified.
240         */
241        public void setResponseTypes(final Set<ResponseType> responseTypes) {
242                
243                this.responseTypes = responseTypes;
244        }
245        
246        
247        /**
248         * Gets the expected OAuth 2.0 grant types. Corresponds to the
249         * {@code grant_types} client metadata field.
250         * 
251         * @return The grant types, {@code null} if not specified.
252         */
253        public Set<GrantType> getGrantTypes() {
254                
255                return grantTypes;
256        }
257        
258        
259        /**
260         * Sets the expected OAuth 2.0 grant types. Corresponds to the
261         * {@code grant_types} client metadata field.
262         * 
263         * @param grantTypes The grant types, {@code null} if not specified.
264         */
265        public void setGrantTypes(final Set<GrantType> grantTypes) {
266                
267                this.grantTypes = grantTypes;
268        }
269        
270        
271        /**
272         * Gets the administrator contacts for the client. Corresponds to the
273         * {@code contacts} client metadata field.
274         *
275         * @return The administrator contacts, {@code null} if not specified.
276         */
277        public List<InternetAddress> getContacts() {
278
279                return contacts;
280        }
281
282
283        /**
284         * Sets the administrator contacts for the client. Corresponds to the
285         * {@code contacts} client metadata field.
286         *
287         * @param contacts The administrator contacts, {@code null} if not
288         *                 specified.
289         */
290        public void setContacts(final List<InternetAddress> contacts) {
291
292                this.contacts = contacts;
293        }
294        
295        
296        /**
297         * Gets the client name. Corresponds to the {@code client_name} client 
298         * metadata field, with no language tag.
299         *
300         * @return The client name, {@code null} if not specified.
301         */
302        public String getName() {
303
304                return getName(null);
305        }
306
307
308        /**
309         * Gets the client name. Corresponds to the {@code client_name} client
310         * metadata field, with an optional language tag.
311         *
312         * @param langTag The language tag of the entry, {@code null} to get 
313         *                the non-tagged entry.
314         *
315         * @return The client name, {@code null} if not specified.
316         */
317        public String getName(final LangTag langTag) {
318
319                return nameEntries.get(langTag);
320        }
321
322
323        /**
324         * Gets the client name entries. Corresponds to the {@code client_name}
325         * client metadata field.
326         *
327         * @return The client name entries, empty map if none.
328         */
329        public Map<LangTag,String> getNameEntries() {
330
331                return nameEntries;
332        }
333
334
335        /**
336         * Sets the client name. Corresponds to the {@code client_name} client
337         * metadata field, with no language tag.
338         *
339         * @param name The client name, {@code null} if not specified.
340         */
341        public void setName(final String name) {
342
343                nameEntries.put(null, name);
344        }
345
346
347        /**
348         * Sets the client name. Corresponds to the {@code client_name} client
349         * metadata field, with an optional language tag.
350         *
351         * @param name    The client name. Must not be {@code null}.
352         * @param langTag The language tag, {@code null} if not specified.
353         */
354        public void setName(final String name, final LangTag langTag) {
355
356                nameEntries.put(langTag, name);
357        }
358
359
360        /**
361         * Gets the client application logo. Corresponds to the 
362         * {@code logo_uri} client metadata field, with no language 
363         * tag.
364         *
365         * @return The logo URI, {@code null} if not specified.
366         */
367        public URL getLogoURI() {
368
369                return getLogoURI(null);
370        }
371
372
373        /**
374         * Gets the client application logo. Corresponds to the 
375         * {@code logo_uri} client metadata field, with an optional
376         * language tag.
377         *
378         * @return The logo URI, {@code null} if not specified.
379         */
380        public URL getLogoURI(final LangTag langTag) {
381
382                return logoURIEntries.get(langTag);
383        }
384
385
386        /**
387         * Gets the client application logo entries. Corresponds to the 
388         * {@code logo_uri} client metadata field.
389         *
390         * @return The logo URI entries, empty map if none.
391         */
392        public Map<LangTag,URL> getLogoURIEntries() {
393
394                return logoURIEntries;
395        }
396
397
398        /**
399         * Sets the client application logo. Corresponds to the 
400         * {@code logo_uri} client metadata field, with no language 
401         * tag.
402         *
403         * @param logoURI The logo URI, {@code null} if not specified.
404         */
405        public void setLogoURI(final URL logoURI) {
406
407                logoURIEntries.put(null, logoURI);
408        }
409
410
411        /**
412         * Sets the client application logo. Corresponds to the 
413         * {@code logo_uri} client metadata field, with an optional
414         * language tag.
415         *
416         * @param logoURI The logo URI. Must not be {@code null}.
417         * @param langTag The language tag, {@code null} if not specified.
418         */
419        public void setLogoURI(final URL logoURI, final LangTag langTag) {
420
421                logoURIEntries.put(langTag, logoURI);
422        }
423        
424        
425        /**
426         * Gets the client home page. Corresponds to the {@code client_uri} 
427         * client metadata field, with no language tag.
428         *
429         * @return The client URI, {@code null} if not specified.
430         */
431        public URL getURI() {
432
433                return getURI(null);
434        }
435
436
437        /**
438         * Gets the client home page. Corresponds to the {@code client_uri} 
439         * client metadata field, with an optional language tag.
440         *
441         * @return The client URI, {@code null} if not specified.
442         */
443        public URL getURI(final LangTag langTag) {
444
445                return uriEntries.get(langTag);
446        }
447
448
449        /**
450         * Gets the client home page entries. Corresponds to the 
451         * {@code client_uri} client metadata field.
452         *
453         * @return The client URI entries, empty map if none.
454         */
455        public Map<LangTag,URL> getURIEntries() {
456
457                return uriEntries;
458        }
459
460
461        /**
462         * Sets the client home page. Corresponds to the {@code client_uri} 
463         * client metadata field, with no language tag.
464         *
465         * @param uri The client URI, {@code null} if not specified.
466         */
467        public void setURI(final URL uri) {
468
469                uriEntries.put(null, uri);
470        }
471
472
473        /**
474         * Sets the client home page. Corresponds to the {@code client_uri} 
475         * client metadata field, with an optional language tag.
476         *
477         * @param uri     The URI. Must not be {@code null}.
478         * @param langTag The language tag, {@code null} if not specified.
479         */
480        public void setURI(final URL uri, final LangTag langTag) {
481
482                uriEntries.put(langTag, uri);
483        }
484        
485
486        /**
487         * Gets the client policy for use of end-user data. Corresponds to the 
488         * {@code policy_uri} client metadata field, with no language 
489         * tag.
490         *
491         * @return The policy URI, {@code null} if not specified.
492         */
493        public URL getPolicyURI() {
494
495                return getPolicyURI(null);
496        }
497
498
499        /**
500         * Gets the client policy for use of end-user data. Corresponds to the 
501         * {@code policy_url} client metadata field, with an optional
502         * language tag.
503         *
504         * @return The policy URI, {@code null} if not specified.
505         */
506        public URL getPolicyURI(final LangTag langTag) {
507
508                return policyURIEntries.get(langTag);
509        }
510
511
512        /**
513         * Gets the client policy entries for use of end-user data. 
514         * Corresponds to the {@code policy_uri} client metadata field.
515         *
516         * @return The policy URI entries, empty map if none.
517         */
518        public Map<LangTag,URL> getPolicyURIEntries() {
519
520                return policyURIEntries;
521        }
522
523
524        /**
525         * Sets the client policy for use of end-user data. Corresponds to the 
526         * {@code policy_uri} client metadata field, with no language 
527         * tag.
528         *
529         * @param policyURI The policy URI, {@code null} if not specified.
530         */
531        public void setPolicyURI(final URL policyURI) {
532
533                policyURIEntries.put(null, policyURI);
534        }
535
536
537        /**
538         * Sets the client policy for use of end-user data. Corresponds to the 
539         * {@code policy_uri} client metadata field, with an optional
540         * language tag.
541         *
542         * @param policyURI The policy URI. Must not be {@code null}.
543         * @param langTag   The language tag, {@code null} if not specified.
544         */
545        public void setPolicyURI(final URL policyURI, final LangTag langTag) {
546
547                policyURIEntries.put(langTag, policyURI);
548        }
549
550
551        /**
552         * Gets the client's terms of service. Corresponds to the 
553         * {@code tos_uri} client metadata field, with no language 
554         * tag.
555         *
556         * @return The terms of service URI, {@code null} if not specified.
557         */
558        public URL getTermsOfServiceURI() {
559
560                return getTermsOfServiceURI(null);
561        }
562
563
564        /**
565         * Gets the client's terms of service. Corresponds to the 
566         * {@code tos_uri} client metadata field, with an optional
567         * language tag.
568         *
569         * @return The terms of service URI, {@code null} if not specified.
570         */
571        public URL getTermsOfServiceURI(final LangTag langTag) {
572
573                return tosURIEntries.get(langTag);
574        }
575
576
577        /**
578         * Gets the client's terms of service entries. Corresponds to the 
579         * {@code tos_uri} client metadata field.
580         *
581         * @return The terms of service URI entries, empty map if none.
582         */
583        public Map<LangTag,URL> getTermsOfServiceURIEntries() {
584
585                return tosURIEntries;
586        }
587
588
589        /**
590         * Sets the client's terms of service. Corresponds to the 
591         * {@code tos_uri} client metadata field, with no language 
592         * tag.
593         *
594         * @param tosURI The terms of service URI, {@code null} if not 
595         *               specified.
596         */
597        public void setTermsOfServiceURI(final URL tosURI) {
598
599                tosURIEntries.put(null, tosURI);
600        }
601
602
603        /**
604         * Sets the client's terms of service. Corresponds to the 
605         * {@code tos_uri} client metadata field, with an optional
606         * language tag.
607         *
608         * @param tosURI  The terms of service URI. Must not be {@code null}.
609         * @param langTag The language tag, {@code null} if not specified.
610         */
611        public void setTermsOfServiceURI(final URL tosURI, final LangTag langTag) {
612
613                tosURIEntries.put(langTag, tosURI);
614        }
615        
616        
617        /**
618         * Gets the Token endpoint authentication method. Corresponds to the 
619         * {@code token_endpoint_auth_method} client metadata field.
620         *
621         * @return The Token endpoint authentication method, {@code null} if
622         *         not specified.
623         */
624        public ClientAuthenticationMethod getTokenEndpointAuthMethod() {
625
626                return authMethod;
627        }
628
629
630        /**
631         * Sets the Token endpoint authentication method. Corresponds to the 
632         * {@code token_endpoint_auth_method} client metadata field.
633         *
634         * @param authMethod The Token endpoint authentication  method, 
635         *                   {@code null} if not specified.
636         */
637        public void setTokenEndpointAuthMethod(final ClientAuthenticationMethod authMethod) {
638
639                this.authMethod = authMethod;
640        }
641        
642        
643        /**
644         * Gets the URI for this client's JSON Web Key (JWK) set containing 
645         * key(s) that are used in signing requests to the server and key(s) 
646         * for encrypting responses. Corresponds to the {@code jwks_uri} client 
647         * metadata field.
648         *
649         * @return The JWK set URI, {@code null} if not specified.
650         */
651        public URL getJWKSetURI() {
652
653                return jwkSetURI;
654        }
655
656
657        /**
658         * Sets the URI for this client's JSON Web Key (JWK) set containing 
659         * key(s) that are used in signing requests to the server and key(s) 
660         * for encrypting responses. Corresponds to the {@code jwks_uri} client 
661         * metadata field.
662         *
663         * @param jwkSetURI The JWK set URI, {@code null} if not specified.
664         */
665        public void setJWKSetURL(final URL jwkSetURI) {
666
667                this.jwkSetURI = jwkSetURI;
668        }
669        
670        
671        /**
672         * Applies the client metadata defaults where no values have been
673         * specified.
674         * 
675         * <ul>
676         *     <li>The response types default to {@code ["code"]}.
677         *     <li>The grant types default to {@code "authorization_code".}
678         *     <li>The client authentication method defaults to 
679         *         "client_secret_basic".
680         * </ul>
681         */
682        public void applyDefaults() {
683                
684                if (responseTypes == null) {
685                        responseTypes = new HashSet<ResponseType>();
686                        responseTypes.add(ResponseType.getDefault());
687                }
688                
689                if (grantTypes == null) {
690                        grantTypes = new HashSet<GrantType>();
691                        grantTypes.add(GrantType.AUTHORIZATION_CODE);
692                }
693                
694                if (authMethod == null) {
695                        authMethod = ClientAuthenticationMethod.getDefault();
696                }
697        }
698        
699        
700        /**
701         * Returns the JSON object representation of this client metadata.
702         *
703         * @return The JSON object.
704         */
705        public JSONObject toJSONObject() {
706
707                JSONObject o = new JSONObject();
708
709                if (redirectURIs != null) {
710
711                        JSONArray uriList = new JSONArray();
712
713                        for (URL uri: redirectURIs)
714                                uriList.add(uri.toString());
715
716                        o.put("redirect_uris", uriList);
717                }
718                
719                
720                if (scope != null)
721                        o.put("scope", scope.toString());
722                
723                
724                if (responseTypes != null) {
725                        
726                        JSONArray rtList = new JSONArray();
727                        
728                        for (ResponseType rt: responseTypes)
729                                rtList.add(rt.toString());
730                        
731                        o.put("response_types", rtList);
732                }
733                
734                
735                if (grantTypes != null) {
736                        
737                        JSONArray grantList = new JSONArray();
738                        
739                        for (GrantType grant: grantTypes)
740                                grantList.add(grant.toString());
741                        
742                        o.put("grant_types", grantList);
743                }
744
745
746                if (contacts != null) {
747
748                        JSONArray contactList = new JSONArray();
749
750                        for (InternetAddress email: contacts)
751                                contactList.add(email.toString());
752
753                        o.put("contacts", contactList);
754                }
755
756
757                if (! nameEntries.isEmpty()) {
758
759                        for (Map.Entry<LangTag,String> entry: nameEntries.entrySet()) {
760
761                                LangTag langTag = entry.getKey();
762                                String name = entry.getValue();
763                                
764                                if (name == null)
765                                        continue;
766
767                                if (langTag == null)
768                                        o.put("client_name", entry.getValue());
769                                else
770                                        o.put("client_name#" + langTag, entry.getValue());
771                        } 
772                }
773                
774                
775                if (! logoURIEntries.isEmpty()) {
776
777                        for (Map.Entry<LangTag,URL> entry: logoURIEntries.entrySet()) {
778
779                                LangTag langTag = entry.getKey();
780                                URL uri = entry.getValue();
781                                
782                                if (uri == null)
783                                        continue;
784
785                                if (langTag == null)
786                                        o.put("logo_uri", entry.getValue().toString());
787                                else
788                                        o.put("logo_uri#" + langTag, entry.getValue().toString());
789                        } 
790                }
791                
792                
793                if (! uriEntries.isEmpty()) {
794
795                        for (Map.Entry<LangTag,URL> entry: uriEntries.entrySet()) {
796
797                                LangTag langTag = entry.getKey();
798                                URL uri = entry.getValue();
799                                
800                                if (uri == null)
801                                        continue;
802
803                                if (langTag == null)
804                                        o.put("client_uri", entry.getValue().toString());
805                                else
806                                        o.put("client_uri#" + langTag, entry.getValue().toString());
807                        } 
808                }
809                
810                
811                if (! policyURIEntries.isEmpty()) {
812
813                        for (Map.Entry<LangTag,URL> entry: policyURIEntries.entrySet()) {
814
815                                LangTag langTag = entry.getKey();
816                                URL uri = entry.getValue();
817                                
818                                if (uri == null)
819                                        continue;
820
821                                if (langTag == null)
822                                        o.put("policy_uri", entry.getValue().toString());
823                                else
824                                        o.put("policy_uri#" + langTag, entry.getValue().toString());
825                        } 
826                }
827                
828                
829                if (! tosURIEntries.isEmpty()) {
830
831                        for (Map.Entry<LangTag,URL> entry: tosURIEntries.entrySet()) {
832
833                                LangTag langTag = entry.getKey();
834                                URL uri = entry.getValue();
835                                
836                                if (uri == null)
837                                        continue;
838
839                                if (langTag == null)
840                                        o.put("tos_uri", entry.getValue().toString());
841                                else
842                                        o.put("tos_uri#" + langTag, entry.getValue().toString());
843                        } 
844                }
845
846
847                if (authMethod != null)
848                        o.put("token_endpoint_auth_method", authMethod.toString());
849
850
851                if (jwkSetURI != null)
852                        o.put("jwks_uri", jwkSetURI.toString());
853
854                return o;
855        }
856        
857        
858        /**
859         * Parses an client metadata instance from the specified JSON object.
860         *
861         * @param jsonObject The JSON object to parse. Must not be  
862         *                   {@code null}.
863         *
864         * @return The client metadata.
865         *
866         * @throws ParseException If the JSON object couldn't be parsed to a
867         *                        client metadata instance.
868         */
869        public static ClientMetadata parse(final JSONObject jsonObject)
870                throws ParseException {
871
872                ClientMetadata metadata = new ClientMetadata();
873
874                if (jsonObject.containsKey("redirect_uris")) {
875
876                        Set<URL> redirectURIs = new LinkedHashSet<URL>();
877
878                        for (String uriString: JSONObjectUtils.getStringArray(jsonObject, "redirect_uris")) {
879
880                                try {
881                                        redirectURIs.add(new URL(uriString));
882
883                                } catch (MalformedURLException e) {
884
885                                        throw new ParseException("Invalid \"redirect_uris\" parameter: " +
886                                                                  e.getMessage());
887                                }
888                        }
889
890                        metadata.setRedirectURIs(redirectURIs);
891                }
892                
893                
894                if (jsonObject.containsKey("scope"))
895                        metadata.setScope(Scope.parse(JSONObjectUtils.getString(jsonObject, "scope")));
896                
897                
898                if (jsonObject.containsKey("response_types")) {
899                        
900                        Set<ResponseType> responseTypes = new LinkedHashSet<ResponseType>();
901                        
902                        for (String rt: JSONObjectUtils.getStringArray(jsonObject, "response_types")) {
903                                
904                                responseTypes.add(ResponseType.parse(rt));
905                        }
906                        
907                        metadata.setResponseTypes(responseTypes);
908                }
909                
910                
911                if (jsonObject.containsKey("grant_types")) {
912                        
913                        Set<GrantType> grantTypes = new LinkedHashSet<GrantType>();
914                        
915                        for (String grant: JSONObjectUtils.getStringArray(jsonObject, "grant_types")) {
916                                
917                                grantTypes.add(new GrantType(grant));
918                        }
919                        
920                        metadata.setGrantTypes(grantTypes);
921                }       
922                
923
924                if (jsonObject.containsKey("contacts")) {
925
926                        List<InternetAddress> emailList = new LinkedList<InternetAddress>();
927
928                        for (String emailString: JSONObjectUtils.getStringArray(jsonObject, "contacts")) {
929
930                                try {
931                                        emailList.add(new InternetAddress(emailString));
932
933                                } catch (AddressException e) {
934
935                                        throw new ParseException("Invalid \"contacts\" parameter: " +
936                                                                 e.getMessage());
937                                }
938                        }
939
940                        metadata.setContacts(emailList);
941                }
942
943                // Find lang-tagged client_name params
944                Map<LangTag,Object> matches = LangTagUtil.find("client_name", jsonObject);
945
946                for (Map.Entry<LangTag,Object> entry: matches.entrySet()) {
947
948                        try {
949                                metadata.setName((String)entry.getValue(), entry.getKey());
950
951                        } catch (ClassCastException e) {
952
953                                throw new ParseException("Invalid \"client_name\" (language tag) parameter");
954                        }
955                }
956
957
958                matches = LangTagUtil.find("logo_uri", jsonObject);
959
960                for (Map.Entry<LangTag,Object> entry: matches.entrySet()) {
961
962                        try {
963                                metadata.setLogoURI(new URL((String)entry.getValue()), entry.getKey());
964
965                        } catch (Exception e) {
966
967                                throw new ParseException("Invalid \"logo_uri\" (language tag) parameter");
968                        }
969                }
970                
971                
972                matches = LangTagUtil.find("client_uri", jsonObject);
973
974                for (Map.Entry<LangTag,Object> entry: matches.entrySet()) {
975
976                        try {
977                                metadata.setURI(new URL((String)entry.getValue()), entry.getKey());
978
979                        } catch (Exception e) {
980
981                                throw new ParseException("Invalid \"client_uri\" (language tag) parameter");
982                        }
983                }
984                
985                
986                matches = LangTagUtil.find("policy_uri", jsonObject);
987
988                for (Map.Entry<LangTag,Object> entry: matches.entrySet()) {
989
990                        try {
991                                metadata.setPolicyURI(new URL((String)entry.getValue()), entry.getKey());
992
993                        } catch (Exception e) {
994
995                                throw new ParseException("Invalid \"policy_uri\" (language tag) parameter");
996                        }
997                }
998                
999                
1000                matches = LangTagUtil.find("tos_uri", jsonObject);
1001
1002                for (Map.Entry<LangTag,Object> entry: matches.entrySet()) {
1003
1004                        try {
1005                                metadata.setTermsOfServiceURI(new URL((String)entry.getValue()), entry.getKey());
1006
1007                        } catch (Exception e) {
1008
1009                                throw new ParseException("Invalid \"tos_uri\" (language tag) parameter");
1010                        }
1011                }
1012                
1013
1014                if (jsonObject.containsKey("token_endpoint_auth_method"))
1015                        metadata.setTokenEndpointAuthMethod(new ClientAuthenticationMethod(
1016                                JSONObjectUtils.getString(jsonObject, "token_endpoint_auth_method")));
1017
1018                        
1019                if (jsonObject.containsKey("jwks_uri"))
1020                        metadata.setJWKSetURL(JSONObjectUtils.getURL(jsonObject, "jwks_uri"));
1021
1022                return metadata;
1023        }
1024}