001package com.nimbusds.openid.connect.provider.spi.grants; 002 003 004import java.util.*; 005 006import net.jcip.annotations.Immutable; 007 008import net.minidev.json.JSONObject; 009import org.checkerframework.checker.nullness.qual.Nullable; 010 011import com.nimbusds.oauth2.sdk.ParseException; 012import com.nimbusds.oauth2.sdk.Scope; 013import com.nimbusds.oauth2.sdk.id.Audience; 014import com.nimbusds.oauth2.sdk.id.Subject; 015import com.nimbusds.oauth2.sdk.util.JSONObjectUtils; 016 017import com.nimbusds.openid.connect.sdk.claims.ACR; 018import com.nimbusds.openid.connect.sdk.claims.AMR; 019 020 021/** 022 * Authorisation produced by a {@link PasswordGrantHandler}. Specifies a 023 * subject (end-user) and permits ID and refresh token issue. 024 * 025 * <p>Required authorisation details: 026 * 027 * <ul> 028 * <li>The authenticated subject (end-user). 029 * <li>The authorised scope. 030 * </ul> 031 * 032 * <p>All other parameters are optional or have suitable defaults. 033 */ 034@Immutable 035public class PasswordGrantAuthorization extends SubjectAuthorization { 036 037 038 /** 039 * Controls the authorisation lifetime, {@code true} for a long-lived 040 * (implies persistence), {@code false} for a short-lived (transient). 041 */ 042 private final boolean longLived; 043 044 045 /** 046 * The refresh token specification. 047 */ 048 private final RefreshTokenSpec refreshTokenSpec; 049 050 051 /** 052 * Creates a new OAuth 2.0 - only authorisation for a password grant. 053 * 054 * @param subject The subject (end-user) identifier. Must not 055 * be {@code null}. 056 * @param scope The authorised scope values. Must not be 057 * {@code null}. 058 */ 059 public PasswordGrantAuthorization(final Subject subject, 060 final Scope scope) { 061 062 this (subject, null, null, null, scope, null, false, AccessTokenSpec.DEFAULT, RefreshTokenSpec.DEFAULT, 063 IDTokenSpec.NONE, ClaimsSpec.NONE, null); 064 } 065 066 067 /** 068 * Creates a new OAuth 2.0 - only authorisation for a password grant. 069 * 070 * @param subject The subject (end-user) identifier. Must not 071 * be {@code null}. 072 * @param scope The authorised scope values. Must not be 073 * {@code null}. 074 * @param audList Explicit list of audiences for the access 075 * token, {@code null} if not specified. 076 * @param longLived Controls the authorisation lifetime, 077 * {@code true} for a long-lived (implies 078 * persistence), {@code false} for a 079 * short-lived (transient). 080 * @param accessTokenSpec The access token specification. Must not 081 * be {@code null}. 082 * @param refreshTokenSpec The refresh token specification. Must not 083 * be {@code null}. 084 * @param data Additional data as a JSON object, 085 * {@code null} if not specified. 086 */ 087 public PasswordGrantAuthorization(final Subject subject, 088 final Scope scope, 089 final @Nullable List<Audience> audList, 090 final boolean longLived, 091 final AccessTokenSpec accessTokenSpec, 092 final RefreshTokenSpec refreshTokenSpec, 093 final @Nullable JSONObject data) { 094 095 this (subject, null, null, null, scope, audList, longLived, accessTokenSpec, refreshTokenSpec, 096 IDTokenSpec.NONE, ClaimsSpec.NONE, data); 097 } 098 099 100 /** 101 * Creates a new OpenID Connect / OAuth 2.0 authorisation for a 102 * password grant. 103 * 104 * @param subject The subject (end-user) identifier. Must not 105 * be {@code null}. 106 * @param authTime The time of the subject authentication. If 107 * {@code null} it will be set to now. 108 * Applies only if an ID token is issued. 109 * @param acr The Authentication Context Class Reference 110 * (ACR), {@code null} if not specified. 111 * Applies only if an ID token is issued. 112 * @param amrList The Authentication Methods Reference (AMR) 113 * list, {@code null} if not specified. Applies 114 * only if an ID token is issued. 115 * @param scope The authorised scope values. Must not be 116 * {@code null}. 117 * @param audList Explicit list of audiences for the access 118 * token, {@code null} if not specified. 119 * @param longLived Controls the authorisation lifetime. 120 * {@code true} for a long-lived (implies 121 * persistence), {@code false} for a 122 * short-lived (transient). 123 * @param accessTokenSpec The access token specification. Must not be 124 * {@code null}. 125 * @param refreshTokenSpec The refresh token specification. Must not be 126 * {@code null}. 127 * @param idTokenSpec The ID token specification. Must not be 128 * {@code null}. 129 * @param claimsSpec The OpenID claims specification. 130 * @param data Additional data as a JSON object, 131 * {@code null} if not specified. 132 */ 133 @Deprecated 134 public PasswordGrantAuthorization(final Subject subject, 135 final @Nullable Date authTime, 136 final @Nullable ACR acr, 137 final @Nullable List<AMR> amrList, 138 final Scope scope, 139 final @Nullable List<Audience> audList, 140 final boolean longLived, 141 final AccessTokenSpec accessTokenSpec, 142 final RefreshTokenSpec refreshTokenSpec, 143 final IDTokenSpec idTokenSpec, 144 final ClaimsSpec claimsSpec, 145 final @Nullable JSONObject data) { 146 147 this( 148 subject, 149 scope, 150 longLived, 151 new AccessTokenSpec(accessTokenSpec.getLifetime(), audList, accessTokenSpec.getEncoding(), accessTokenSpec.getImpersonatedSubject(), accessTokenSpec.encrypt(), accessTokenSpec.getSubjectType()), 152 refreshTokenSpec, 153 new IDTokenSpec(idTokenSpec.issue(), idTokenSpec.getLifetime(), authTime, acr, amrList, idTokenSpec.getImpersonatedSubject()), 154 claimsSpec, 155 data); 156 } 157 158 159 /** 160 * Creates a new OpenID Connect / OAuth 2.0 authorisation for a 161 * password grant. 162 * 163 * @param subject The subject (end-user) identifier. Must not 164 * be {@code null}. 165 * @param scope The authorised scope values. Must not be 166 * {@code null}. 167 * @param longLived Controls the authorisation lifetime. 168 * {@code true} for a long-lived (implies 169 * persistence), {@code false} for a 170 * short-lived (transient). 171 * @param accessTokenSpec The access token specification. Must not be 172 * {@code null}. 173 * @param refreshTokenSpec The refresh token specification. Must not be 174 * {@code null}. 175 * @param idTokenSpec The ID token specification. Must not be 176 * {@code null}. 177 * @param claimsSpec The OpenID claims specification. 178 * @param data Additional data as a JSON object, 179 * {@code null} if not specified. 180 */ 181 public PasswordGrantAuthorization(final Subject subject, 182 final Scope scope, 183 final boolean longLived, 184 final AccessTokenSpec accessTokenSpec, 185 final RefreshTokenSpec refreshTokenSpec, 186 final IDTokenSpec idTokenSpec, 187 final ClaimsSpec claimsSpec, 188 final @Nullable JSONObject data) { 189 190 super(subject, scope, accessTokenSpec, idTokenSpec, claimsSpec, data); 191 192 this.longLived = longLived; 193 194 if (refreshTokenSpec == null) { 195 throw new IllegalArgumentException("The refresh token specification must not be null"); 196 } 197 this.refreshTokenSpec = refreshTokenSpec; 198 } 199 200 201 /** 202 * Returns the authorisation lifetime. 203 * 204 * @return {@code true} for a long-lived authorisation (implies 205 * persistence), {@code false} for a short-lived (transient). 206 */ 207 public boolean isLongLived() { 208 209 return longLived; 210 } 211 212 213 /** 214 * Returns the refresh token specification. 215 * 216 * @return The refresh token specification. 217 */ 218 public RefreshTokenSpec getRefreshTokenSpec() { 219 220 return refreshTokenSpec; 221 } 222 223 224 @Override 225 public JSONObject toJSONObject() { 226 227 JSONObject o = super.toJSONObject(); 228 229 o.put("long_lived", longLived); 230 231 if (longLived && refreshTokenSpec.issue()) { 232 o.put("refresh_token", refreshTokenSpec.toJSONObject()); 233 } 234 235 return o; 236 } 237 238 239 /** 240 * Parses a password grant authorisation from the specified JSON 241 * object. 242 * 243 * @param jsonObject The JSON object to parse. Must not be 244 * {@code null}. 245 * 246 * @return The password grant authorisation. 247 * 248 * @throws ParseException If parsing failed. 249 */ 250 public static PasswordGrantAuthorization parse(final JSONObject jsonObject) 251 throws ParseException { 252 253 SubjectAuthorization authz = SubjectAuthorization.parse(jsonObject); 254 255 boolean longLived = false; 256 257 if (jsonObject.containsKey("long_lived")) { 258 longLived = JSONObjectUtils.getBoolean(jsonObject, "long_lived"); 259 } 260 261 RefreshTokenSpec rtSpec = new RefreshTokenSpec(); 262 263 if (longLived && jsonObject.containsKey("refresh_token")) { 264 rtSpec = RefreshTokenSpec.parse(JSONObjectUtils.getJSONObject(jsonObject, "refresh_token")); 265 } 266 267 return new PasswordGrantAuthorization( 268 authz.getSubject(), 269 authz.getScope(), 270 longLived, 271 authz.getAccessTokenSpec(), 272 rtSpec, 273 authz.getIDTokenSpec(), 274 authz.getClaimsSpec(), 275 authz.getData()); 276 } 277 278 279 /** 280 * Parses a password grant authorisation from the specified JSON 281 * object string. 282 * 283 * @param json The JSON object string to parse. Must not be 284 * {@code null}. 285 * 286 * @return The password grant authorisation. 287 * 288 * @throws ParseException If parsing failed. 289 */ 290 public static PasswordGrantAuthorization parse(final String json) 291 throws ParseException { 292 293 return parse(JSONObjectUtils.parse(json)); 294 } 295}