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                throws SerializeException {
150        
151                HTTPResponse httpResponse = new HTTPResponse(HTTPResponse.SC_OK);
152                
153                httpResponse.setContentType(getContentType());
154                
155                String content;
156                
157                if (claimsSet != null) {
158                
159                        content = claimsSet.toJSONObject().toString();
160
161                } else {
162                        
163                        try {
164                                content = jwt.serialize();
165                                
166                        } catch (IllegalStateException e) {
167                        
168                                throw new SerializeException("Couldn't serialize UserInfo claims JWT: " + 
169                                                             e.getMessage(), e);
170                        }
171                }
172                
173                httpResponse.setContent(content);
174        
175                return httpResponse;
176        }
177        
178        
179        /**
180         * Parses a UserInfo response from the specified HTTP response.
181         *
182         * <p>Example HTTP response:
183         *
184         * <pre>
185         * HTTP/1.1 200 OK
186         * Content-Type: application/json
187         * 
188         * {
189         *  "sub"         : "248289761001",
190         *  "name"        : "Jane Doe"
191         *  "given_name"  : "Jane",
192         *  "family_name" : "Doe",
193         *  "email"       : "[email protected]",
194         *  "picture"     : "http://example.com/janedoe/me.jpg"
195         * }
196         * </pre>
197         *
198         * @param httpResponse The HTTP response. Must not be {@code null}.
199         *
200         * @return The UserInfo response.
201         *
202         * @throws ParseException If the HTTP response couldn't be parsed to a 
203         *                        UserInfo response.
204         */
205        public static UserInfoSuccessResponse parse(final HTTPResponse httpResponse)
206                throws ParseException {
207                
208                httpResponse.ensureStatusCode(HTTPResponse.SC_OK);
209                
210                httpResponse.ensureContentType();
211                
212                ContentType ct = httpResponse.getContentType();
213                
214                
215                UserInfoSuccessResponse response;
216                
217                if (ct.match(CommonContentTypes.APPLICATION_JSON)) {
218                
219                        UserInfo claimsSet;
220                        
221                        try {
222                                claimsSet = new UserInfo(httpResponse.getContentAsJSONObject());
223                                
224                        } catch (Exception e) {
225                                
226                                throw new ParseException("Couldn't parse UserInfo claims: " + 
227                                                         e.getMessage(), e);
228                        }
229                        
230                        response = new UserInfoSuccessResponse(claimsSet);
231                }
232                else if (ct.match(CommonContentTypes.APPLICATION_JWT)) {
233                
234                        JWT jwt;
235                        
236                        try {
237                                jwt = httpResponse.getContentAsJWT();
238                                
239                        } catch (ParseException e) {
240                        
241                                throw new ParseException("Couldn't parse UserInfo claims JWT: " + 
242                                                         e.getMessage(), e);
243                        }
244                        
245                        response = new UserInfoSuccessResponse(jwt);
246                }
247                else {
248                        throw new ParseException("Unexpected Content-Type, must be " + 
249                                                 CommonContentTypes.APPLICATION_JSON +
250                                                 " or " +
251                                                 CommonContentTypes.APPLICATION_JWT);
252                }
253                
254                return response;
255        }
256}