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}