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 public GrantAuthorization(final Scope scope, 107 final List<Audience> audList, 108 final AccessTokenSpec accessTokenSpec, 109 final JSONObject data) { 110 111 this(scope, 112 new AccessTokenSpec( 113 accessTokenSpec.getLifetime(), 114 audList, // override with top-level parameter, backward compat API 115 accessTokenSpec.getEncoding(), 116 accessTokenSpec.encrypt()), 117 data); 118 } 119 120 121 /** 122 * Returns the authorised scope values. 123 * 124 * @return The authorised scope values. 125 */ 126 public Scope getScope() { 127 128 return scope; 129 } 130 131 132 /** 133 * Returns the explicit list of audiences for the access token. 134 * 135 * @return The explicit list of audiences for the access token, 136 * {@code null} if not specified. 137 */ 138 public List<Audience> getAudience() { 139 140 return getAccessTokenSpec().getAudience(); 141 } 142 143 144 /** 145 * Returns the access token specification. 146 * 147 * @return The access token specification. 148 */ 149 public AccessTokenSpec getAccessTokenSpec() { 150 151 return accessTokenSpec; 152 } 153 154 155 /** 156 * Returns the additional data as a JSON object. 157 * 158 * @return The additional data, {@code null} if not specified. 159 */ 160 public JSONObject getData() { 161 162 return data; 163 } 164 165 166 /** 167 * Returns a JSON object representation of this authorisation. 168 * 169 * @return The JSON object representation. 170 */ 171 public JSONObject toJSONObject() { 172 173 JSONObject o = new JSONObject(); 174 175 o.put("scope", scope.toStringList()); 176 177 JSONObject accessTokenSpecJSONObject = accessTokenSpec.toJSONObject(); 178 179 // Backward API compat 180 if (CollectionUtils.isNotEmpty(getAccessTokenSpec().getAudience())) { 181 o.put("audience", accessTokenSpecJSONObject.remove("audience")); 182 } 183 184 o.put("access_token", accessTokenSpecJSONObject); 185 186 if (MapUtils.isNotEmpty(data)) { 187 o.put("data", data); 188 } 189 190 return o; 191 } 192 193 194 /** 195 * Parses a basic authorisation from the specified JSON object. 196 * 197 * @param jsonObject The JSON object to parse. Must not be 198 * {@code null}. 199 * 200 * @return The basic authorisation. 201 * 202 * @throws ParseException If parsing failed. 203 */ 204 public static GrantAuthorization parse(final JSONObject jsonObject) 205 throws ParseException { 206 207 Scope scope = Scope.parse(Arrays.asList(JSONObjectUtils.getStringArray(jsonObject, "scope"))); 208 209 // Backward API compat 210 List<Audience> topLevelAudList = null; 211 212 if (jsonObject.containsKey("audience")) { 213 String[] sa = JSONObjectUtils.getStringArray(jsonObject, "audience"); 214 topLevelAudList = new ArrayList<>(sa.length); 215 for (String s: sa) { 216 topLevelAudList.add(new Audience(s)); 217 } 218 } 219 220 AccessTokenSpec accessTokenSpec; 221 222 if (jsonObject.containsKey("access_token")) { 223 // Parse 224 accessTokenSpec = AccessTokenSpec.parse(JSONObjectUtils.getJSONObject(jsonObject, "access_token")); 225 if (topLevelAudList != null) { 226 accessTokenSpec = new AccessTokenSpec( 227 accessTokenSpec.getLifetime(), 228 topLevelAudList, // Backward API compat 229 accessTokenSpec.getEncoding(), 230 accessTokenSpec.encrypt()); 231 } 232 } else { 233 // Apply default settings 234 accessTokenSpec = new AccessTokenSpec(); 235 } 236 237 JSONObject data = null; 238 239 if (jsonObject.containsKey("data")) { 240 data = JSONObjectUtils.getJSONObject(jsonObject, "data"); 241 } 242 243 return new GrantAuthorization(scope, accessTokenSpec, data); 244 } 245 246 247 /** 248 * Parses a basic authorisation from the specified JSON object string. 249 * 250 * @param json The JSON object string to parse. Must not be 251 * {@code null}. 252 * 253 * @return The basic authorisation. 254 * 255 * @throws ParseException If parsing failed. 256 */ 257 public static GrantAuthorization parse(final String json) 258 throws ParseException { 259 260 return parse(JSONObjectUtils.parse(json)); 261 } 262}