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}