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