001package com.nimbusds.openid.connect.provider.spi.grants;
002
003
004import com.nimbusds.oauth2.sdk.ParseException;
005import com.nimbusds.oauth2.sdk.util.JSONObjectUtils;
006import net.jcip.annotations.Immutable;
007import net.minidev.json.JSONObject;
008
009import java.util.Optional;
010
011
012/**
013 * Refresh token specification.
014 */
015@Immutable
016public class RefreshTokenSpec extends OptionalTokenSpec {
017
018
019        /**
020         * Default refresh token specification (no issue).
021         */
022        public static final RefreshTokenSpec DEFAULT = new RefreshTokenSpec();
023
024
025        /**
026         * The maximum idle time, in seconds. Zero means no idle time
027         * expiration.
028         */
029        private final long maxIdleTime;
030        
031        
032        /**
033         * The rotation preference.
034         */
035        private final Optional<Boolean> rotate;
036
037
038        /**
039         * Creates a new default refresh token specification (no issue).
040         */
041        public RefreshTokenSpec() {
042
043                this(false, -1L);
044        }
045
046
047        /**
048         * Creates a new refresh token specification.
049         *
050         * @param issue    Controls the refresh token issue. If {@code true}
051         *                 a refresh token must be issued (requires a
052         *                 long-lived authorisation), {@code false} to prohibit
053         *                 issue.
054         * @param lifetime The refresh token maximum lifetime, in seconds. Zero
055         *                 means no lifetime limit. Negative means not
056         *                 specified (to let the Connect2id server apply the
057         *                 default configured refresh token lifetime). Applies
058         *                 only when a refresh token is issued.
059         */
060        public RefreshTokenSpec(final boolean issue, final long lifetime) {
061
062                this(issue, lifetime, Optional.empty());
063        }
064
065
066        /**
067         * Creates a new refresh token specification.
068         *
069         * @param issue    Controls the refresh token issue. If {@code true}
070         *                 a refresh token must be issued (requires a
071         *                 long-lived authorisation), {@code false} to prohibit
072         *                 issue.
073         * @param lifetime The refresh token maximum lifetime, in seconds. Zero
074         *                 means no lifetime limit. Negative means not
075         *                 specified (to let the Connect2id server apply the
076         *                 default configured refresh token lifetime). Applies
077         *                 only when a refresh token is issued.
078         * @param rotate   The optional rotation preference, if none the
079         *                 default refresh token rotation policy will apply.
080         */
081        public RefreshTokenSpec(final boolean issue, final long lifetime, final Optional<Boolean> rotate) {
082
083                this(issue, lifetime, 0L, rotate);
084        }
085
086
087        /**
088         * Creates a new refresh token specification.
089         *
090         * @param issue       Controls the refresh token issue. If {@code true}
091         *                    a refresh token must be issued (requires a
092         *                    long-lived authorisation), {@code false} to
093         *                    prohibit issue.
094         * @param lifetime    The refresh token maximum lifetime, in seconds.
095         *                    Zero means no lifetime limit. Negative means not
096         *                    specified (to let the Connect2id server apply the
097         *                    default configured refresh token lifetime).
098         *                    Applies only when a refresh token is issued.
099         * @param maxIdleTime The refresh token maximum idle time, in seconds.
100         *                    Zero means no idle time expiration.
101         * @param rotate      The optional rotation preference, if none the
102         *                    default refresh token rotation policy will apply.
103         */
104        public RefreshTokenSpec(final boolean issue,
105                                final long lifetime,
106                                final long maxIdleTime,
107                                final Optional<Boolean> rotate) {
108
109                super(issue, lifetime, null, null);
110                this.maxIdleTime = maxIdleTime;
111                this.rotate = rotate;
112        }
113
114
115        /**
116         * Returns the refresh token maximum idle time.
117         *
118         * @return The maximum idle time, in seconds. Zero means no idle time
119         *         expiration.
120         */
121        public long getMaxIdleTime() {
122                return maxIdleTime;
123        }
124
125
126        /**
127         * Returns the optional refresh token rotation preference.
128         *
129         * @return The rotation preference, if none the default refresh token
130         *         rotation policy will apply.
131         */
132        public Optional<Boolean> getRotate() {
133                return rotate;
134        }
135        
136        
137        @Override
138        public JSONObject toJSONObject() {
139                
140                JSONObject o = super.toJSONObject();
141                if (maxIdleTime > 0L) {
142                        o.put("max_idle", maxIdleTime);
143                }
144                rotate.ifPresent(aBoolean -> o.put("rotate", aBoolean));
145                return o;
146        }
147        
148        
149        /**
150         * Parses a refresh token specification from the specified JSON object.
151         *
152         * @param o The JSON object. Must not be {@code null}.
153         *
154         * @return The refresh token specification.
155         *
156         * @throws ParseException If parsing failed.
157         */
158        public static RefreshTokenSpec parse(final JSONObject o)
159                throws ParseException {
160                
161                OptionalTokenSpec optionalTokenSpec = OptionalTokenSpec.parse(o);
162
163                long maxIdleTime = 0L;
164                if (o.containsKey("max_idle")) {
165                        maxIdleTime = JSONObjectUtils.getLong(o, "max_idle");
166                }
167                
168                Optional<Boolean> rotate;
169                if (o.get("rotate") != null) {
170                        rotate = Optional.of(JSONObjectUtils.getBoolean(o, "rotate"));
171                } else {
172                        rotate = Optional.empty();
173                }
174                
175                return new RefreshTokenSpec(
176                        optionalTokenSpec.issue(),
177                        optionalTokenSpec.getLifetime(),
178                        maxIdleTime,
179                        rotate);
180        }
181}