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