001package com.nimbusds.openid.connect.provider.spi.grants; 002 003 004import java.util.ArrayList; 005import java.util.List; 006 007import com.nimbusds.oauth2.sdk.ParseException; 008import com.nimbusds.oauth2.sdk.id.Audience; 009import com.nimbusds.oauth2.sdk.id.Subject; 010import com.nimbusds.oauth2.sdk.util.JSONObjectUtils; 011import net.jcip.annotations.Immutable; 012import net.minidev.json.JSONObject; 013import org.apache.commons.collections4.CollectionUtils; 014 015 016/** 017 * Base token specification. 018 */ 019@Immutable 020public class TokenSpec { 021 022 023 /** 024 * The token lifetime, in seconds. Zero if permanent / not specified. 025 */ 026 private final long lifetime; 027 028 029 /** 030 * Explicit list of audiences for the token, {@code null} if none. 031 */ 032 private final List<Audience> audList; 033 034 035 /** 036 * The subject in impersonation and delegation cases, {@code null} if 037 * not applicable. 038 */ 039 private final Subject impersonatedSubject; 040 041 042 /** 043 * Creates a new token specification. No explicit token audience is 044 * specified. No subject in impersonation and delegation cases is 045 * specified. 046 * 047 * @param lifetime The token lifetime, in seconds. Zero implies 048 * permanent or not specified (to let the Connect2id 049 * server apply the default configured lifetime), 050 * depending on the token type. Must not be a negative 051 * integer. 052 */ 053 public TokenSpec(final long lifetime) { 054 055 this(lifetime, null, null); 056 } 057 058 059 /** 060 * Creates a new token specification. 061 * 062 * @param lifetime The token lifetime, in seconds. Zero 063 * implies permanent or not specified (to 064 * let the Connect2id server apply the 065 * default configured lifetime), depending 066 * on the token type. Must not be a negative 067 * integer. 068 * @param audList Explicit list of audiences for the token, 069 * {@code null} if not specified. 070 * @param impersonatedSubject The subject in impersonation and 071 * delegation cases, {@code null} if not 072 * applicable. 073 */ 074 public TokenSpec(final long lifetime, final List<Audience> audList, final Subject impersonatedSubject) { 075 076 if (lifetime < 0L) { 077 throw new IllegalArgumentException("The token lifetime must not be negative"); 078 } 079 080 this.lifetime = lifetime; 081 082 this.audList = audList; 083 084 this.impersonatedSubject = impersonatedSubject; 085 } 086 087 088 /** 089 * Returns the token lifetime. 090 * 091 * @return The token lifetime, in seconds. Zero implies permanent or 092 * not specified (to let the Connect2id server apply the 093 * default configured lifetime), depending on the token type. 094 */ 095 public long getLifetime() { 096 097 return lifetime; 098 } 099 100 101 /** 102 * Returns the explicit list of audiences for the token. 103 * 104 * @return The explicit list of audiences for the token, {@code null} 105 * if not specified. 106 */ 107 public List<Audience> getAudience() { 108 109 return audList; 110 } 111 112 113 /** 114 * Returns the subject in impersonation and delegation cases. 115 * 116 * @return The subject in impersonation and delegation cases, 117 * {@code null} if not applicable. 118 */ 119 public Subject getImpersonatedSubject() { 120 121 return impersonatedSubject; 122 } 123 124 125 /** 126 * Returns a JSON object representation of this token specification. 127 * 128 * @return The JSON object. 129 */ 130 public JSONObject toJSONObject() { 131 132 JSONObject o = new JSONObject(); 133 134 if (lifetime > 0L) { 135 o.put("lifetime", lifetime); 136 } 137 138 if (CollectionUtils.isNotEmpty(audList)) { 139 140 List<String> sl = new ArrayList<>(audList.size()); 141 142 for (Audience aud: audList) { 143 sl.add(aud.getValue()); 144 } 145 146 o.put("audience", sl); 147 } 148 149 if (impersonatedSubject != null) { 150 o.put("impersonated_sub", impersonatedSubject.getValue()); 151 } 152 153 return o; 154 } 155 156 157 @Override 158 public String toString() { 159 160 return toJSONObject().toJSONString(); 161 } 162 163 164 /** 165 * Parses a token specification from the specified JSON object. 166 * 167 * @param jsonObject The JSON object. Must not be {@code null}. 168 * 169 * @return The token specification. 170 * 171 * @throws ParseException If parsing failed. 172 */ 173 public static TokenSpec parse(final JSONObject jsonObject) 174 throws ParseException { 175 176 long lifetime = 0L; 177 178 if (jsonObject.containsKey("lifetime")) { 179 lifetime = JSONObjectUtils.getLong(jsonObject, "lifetime"); 180 } 181 182 List<Audience> audList = null; 183 184 if (jsonObject.containsKey("audience")) { 185 String[] sa = JSONObjectUtils.getStringArray(jsonObject, "audience"); 186 audList = new ArrayList<>(sa.length); 187 for (String s: sa) { 188 audList.add(new Audience(s)); 189 } 190 } 191 192 Subject imersonatedSub = null; 193 194 if (jsonObject.containsKey("impersonated_sub")) { 195 try { 196 imersonatedSub = new Subject(JSONObjectUtils.getString(jsonObject, "impersonated_sub")); 197 } catch (IllegalArgumentException e) { 198 // On invalid subject 199 throw new ParseException(e.getMessage(), e); 200 } 201 } 202 203 return new TokenSpec(lifetime, audList, imersonatedSub); 204 } 205}