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}