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.openid.connect.sdk;
019
020
021import net.jcip.annotations.Immutable;
022
023import com.nimbusds.common.contenttype.ContentType;
024import com.nimbusds.jwt.JWT;
025import com.nimbusds.oauth2.sdk.ParseException;
026import com.nimbusds.oauth2.sdk.SerializeException;
027import com.nimbusds.oauth2.sdk.SuccessResponse;
028import com.nimbusds.oauth2.sdk.http.CommonContentTypes;
029import com.nimbusds.oauth2.sdk.http.HTTPResponse;
030import com.nimbusds.openid.connect.sdk.claims.UserInfo;
031
032
033/**
034 * UserInfo success response.
035 *
036 * <p>The UserInfo claims may be passed as an unprotected JSON object or as a 
037 * plain, signed or encrypted JSON Web Token (JWT). Use the appropriate 
038 * constructor for that.
039 *
040 * <p>Example UserInfo HTTP response:
041 *
042 * <pre>
043 * HTTP/1.1 200 OK
044 * Content-Type: application/json
045 * 
046 * {
047 *  "sub"         : "248289761001",
048 *  "name"        : "Jane Doe"
049 *  "given_name"  : "Jane",
050 *  "family_name" : "Doe",
051 *  "email"       : "[email protected]",
052 *  "picture"     : "http://example.com/janedoe/me.jpg"
053 * }
054 * </pre>
055 *
056 * <p>Related specifications:
057 *
058 * <ul>
059 *     <li>OpenID Connect Core 1.0, section 5.3.2.
060 * </ul>
061 */
062@Immutable
063public class UserInfoSuccessResponse
064        extends UserInfoResponse
065        implements SuccessResponse {
066
067
068        /**
069         * The UserInfo claims set, serialisable to a JSON object.
070         */
071        private final UserInfo claimsSet;
072        
073        
074        /**
075         * The UserInfo claims set, as plain, signed or encrypted JWT.
076         */
077        private final JWT jwt;
078        
079        
080        /**
081         * Creates a new UserInfo success response where the claims are 
082         * specified as an unprotected UserInfo claims set.
083         *
084         * @param claimsSet The UserInfo claims set. Must not be {@code null}.
085         */
086        public UserInfoSuccessResponse(final UserInfo claimsSet) {
087        
088                if (claimsSet == null)
089                        throw new IllegalArgumentException("The claims must not be null");
090                
091                this.claimsSet = claimsSet;
092                
093                this.jwt = null;
094        }
095        
096        
097        /**
098         * Creates a new UserInfo success response where the claims are 
099         * specified as a plain, signed or encrypted JSON Web Token (JWT).
100         *
101         * @param jwt The UserInfo claims set. Must not be {@code null}.
102         */
103        public UserInfoSuccessResponse(final JWT jwt) {
104        
105                if (jwt == null)
106                        throw new IllegalArgumentException("The claims JWT must not be null");
107                
108                this.jwt = jwt;
109                
110                this.claimsSet = null;
111        }
112
113
114        @Override
115        public boolean indicatesSuccess() {
116
117                return true;
118        }
119        
120        
121        /**
122         * Gets the content type of this UserInfo response.
123         *
124         * @return The content type, according to the claims format.
125         */
126        public ContentType getEntityContentType() {
127        
128                if (claimsSet != null)
129                        return ContentType.APPLICATION_JSON;
130                else
131                        return ContentType.APPLICATION_JWT;
132        }
133        
134        
135        /**
136         * @see #getEntityContentType()
137         */
138        @Deprecated
139        public javax.mail.internet.ContentType getContentType() {
140        
141                if (claimsSet != null)
142                        return CommonContentTypes.APPLICATION_JSON;
143                else
144                        return CommonContentTypes.APPLICATION_JWT;
145        }
146        
147        
148        /**
149         * Gets the UserInfo claims set as an unprotected UserInfo claims set.
150         *
151         * @return The UserInfo claims set, {@code null} if it was specified as
152         *         JSON Web Token (JWT) instead.
153         */
154        public UserInfo getUserInfo() {
155        
156                return claimsSet;
157        }
158        
159        
160        /**
161         * Gets the UserInfo claims set as a plain, signed or encrypted JSON
162         * Web Token (JWT).
163         *
164         * @return The UserInfo claims set as a JSON Web Token (JWT), 
165         *         {@code null} if it was specified as an unprotected UserInfo
166         *         claims set instead.
167         */
168        public JWT getUserInfoJWT() {
169        
170                return jwt;
171        }
172        
173        
174        @Override
175        public HTTPResponse toHTTPResponse() {
176        
177                HTTPResponse httpResponse = new HTTPResponse(HTTPResponse.SC_OK);
178                
179                httpResponse.setEntityContentType(getEntityContentType());
180                
181                String content;
182                
183                if (claimsSet != null) {
184                
185                        content = claimsSet.toJSONObject().toString();
186
187                } else {
188                        
189                        try {
190                                content = jwt.serialize();
191                                
192                        } catch (IllegalStateException e) {
193                        
194                                throw new SerializeException("Couldn't serialize UserInfo claims JWT: " + 
195                                                             e.getMessage(), e);
196                        }
197                }
198                
199                httpResponse.setContent(content);
200        
201                return httpResponse;
202        }
203        
204        
205        /**
206         * Parses a UserInfo response from the specified HTTP response.
207         *
208         * <p>Example HTTP response:
209         *
210         * <pre>
211         * HTTP/1.1 200 OK
212         * Content-Type: application/json
213         * 
214         * {
215         *  "sub"         : "248289761001",
216         *  "name"        : "Jane Doe"
217         *  "given_name"  : "Jane",
218         *  "family_name" : "Doe",
219         *  "email"       : "[email protected]",
220         *  "picture"     : "http://example.com/janedoe/me.jpg"
221         * }
222         * </pre>
223         *
224         * @param httpResponse The HTTP response. Must not be {@code null}.
225         *
226         * @return The UserInfo response.
227         *
228         * @throws ParseException If the HTTP response couldn't be parsed to a 
229         *                        UserInfo response.
230         */
231        public static UserInfoSuccessResponse parse(final HTTPResponse httpResponse)
232                throws ParseException {
233                
234                httpResponse.ensureStatusCode(HTTPResponse.SC_OK);
235                
236                httpResponse.ensureEntityContentType();
237                
238                ContentType ct = httpResponse.getEntityContentType();
239                
240                UserInfoSuccessResponse response;
241                
242                if (ct.matches(ContentType.APPLICATION_JSON)) {
243                
244                        UserInfo claimsSet;
245                        
246                        try {
247                                claimsSet = new UserInfo(httpResponse.getContentAsJSONObject());
248                                
249                        } catch (Exception e) {
250                                
251                                throw new ParseException("Couldn't parse UserInfo claims: " + 
252                                                         e.getMessage(), e);
253                        }
254                        
255                        response = new UserInfoSuccessResponse(claimsSet);
256                        
257                } else if (ct.matches(ContentType.APPLICATION_JWT)) {
258                
259                        JWT jwt;
260                        
261                        try {
262                                jwt = httpResponse.getContentAsJWT();
263                                
264                        } catch (ParseException e) {
265                        
266                                throw new ParseException("Couldn't parse UserInfo claims JWT: " + 
267                                                         e.getMessage(), e);
268                        }
269                        
270                        response = new UserInfoSuccessResponse(jwt);
271                        
272                } else {
273                        throw new ParseException("Unexpected Content-Type, must be " + 
274                                                 ContentType.APPLICATION_JSON +
275                                                 " or " +
276                                                 ContentType.APPLICATION_JWT);
277                }
278                
279                return response;
280        }
281}