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;
009
010import com.nimbusds.oauth2.sdk.ParseException;
011import com.nimbusds.oauth2.sdk.id.Audience;
012import com.nimbusds.oauth2.sdk.id.Subject;
013import com.nimbusds.oauth2.sdk.util.CollectionUtils;
014import com.nimbusds.oauth2.sdk.util.JSONObjectUtils;
015
016
017/**
018 * Base token specification.
019 */
020@Immutable
021public class TokenSpec {
022
023
024        /**
025         * The token lifetime, in seconds. For access tokens zero and negative
026         * implies not specified (to let the Connect2id server apply the
027         * default configured access token lifetime). For refresh tokens zero
028         * implies permanent (no expiration) and negative not specified (to let
029         * the Connect2id server apply the default configured refresh token
030         * lifetime).
031         */
032        private final long lifetime;
033
034
035        /**
036         * Explicit list of audiences for the token, {@code null} if none.
037         */
038        private final List<Audience> audList;
039
040
041        /**
042         * The subject in impersonation and delegation cases, {@code null} if
043         * not applicable.
044         */
045        private final Subject impersonatedSubject;
046
047
048        /**
049         * Creates a new token specification. No explicit token audience is
050         * specified. No subject in impersonation and delegation cases is
051         * specified.
052         *
053         * @param lifetime The token lifetime, in seconds. For access tokens
054         *                 zero and negative implies not specified (to let the
055         *                 Connect2id server apply the default configured
056         *                 access token lifetime). For refresh tokens zero
057         *                 implies permanent (no expiration) and negative not
058         *                 specified (to let the Connect2id server apply the
059         *                 default configured refresh token lifetime).
060         */
061        public TokenSpec(final long lifetime) {
062
063                this(lifetime, null, null);
064        }
065
066
067        /**
068         * Creates a new token specification.
069         *
070         * @param lifetime            The token lifetime, in seconds. For
071         *                            access tokens zero and negative implies
072         *                            not specified (to let the Connect2id
073         *                            server apply the default configured
074         *                            access token lifetime). For refresh
075         *                            tokens zero implies permanent (no
076         *                            expiration) and negative not specified
077         *                            (to let the Connect2id server apply the
078         *                            default configured refresh token
079         *                            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 List<Audience>  audList, final 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 implies not specified (to let the Connect2id server
099         *         apply the default configured access token lifetime). For
100         *         refresh tokens zero implies permanent (no expiration) and
101         *         negative not specified (to let the Connect2id server apply
102         *         the 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 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 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}