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