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