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