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