001/*
002 * oauth2-oidc-sdk
003 *
004 * Copyright 2012-2016, Connect2id Ltd and contributors.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use
007 * this file except in compliance with the License. You may obtain a copy of the
008 * License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software distributed
013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
015 * specific language governing permissions and limitations under the License.
016 */
017
018package com.nimbusds.oauth2.sdk.client;
019
020
021import com.nimbusds.oauth2.sdk.ParseException;
022import com.nimbusds.oauth2.sdk.auth.ClientAuthenticationMethod;
023import com.nimbusds.oauth2.sdk.auth.Secret;
024import com.nimbusds.oauth2.sdk.id.ClientID;
025import com.nimbusds.oauth2.sdk.token.BearerAccessToken;
026import net.jcip.annotations.Immutable;
027import net.minidev.json.JSONObject;
028
029import java.net.URI;
030import java.util.*;
031
032
033/**
034 * Client information. Encapsulates the registration and metadata details of 
035 * an OAuth 2.0 client:
036 * 
037 * <ul>
038 *     <li>The client identifier.
039 *     <li>The client metadata.
040 *     <li>The optional client secret for a confidential client.
041 *     <li>The optional registration URI and access token if dynamic client
042 *         registration is permitted.
043 * </ul>
044 *
045 * <p>Related specifications:
046 *
047 * <ul>
048 *     <li>OAuth 2.0 Dynamic Client Registration Protocol (RFC 7591)
049 *     <li>OAuth 2.0 Dynamic Client Registration Management Protocol (RFC 7592)
050 * </ul>
051 */
052@Immutable
053public class ClientInformation {
054
055
056        /**
057         * The registered parameter names.
058         */
059        private static final Set<String> REGISTERED_PARAMETER_NAMES;
060
061
062        static {
063                Set<String> p = new HashSet<>(ClientMetadata.getRegisteredParameterNames());
064
065                p.add("client_id");
066                p.add("client_id_issued_at");
067                p.add("client_secret");
068                p.add("client_secret_expires_at");
069                p.add("registration_access_token");
070                p.add("registration_client_uri");
071
072                REGISTERED_PARAMETER_NAMES = Collections.unmodifiableSet(p);
073        }
074
075
076        /**
077         * The registered client ID.
078         */
079        private final ClientID id;
080
081
082        /**
083         * The date the client ID was issued at.
084         */
085        private final Date issueDate;
086
087
088        /**
089         * The client metadata.
090         */
091        private final ClientMetadata metadata;
092
093
094        /**
095         * The optional client secret.
096         */
097        private final Secret secret;
098
099
100        /**
101         * The client registration URI.
102         */
103        private final URI registrationURI;
104
105
106        /**
107         * The client registration access token.
108         */
109        private final BearerAccessToken accessToken;
110        
111        
112        /**
113         * Creates a new minimal client information instance without a client
114         * secret.
115         *
116         * @param id       The client identifier. Must not be {@code null}.
117         * @param metadata The client metadata. Must not be {@code null}.
118         */
119        public ClientInformation(final ClientID id, final ClientMetadata metadata) {
120                this(id, null, metadata, null);
121        }
122
123
124        /**
125         * Creates a new client information instance.
126         *
127         * @param id        The client identifier. Must not be {@code null}.
128         * @param issueDate The issue date of the client identifier,
129         *                  {@code null} if not specified.
130         * @param metadata  The client metadata. Must not be {@code null}.
131         * @param secret    The optional client secret, {@code null} if not
132         *                  specified.
133         */
134        public ClientInformation(final ClientID id,
135                                 final Date issueDate,
136                                 final ClientMetadata metadata,
137                                 final Secret secret) {
138
139                this(id, issueDate, metadata, secret, null, null);
140        }
141
142
143        /**
144         * Creates a new client information instance permitting dynamic client
145         * registration management.
146         * 
147         * @param id              The client identifier. Must not be 
148         *                        {@code null}.
149         * @param issueDate       The issue date of the client identifier,
150         *                        {@code null} if not specified.
151         * @param metadata        The client metadata. Must not be
152         *                        {@code null}.
153         * @param secret          The optional client secret, {@code null} if
154         *                        not specified.
155         * @param registrationURI The client registration URI, {@code null} if
156         *                        not specified.
157         * @param accessToken     The client registration access token,
158         *                        {@code null} if not specified.
159         */
160        public ClientInformation(final ClientID id,
161                                 final Date issueDate,
162                                 final ClientMetadata metadata,
163                                 final Secret secret,
164                                 final URI registrationURI,
165                                 final BearerAccessToken accessToken) {
166
167                this.id = Objects.requireNonNull(id);
168                this.issueDate = issueDate;
169                this.metadata = Objects.requireNonNull(metadata);
170                this.secret = secret;
171                this.registrationURI = registrationURI;
172                this.accessToken = accessToken;
173        }
174
175
176        /**
177         * Gets the registered client metadata parameter names.
178         *
179         * @return The registered parameter names, as an unmodifiable set.
180         */
181        public static Set<String> getRegisteredParameterNames() {
182
183                return REGISTERED_PARAMETER_NAMES;
184        }
185
186
187        /**
188         * Gets the client identifier. Corresponds to the {@code client_id}
189         * client registration parameter.
190         *
191         * @return The client ID.
192         */
193        public ClientID getID() {
194
195                return id;
196        }
197
198
199        /**
200         * Gets the issue date of the client identifier. Corresponds to the
201         * {@code client_id_issued_at} client registration parameter.
202         *
203         * @return The issue date, {@code null} if not specified.
204         */
205        public Date getIDIssueDate() {
206
207                return issueDate;
208        }
209        
210        
211        /**
212         * Gets the client metadata.
213         * 
214         * @return The client metadata.
215         */
216        public ClientMetadata getMetadata() {
217                
218                return metadata;
219        }
220
221
222        /**
223         * Gets the client secret. Corresponds to the {@code client_secret} and
224         * {@code client_secret_expires_at} client registration parameters.
225         *
226         * @return The client secret, {@code null} if not specified.
227         */
228        public Secret getSecret() {
229
230                return secret;
231        }
232
233
234        /**
235         * Infers the client type.
236         *
237         * @return The client type.
238         */
239        public ClientType inferClientType() {
240
241                // The client must be unambiguously public, else it is marked as confidential
242
243                return secret == null
244                        && ClientAuthenticationMethod.NONE.equals(getMetadata().getTokenEndpointAuthMethod())
245                        && getMetadata().getJWKSetURI() == null
246                        && getMetadata().getJWKSet() == null
247                        ? ClientType.PUBLIC : ClientType.CONFIDENTIAL;
248        }
249
250
251        /**
252         * Gets the URI of the client registration. Corresponds to the
253         * {@code registration_client_uri} client registration parameter.
254         *
255         * @return The registration URI, {@code null} if not specified.
256         */
257        public URI getRegistrationURI() {
258
259                return registrationURI;
260        }
261
262
263        /**
264         * Gets the registration access token. Corresponds to the
265         * {@code registration_access_token} client registration parameter.
266         *
267         * @return The registration access token, {@code null} if not
268         *         specified.
269         */
270        public BearerAccessToken getRegistrationAccessToken() {
271
272                return accessToken;
273        }
274
275
276        /**
277         * Returns the JSON object representation of this client information 
278         * instance.
279         *
280         * @return The JSON object.
281         */
282        public JSONObject toJSONObject() {
283
284                JSONObject o = metadata.toJSONObject();
285
286                o.put("client_id", id.getValue());
287
288                if (issueDate != null) {
289
290                        o.put("client_id_issued_at", issueDate.getTime() / 1000);
291                }
292
293                if (secret != null) {
294                        o.put("client_secret", secret.getValue());
295
296                        if (secret.getExpirationDate() != null) {
297                                o.put("client_secret_expires_at", secret.getExpirationDate().getTime() / 1000);
298                        } else {
299                                o.put("client_secret_expires_at", 0L);
300                        }
301                }
302
303                if (registrationURI != null) {
304
305                        o.put("registration_client_uri", registrationURI.toString());
306                }
307
308                if (accessToken != null) {
309
310                        o.put("registration_access_token", accessToken.getValue());
311                }
312
313                return o;
314        }
315
316
317        /**
318         * Parses a client information instance from the specified JSON object.
319         *
320         * @param jsonObject The JSON object to parse. Must not be 
321         *                   {@code null}.
322         *
323         * @return The client information.
324         *
325         * @throws ParseException If the JSON object couldn't be parsed to a
326         *                        client information instance.
327         */
328        public static ClientInformation parse(final JSONObject jsonObject)
329                throws ParseException {
330                
331                return new ClientInformation(
332                        ClientCredentialsParser.parseID(jsonObject),
333                        ClientCredentialsParser.parseIDIssueDate(jsonObject),
334                        ClientMetadata.parse(jsonObject),
335                        ClientCredentialsParser.parseSecret(jsonObject),
336                        ClientCredentialsParser.parseRegistrationURI(jsonObject),
337                        ClientCredentialsParser.parseRegistrationAccessToken(jsonObject));
338        }
339}