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