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