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        /**
101         * Gets the content type of this UserInfo response.
102         *
103         * @return The content type, according to the claims format.
104         */
105        public ContentType getContentType() {
106        
107                if (claimsSet != null)
108                        return CommonContentTypes.APPLICATION_JSON;
109                else
110                        return CommonContentTypes.APPLICATION_JWT;
111        }
112        
113        
114        /**
115         * Gets the UserInfo claims set as an unprotected UserInfo claims set.
116         *
117         * @return The UserInfo claims set, {@code null} if it was specified as
118         *         JSON Web Token (JWT) instead.
119         */
120        public UserInfo getUserInfo() {
121        
122                return claimsSet;
123        }
124        
125        
126        /**
127         * Gets the UserInfo claims set as a plain, signed or encrypted JSON
128         * Web Token (JWT).
129         *
130         * @return The UserInfo claims set as a JSON Web Token (JWT), 
131         *         {@code null} if it was specified as an unprotected UserInfo
132         *         claims set instead.
133         */
134        public JWT getUserInfoJWT() {
135        
136                return jwt;
137        }
138        
139        
140        @Override
141        public HTTPResponse toHTTPResponse()
142                throws SerializeException {
143        
144                HTTPResponse httpResponse = new HTTPResponse(HTTPResponse.SC_OK);
145                
146                httpResponse.setContentType(getContentType());
147                
148                String content;
149                
150                if (claimsSet != null) {
151                
152                        content = claimsSet.toJSONObject().toString();
153
154                } else {
155                        
156                        try {
157                                content = jwt.serialize();
158                                
159                        } catch (IllegalStateException e) {
160                        
161                                throw new SerializeException("Couldn't serialize UserInfo claims JWT: " + 
162                                                             e.getMessage(), e);
163                        }
164                }
165                
166                httpResponse.setContent(content);
167        
168                return httpResponse;
169        }
170        
171        
172        /**
173         * Parses a UserInfo response from the specified HTTP response.
174         *
175         * <p>Example HTTP response:
176         *
177         * <pre>
178         * HTTP/1.1 200 OK
179         * Content-Type: application/json
180         * 
181         * {
182         *  "sub"         : "248289761001",
183         *  "name"        : "Jane Doe"
184         *  "given_name"  : "Jane",
185         *  "family_name" : "Doe",
186         *  "email"       : "[email protected]",
187         *  "picture"     : "http://example.com/janedoe/me.jpg"
188         * }
189         * </pre>
190         *
191         * @param httpResponse The HTTP response. Must not be {@code null}.
192         *
193         * @return The UserInfo response.
194         *
195         * @throws ParseException If the HTTP response couldn't be parsed to a 
196         *                        UserInfo response.
197         */
198        public static UserInfoSuccessResponse parse(final HTTPResponse httpResponse)
199                throws ParseException {
200                
201                httpResponse.ensureStatusCode(HTTPResponse.SC_OK);
202                
203                httpResponse.ensureContentType();
204                
205                ContentType ct = httpResponse.getContentType();
206                
207                
208                UserInfoSuccessResponse response;
209                
210                if (ct.match(CommonContentTypes.APPLICATION_JSON)) {
211                
212                        UserInfo claimsSet;
213                        
214                        try {
215                                claimsSet = new UserInfo(httpResponse.getContentAsJSONObject());
216                                
217                        } catch (Exception e) {
218                                
219                                throw new ParseException("Couldn't parse UserInfo claims: " + 
220                                                         e.getMessage(), e);
221                        }
222                        
223                        response = new UserInfoSuccessResponse(claimsSet);
224                }
225                else if (ct.match(CommonContentTypes.APPLICATION_JWT)) {
226                
227                        JWT jwt;
228                        
229                        try {
230                                jwt = httpResponse.getContentAsJWT();
231                                
232                        } catch (ParseException e) {
233                        
234                                throw new ParseException("Couldn't parse UserInfo claims JWT: " + 
235                                                         e.getMessage(), e);
236                        }
237                        
238                        response = new UserInfoSuccessResponse(jwt);
239                }
240                else {
241                        throw new ParseException("Unexpected Content-Type, must be " + 
242                                                 CommonContentTypes.APPLICATION_JSON +
243                                                 " or " +
244                                                 CommonContentTypes.APPLICATION_JWT);
245                }
246                
247                return response;
248        }
249}