001package com.nimbusds.openid.connect.provider.spi.grants; 002 003 004import java.util.ArrayList; 005import java.util.Date; 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.id.Subject; 013import com.nimbusds.oauth2.sdk.util.CollectionUtils; 014import com.nimbusds.oauth2.sdk.util.JSONObjectUtils; 015import com.nimbusds.openid.connect.sdk.claims.ACR; 016import com.nimbusds.openid.connect.sdk.claims.AMR; 017 018 019/** 020 * Identity (ID) token specification. 021 */ 022@Immutable 023public class IDTokenSpec extends OptionalTokenSpec { 024 025 026 /** 027 * None (no issue) ID token specification. 028 */ 029 public static final IDTokenSpec NONE = new IDTokenSpec(); 030 031 032 /** 033 * The time of the subject authentication. If {@code null} it will be 034 * set to now. 035 */ 036 private final Date authTime; 037 038 039 /** 040 * The Authentication Context Class Reference (ACR), {@code null} if 041 * not specified. 042 */ 043 private final ACR acr; 044 045 046 /** 047 * The Authentication Methods Reference (AMR) list, {@code null} if not 048 * specified. 049 */ 050 private final List<AMR> amrList; 051 052 053 /** 054 * Creates a new default ID token specification (no issue). 055 */ 056 public IDTokenSpec() { 057 058 this(false, 0L, null, null, null, null); 059 } 060 061 062 /** 063 * Creates a new ID token specification. 064 * 065 * @param issue Controls the ID token issue. If 066 * {@code true} an ID token must be issued, 067 * {@code false} to prohibit issue. 068 * @param lifetime The ID token lifetime, in seconds, zero 069 * if not specified (to let the Connect2id 070 * server apply the default configured 071 * lifetime for ID tokens). 072 * @param impersonatedSubject The subject in impersonation and 073 * delegation cases, {@code null} if not 074 * applicable. 075 */ 076 public IDTokenSpec(final boolean issue, 077 long lifetime, 078 final Subject impersonatedSubject) { 079 080 this(issue, lifetime, null, null, null, impersonatedSubject); 081 } 082 083 084 /** 085 * Creates a new ID token specification. 086 * 087 * @param issue Controls the ID token issue. If 088 * {@code true} an ID token must be issued, 089 * {@code false} to prohibit issue. 090 * @param lifetime The ID token lifetime, in seconds, zero 091 * if not specified (to let the Connect2id 092 * server apply the default configured 093 * lifetime for ID tokens). 094 * @param authTime The time of the subject authentication. 095 * If {@code null} it will be set to now. 096 * Applies only if an ID token is issued. 097 * @param acr The Authentication Context Class 098 * Reference (ACR), {@code null} if not 099 * specified. Applies only if an ID token is 100 * issued. 101 * @param amrList The Authentication Methods Reference 102 * (AMR) list, {@code null} if not 103 * specified. Applies only if an ID token is 104 * issued. 105 * @param impersonatedSubject The subject in impersonation and 106 * delegation cases, {@code null} if not 107 * applicable. 108 */ 109 public IDTokenSpec(final boolean issue, 110 final long lifetime, 111 final Date authTime, 112 final ACR acr, 113 final List<AMR> amrList, 114 final Subject impersonatedSubject) { 115 116 super(issue, lifetime, null, impersonatedSubject); 117 118 if (issue) { 119 // Applies only if a token is issued 120 this.authTime = authTime; 121 this.acr = acr; 122 this.amrList = amrList; 123 } else { 124 this.authTime = null; 125 this.acr = null; 126 this.amrList = null; 127 } 128 } 129 130 131 /** 132 * Returns the time of the subject authentication. 133 * 134 * @return The time of the subject authentication. If {@code null} it 135 * will be set to now. Applies only if an ID token is issued. 136 */ 137 public Date getAuthTime() { 138 139 return authTime; 140 } 141 142 143 /** 144 * Returns the Authentication Context Class Reference (ACR). 145 * 146 * @return The Authentication Context Class Reference (ACR), 147 * {@code null} if not specified. Applies only if an ID token 148 * is issued. 149 */ 150 public ACR getACR() { 151 152 return acr; 153 } 154 155 156 /** 157 * Returns The Authentication Methods Reference (AMR) list. 158 * 159 * @return The Authentication Methods Reference (AMR) list, 160 * {@code null} if not specified. Applies only if an ID token 161 * is issued. 162 */ 163 public List<AMR> getAMRList() { 164 165 return amrList; 166 } 167 168 169 @Override 170 public JSONObject toJSONObject() { 171 172 JSONObject o = super.toJSONObject(); 173 174 if (getLifetime() <= 0) { 175 // Implies not specified - remove 176 o.remove("lifetime"); 177 } 178 179 if (authTime != null) { 180 o.put("auth_time", authTime.getTime() / 1000L); 181 } 182 183 if (acr != null) { 184 o.put("acr", acr.getValue()); 185 } 186 187 if (CollectionUtils.isNotEmpty(amrList)) { 188 189 List<String> sl = new ArrayList<>(amrList.size()); 190 191 for (AMR amr: amrList) { 192 sl.add(amr.getValue()); 193 } 194 195 o.put("amr", sl); 196 } 197 198 return o; 199 } 200 201 202 /** 203 * Parses an ID token specification from the specified JSON object. 204 * 205 * @param jsonObject The JSON object. Must not be {@code null}. 206 * 207 * @return The ID token specification. 208 * 209 * @throws ParseException If parsing failed. 210 */ 211 public static IDTokenSpec parse(final JSONObject jsonObject) 212 throws ParseException { 213 214 OptionalTokenSpec optionalTokenSpec = OptionalTokenSpec.parse(jsonObject); 215 216 // Adjust lifetime value for not specified (0) 217 long lifetime = optionalTokenSpec.getLifetime() > 0 ? optionalTokenSpec.getLifetime() : 0; 218 219 Date authTime = null; 220 221 if (jsonObject.containsKey("auth_time")) { 222 authTime = new Date(JSONObjectUtils.getLong(jsonObject, "auth_time") * 1000L); 223 } 224 225 ACR acr = null; 226 227 if (jsonObject.containsKey("acr")) { 228 acr = new ACR(JSONObjectUtils.getString(jsonObject, "acr")); 229 } 230 231 List<AMR> amrList = null; 232 233 if (jsonObject.containsKey("amr")) { 234 String[] sa = JSONObjectUtils.getStringArray(jsonObject, "amr"); 235 amrList = new ArrayList<>(sa.length); 236 for (String s: sa) { 237 amrList.add(new AMR(s)); 238 } 239 } 240 241 return new IDTokenSpec( 242 optionalTokenSpec.issue(), 243 lifetime, 244 authTime, 245 acr, 246 amrList, 247 optionalTokenSpec.getImpersonatedSubject()); 248 } 249}