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