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