001package com.nimbusds.openid.connect.provider.spi.grants; 002 003 004import java.util.*; 005 006import net.minidev.json.JSONObject; 007 008import com.nimbusds.oauth2.sdk.ParseException; 009import com.nimbusds.oauth2.sdk.Scope; 010import com.nimbusds.oauth2.sdk.id.Audience; 011import com.nimbusds.oauth2.sdk.id.Subject; 012import com.nimbusds.oauth2.sdk.util.JSONObjectUtils; 013 014import com.nimbusds.openid.connect.sdk.claims.ACR; 015import com.nimbusds.openid.connect.sdk.claims.AMR; 016 017 018/** 019 * Authorisation response from a {@link PasswordGrantHandler}. 020 * 021 * <p>The minimum details it contains is the identifier of the authenticated 022 * subject (end-user) and the authorised scope values. The other parameters are 023 * optional or have suitable defaults. 024 */ 025public class PasswordGrantAuthorization extends GrantAuthorization { 026 027 028 /** 029 * The identifier of the authorised subject. 030 */ 031 private final Subject subject; 032 033 034 /** 035 * The time of the subject authentication. If {@code null} it will be 036 * set to now. Applies only if an ID token is issued. 037 */ 038 private final Date authTime; 039 040 041 /** 042 * The Authentication Context Class Reference (ACR), {@code null} if 043 * not specified. Applies only if an ID token is issued. 044 */ 045 private final ACR acr; 046 047 048 /** 049 * The Authentication Methods Reference (AMR) list, {@code null} if not 050 * specified. Applies only if an ID token is issued. 051 */ 052 private final List<AMR> amrList; 053 054 055 /** 056 * Controls the authorisation lifetime. {@code true} for a long-lived 057 * authorisation (implies persistence), {@code false} for a short-lived 058 * one. 059 */ 060 private final boolean longLived; 061 062 063 /** 064 * The refresh token specification. 065 */ 066 private final RefreshTokenSpec refreshTokenSpec; 067 068 069 /** 070 * The ID token specification. 071 */ 072 private final IDTokenSpec idTokenSpec; 073 074 075 /** 076 * The OpenID Connect claims spec. 077 */ 078 private final ClaimsSpec claimsSpec; 079 080 081 /** 082 * Creates a new OAuth 2.0 - only authorisation response from a 083 * {@link PasswordGrantHandler}. 084 * 085 * @param subject The identifier of the authorised 086 * subject. Must not be {@code null}. 087 * @param scope The authorised scope values. Must not be 088 * {@code null}. 089 * @param audList Explicit list of audiences for the access 090 * token, {@code null} if not specified. 091 * @param longLived Controls the authorisation lifetime. 092 * {@code true} for a long-lived 093 * authorisation (implies persistence), 094 * {@code false} for a short-lived 095 * (transient) one. 096 * @param accessTokenSpec The access token specification. Must not 097 * be {@code null}. 098 * @param refreshTokenSpec The refresh token specification. Must not 099 * be {@code null}. 100 * @param data Optional authorisation data as a JSON 101 * object, {@code null} if not specified. 102 */ 103 public PasswordGrantAuthorization(final Subject subject, 104 final Scope scope, 105 final List<Audience> audList, 106 final boolean longLived, 107 final AccessTokenSpec accessTokenSpec, 108 final RefreshTokenSpec refreshTokenSpec, 109 final JSONObject data) { 110 111 this (subject, null, null, null, scope, audList, longLived, accessTokenSpec, refreshTokenSpec, new IDTokenSpec(), new ClaimsSpec(), data); 112 } 113 114 115 /** 116 * Creates a new OpenID Connect / OAuth 2.0 authorisation response from 117 * a {@link PasswordGrantHandler}. 118 * 119 * @param subject The identifier of the authorised 120 * subject. Must not be {@code null}. 121 * @param authTime The time of the subject authentication. 122 * If {@code null} it will be set to now. 123 * Applies only if an ID token is issued. 124 * @param acr The Authentication Context Class 125 * Reference (ACR), {@code null} if not 126 * specified. Applies only if an ID token 127 * is issued. 128 * @param amrList The Authentication Methods Reference 129 * (AMR) list, {@code null} if not 130 * specified. Applies only if an ID token 131 * is issued. 132 * @param scope The authorised scope values. Must not be 133 * {@code null}. 134 * @param audList Explicit list of audiences for the 135 * access token, {@code null} if not 136 * specified. 137 * @param longLived Controls the authorisation lifetime. 138 * {@code true} for a long-lived 139 * authorisation (implies persistence), 140 * {@code false} for a short-lived one. 141 * @param accessTokenSpec The access token specification. Must not 142 * be {@code null}. 143 * @param refreshTokenSpec The refresh token specification. Must not 144 * be {@code null}. 145 * @param idTokenSpec The ID token specification. Must not be 146 * {@code null}. 147 * @param claimsSpec The claims specification. 148 * @param data Optional authorisation data as a JSON 149 * object, {@code null} if not specified. 150 */ 151 public PasswordGrantAuthorization(final Subject subject, 152 final Date authTime, 153 final ACR acr, 154 final List<AMR> amrList, 155 final Scope scope, 156 final List<Audience> audList, 157 final boolean longLived, 158 final AccessTokenSpec accessTokenSpec, 159 final RefreshTokenSpec refreshTokenSpec, 160 final IDTokenSpec idTokenSpec, 161 final ClaimsSpec claimsSpec, 162 final JSONObject data) { 163 164 super(scope, audList, accessTokenSpec, data); 165 166 if (subject == null) { 167 throw new IllegalArgumentException("The subject must not be null"); 168 } 169 170 this.subject = subject; 171 172 this.authTime = authTime; 173 this.acr = acr; 174 this.amrList = amrList; 175 this.longLived = longLived; 176 177 if (refreshTokenSpec == null) { 178 throw new IllegalArgumentException("The refresh token specification must not be null"); 179 } 180 181 if (longLived) { 182 this.refreshTokenSpec = refreshTokenSpec; 183 } else { 184 // Defaults to no-issue 185 this.refreshTokenSpec = new RefreshTokenSpec(); 186 } 187 188 if (idTokenSpec == null) { 189 throw new IllegalArgumentException("The ID token specification must not be null"); 190 } 191 192 this.idTokenSpec = idTokenSpec; 193 194 if (claimsSpec == null) { 195 throw new IllegalArgumentException("The claim specification must not be null"); 196 } 197 198 this.claimsSpec = claimsSpec; 199 } 200 201 202 /** 203 * Returns the authorised subject. 204 * 205 * @return The identifier of the authorised subject. 206 */ 207 public Subject getSubject() { 208 209 return subject; 210 } 211 212 213 /** 214 * Returns the time of the subject authentication. 215 * 216 * @return The time of the subject authentication. If {@code null} it 217 * will be set to now. Applies only if an ID token is issued. 218 */ 219 public Date getAuthTime() { 220 221 return authTime; 222 } 223 224 225 /** 226 * Returns the Authentication Context Class Reference (ACR). 227 * 228 * @return The Authentication Context Class Reference (ACR), 229 * {@code null} if not specified. Applies only if an ID token 230 * is issued. 231 */ 232 public ACR getACR() { 233 234 return acr; 235 } 236 237 238 /** 239 * Returns The Authentication Methods Reference (AMR) list. 240 * 241 * @return The Authentication Methods Reference (AMR) list, 242 * {@code null} if not specified. Applies only if an ID token 243 * is issued. 244 */ 245 public List<AMR> getAMRList() { 246 247 return amrList; 248 } 249 250 251 /** 252 * Returns the authorisation lifetime. 253 * 254 * @return {@code true} for a long-lived authorisation (implies 255 * persistence), {@code false} for a short-lived one. 256 */ 257 public boolean isLongLived() { 258 259 return longLived; 260 } 261 262 263 /** 264 * Returns the refresh token specification. 265 * 266 * @return The refresh token specification. 267 */ 268 public RefreshTokenSpec getRefreshTokenSpec() { 269 270 return refreshTokenSpec; 271 } 272 273 274 /** 275 * Returns the ID token specification. 276 * 277 * @return The ID token specification. 278 */ 279 public IDTokenSpec getIDTokenSpec() { 280 281 return idTokenSpec; 282 } 283 284 285 /** 286 * Returns the claims specification. 287 * 288 * @return The claims specification. 289 */ 290 public ClaimsSpec getClaimsSpec() { 291 292 return claimsSpec; 293 } 294 295 296 /** 297 * Returns a JSON object representation of this authorisation response. 298 * 299 * @return The JSON object representation. 300 */ 301 public JSONObject toJSONObject() { 302 303 JSONObject o = super.toJSONObject(); 304 305 o.put("sub", subject.getValue()); 306 307 if (authTime != null) { 308 o.put("auth_time", authTime.getTime() / 1000l); 309 } 310 311 if (acr != null) { 312 o.put("acr", acr.getValue()); 313 } 314 315 if (amrList != null) { 316 317 List<String> sl = new ArrayList<>(amrList.size()); 318 319 for (AMR amr: amrList) { 320 sl.add(amr.getValue()); 321 } 322 323 o.put("amr", sl); 324 } 325 326 o.put("long_lived", longLived); 327 328 if (longLived && refreshTokenSpec.issue()) { 329 o.put("refresh_token", refreshTokenSpec.toJSONObject()); 330 } 331 332 if (idTokenSpec.issue()) { 333 o.put("id_token", idTokenSpec.toJSONObject()); 334 } 335 336 o.putAll(claimsSpec.toJSONObject()); 337 338 return o; 339 } 340 341 342 /** 343 * Parses an authorisation response from the specified JSON object 344 * representation. 345 * 346 * @param o The JSON object to parse. Must not be {@code null}. 347 * 348 * @return The authorisation response. 349 * 350 * @throws ParseException If parsing failed. 351 */ 352 public static PasswordGrantAuthorization parse(final JSONObject o) 353 throws ParseException { 354 355 GrantAuthorization basicAuthz = GrantAuthorization.parse(o); 356 357 Subject sub = new Subject(JSONObjectUtils.getString(o, "sub")); 358 359 Date authTime = null; 360 361 if (o.containsKey("auth_time")) { 362 authTime = new Date(JSONObjectUtils.getLong(o, "auth_time") * 1000l); 363 } 364 365 ACR acr = null; 366 367 if (o.containsKey("acr")) { 368 acr = new ACR(JSONObjectUtils.getString(o, "acr")); 369 } 370 371 List<AMR> amrList = null; 372 373 if (o.containsKey("amr")) { 374 String[] sa = JSONObjectUtils.getStringArray(o, "amr"); 375 amrList = new ArrayList<>(sa.length); 376 for (String s: sa) { 377 amrList.add(new AMR(s)); 378 } 379 } 380 381 boolean longLived = false; 382 383 if (o.containsKey("long_lived")) { 384 longLived = JSONObjectUtils.getBoolean(o, "long_lived"); 385 } 386 387 RefreshTokenSpec rtSpec = new RefreshTokenSpec(); 388 389 if (longLived && o.containsKey("refresh_token")) { 390 391 rtSpec = RefreshTokenSpec.parse(JSONObjectUtils.getJSONObject(o, "refresh_token")); 392 } 393 394 IDTokenSpec idSpec = new IDTokenSpec(); 395 396 if (o.containsKey("id_token")) { 397 398 idSpec = IDTokenSpec.parse(JSONObjectUtils.getJSONObject(o, "id_token")); 399 } 400 401 ClaimsSpec clSpec = ClaimsSpec.parse(o); 402 403 return new PasswordGrantAuthorization( 404 sub, authTime, acr, amrList, 405 basicAuthz.getScope(), 406 basicAuthz.getAudience(), 407 longLived, 408 basicAuthz.getAccessTokenSpec(), 409 rtSpec, 410 idSpec, 411 clSpec, 412 basicAuthz.getData()); 413 } 414}