001package com.nimbusds.openid.connect.provider.spi.grants; 002 003 004import java.util.ArrayList; 005import java.util.Arrays; 006import java.util.List; 007 008import net.jcip.annotations.Immutable; 009import net.minidev.json.JSONObject; 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.util.CollectionUtils; 015import com.nimbusds.oauth2.sdk.util.JSONObjectUtils; 016import com.nimbusds.oauth2.sdk.util.MapUtils; 017 018 019/** 020 * Basic OAuth 2.0 authorisation produced by a {@link GrantHandler}. 021 * 022 * <p>Required authorisation details: 023 * 024 * <ul> 025 * <li>The authorised scope. 026 * </ul> 027 * 028 * <p>All other parameters are optional or have suitable defaults. 029 */ 030@Immutable 031public class GrantAuthorization { 032 033 034 /** 035 * The authorised scope values. 036 */ 037 private final Scope scope; 038 039 040 /** 041 * The access token specification. 042 */ 043 private final AccessTokenSpec accessTokenSpec; 044 045 046 /** 047 * Optional authorisation data as a JSON object, {@code null} if not 048 * specified. 049 */ 050 private final JSONObject data; 051 052 053 /** 054 * Creates a new basic authorisation. 055 * 056 * @param scope The authorised scope values. Must not be {@code null}. 057 */ 058 public GrantAuthorization(final Scope scope) { 059 060 this(scope, AccessTokenSpec.DEFAULT, null); 061 } 062 063 064 /** 065 * Creates a new basic authorisation. 066 * 067 * @param scope The authorised scope values. Must not be 068 * {@code null}. 069 * @param accessTokenSpec The access token specification. Must not be 070 * {@code null}. 071 * @param data Additional data as a JSON object, 072 * {@code null} if not specified. 073 */ 074 public GrantAuthorization(final Scope scope, 075 final AccessTokenSpec accessTokenSpec, 076 final JSONObject data) { 077 078 if (scope == null) { 079 throw new IllegalArgumentException("The scope must not be null"); 080 } 081 082 this.scope = scope; 083 084 if (accessTokenSpec == null) { 085 throw new IllegalArgumentException("The access token specification must not be null"); 086 } 087 088 this.accessTokenSpec = accessTokenSpec; 089 090 this.data = data; 091 } 092 093 094 /** 095 * Creates a new basic authorisation. 096 * 097 * @param scope The authorised scope values. Must not be 098 * {@code null}. 099 * @param audList Explicit list of audiences for the access 100 * token, {@code null} if not specified. 101 * @param accessTokenSpec The access token specification. Must not be 102 * {@code null}. 103 * @param data Additional data as a JSON object, 104 * {@code null} if not specified. 105 */ 106 @Deprecated 107 public GrantAuthorization(final Scope scope, 108 final List<Audience> audList, 109 final AccessTokenSpec accessTokenSpec, 110 final JSONObject data) { 111 112 this(scope, 113 new AccessTokenSpec( 114 accessTokenSpec.getLifetime(), 115 audList, // override with top-level parameter, backward compat API 116 accessTokenSpec.getEncoding(), 117 accessTokenSpec.getImpersonatedSubject(), 118 accessTokenSpec.encrypt(), 119 accessTokenSpec.getSubjectType()), 120 data); 121 } 122 123 124 /** 125 * Returns the authorised scope values. 126 * 127 * @return The authorised scope values. 128 */ 129 public Scope getScope() { 130 131 return scope; 132 } 133 134 135 /** 136 * Returns the explicit list of audiences for the access token. 137 * 138 * @return The explicit list of audiences for the access token, 139 * {@code null} if not specified. 140 */ 141 @Deprecated 142 public List<Audience> getAudience() { 143 144 return getAccessTokenSpec().getAudience(); 145 } 146 147 148 /** 149 * Returns the access token specification. 150 * 151 * @return The access token specification. 152 */ 153 public AccessTokenSpec getAccessTokenSpec() { 154 155 return accessTokenSpec; 156 } 157 158 159 /** 160 * Returns the additional data as a JSON object. 161 * 162 * @return The additional data, {@code null} if not specified. 163 */ 164 public JSONObject getData() { 165 166 return data; 167 } 168 169 170 /** 171 * Returns a JSON object representation of this authorisation. 172 * 173 * @return The JSON object representation. 174 */ 175 public JSONObject toJSONObject() { 176 177 JSONObject o = new JSONObject(); 178 179 o.put("scope", scope.toStringList()); 180 181 JSONObject accessTokenSpecJSONObject = accessTokenSpec.toJSONObject(); 182 183 // Backward API compat 184 // TODO remove in future major server version, deprecated in server v12.0 185 if (CollectionUtils.isNotEmpty(getAccessTokenSpec().getAudience())) { 186 o.put("audience", accessTokenSpecJSONObject.get("audience")); 187 } 188 189 o.put("access_token", accessTokenSpecJSONObject); 190 191 if (MapUtils.isNotEmpty(data)) { 192 o.put("data", data); 193 } 194 195 return o; 196 } 197 198 199 /** 200 * Parses a basic authorisation from the specified JSON object. 201 * 202 * @param jsonObject The JSON object to parse. Must not be 203 * {@code null}. 204 * 205 * @return The basic authorisation. 206 * 207 * @throws ParseException If parsing failed. 208 */ 209 public static GrantAuthorization parse(final JSONObject jsonObject) 210 throws ParseException { 211 212 Scope scope = Scope.parse(Arrays.asList(JSONObjectUtils.getStringArray(jsonObject, "scope"))); 213 214 // Backward API compat 215 List<Audience> topLevelAudList = null; 216 if (jsonObject.containsKey("audience")) { 217 String[] sa = JSONObjectUtils.getStringArray(jsonObject, "audience"); 218 topLevelAudList = new ArrayList<>(sa.length); 219 for (String s: sa) { 220 topLevelAudList.add(new Audience(s)); 221 } 222 } 223 224 AccessTokenSpec accessTokenSpec; 225 226 if (jsonObject.get("access_token") != null) { 227 // Parse 228 JSONObject accessTokenJSONObject = JSONObjectUtils.getJSONObject(jsonObject, "access_token"); 229 if (topLevelAudList != null) { 230 accessTokenJSONObject.put("audience", Audience.toStringList(topLevelAudList)); 231 } 232 accessTokenSpec = AccessTokenSpec.parse(accessTokenJSONObject); 233 if (topLevelAudList != null) { 234 accessTokenSpec = new AccessTokenSpec( 235 accessTokenSpec.getLifetime(), 236 topLevelAudList, // Backward API compat 237 accessTokenSpec.getEncoding(), 238 accessTokenSpec.getImpersonatedSubject(), 239 accessTokenSpec.encrypt(), 240 accessTokenSpec.getSubjectType()); 241 } 242 } else { 243 // Apply default settings 244 accessTokenSpec = new AccessTokenSpec(); 245 } 246 247 JSONObject data = null; 248 249 if (jsonObject.containsKey("data")) { 250 data = JSONObjectUtils.getJSONObject(jsonObject, "data"); 251 } 252 253 return new GrantAuthorization(scope, accessTokenSpec, data); 254 } 255 256 257 /** 258 * Parses a basic authorisation from the specified JSON object string. 259 * 260 * @param json The JSON object string to parse. Must not be 261 * {@code null}. 262 * 263 * @return The basic authorisation. 264 * 265 * @throws ParseException If parsing failed. 266 */ 267 public static GrantAuthorization parse(final String json) 268 throws ParseException { 269 270 return parse(JSONObjectUtils.parse(json)); 271 } 272}