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