001/*
002 * nimbus-jose-jwt
003 *
004 * Copyright 2012-2016, Connect2id Ltd and contributors.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use
007 * this file except in compliance with the License. You may obtain a copy of the
008 * License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software distributed
013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
015 * specific language governing permissions and limitations under the License.
016 */
017
018package com.nimbusds.jose.jwk.source;
019
020
021import java.util.Date;
022import java.util.concurrent.TimeUnit;
023
024import com.nimbusds.jose.jwk.JWKSet;
025
026
027/**
028 * JSON Web Key (JWK) set cache implementation.
029 *
030 * @author Vladimir Dzhuvinov
031 * @author Sarvesh Sharma
032 * @version 2020-03-11
033 */
034public class DefaultJWKSetCache implements JWKSetCache {
035        
036        
037        /**
038         * The default lifespan for cached JWK sets (15 minutes).
039         */
040        public static final long DEFAULT_LIFESPAN_MINUTES = 15;
041
042
043        /**
044         * The default refresh time for cached JWK sets (5 minutes).
045         */
046        public static final long DEFAULT_REFRESH_TIME_MINUTES = 5;
047
048        
049        /**
050         * The lifespan of the cached JWK set, in {@link #timeUnit}s, negative
051         * means no expiration.
052         */
053        private final long lifespan;
054
055
056        /**
057         * The refresh time of the cached JWK set, in {@link #timeUnit}s,
058         * negative means no refresh time.
059         */
060        private final long refreshTime;
061
062        
063        /**
064         * The time unit, may be {@code null} if no expiration / refresh time.
065         */
066        private final TimeUnit timeUnit;
067        
068        
069        /**
070         * The cache put timestamp, negative if not specified.
071         */
072        private long putTimestamp = -1;
073        
074        
075        /**
076         * Creates a new JWK set, the default lifespan of the cached JWK set is
077         * set to 15 minutes, the refresh time to 5 minutes.
078         */
079        public DefaultJWKSetCache() {
080                
081                this(DEFAULT_LIFESPAN_MINUTES, DEFAULT_REFRESH_TIME_MINUTES, TimeUnit.MINUTES);
082        }
083        
084        
085        /**
086         * Creates a new JWK set cache.
087         *
088         * @param lifespan    The lifespan of the cached JWK set before it
089         *                    expires, negative means no expiration.
090         * @param refreshTime The time after which the cached JWK set is marked
091         *                    for refresh, negative if not specified. Should be
092         *                    shorter or equal to the lifespan.
093         * @param timeUnit    The lifespan time unit, may be {@code null} if no
094         *                    expiration or refresh time.
095         */
096        public DefaultJWKSetCache(final long lifespan, final long refreshTime, final TimeUnit timeUnit) {
097                
098                this.lifespan = lifespan;
099                this.refreshTime = refreshTime;
100
101                if ((lifespan > -1 || refreshTime > -1) && timeUnit == null) {
102                        throw new IllegalArgumentException("A time unit must be specified for non-negative lifespans or refresh times");
103                }
104                
105                this.timeUnit = timeUnit;
106        }
107        
108        
109        /**
110         * The cached JWK set, {@code null} if none.
111         */
112        private JWKSet jwkSet;
113        
114        
115        @Override
116        public void put(final JWKSet jwkSet) {
117                
118                this.jwkSet = jwkSet;
119                
120                if (jwkSet != null) {
121                        putTimestamp = new Date().getTime();
122                } else {
123                        // cache cleared
124                        putTimestamp = -1;
125                }
126        }
127        
128        
129        @Override
130        public JWKSet get() {
131                
132                if (isExpired()) {
133                        jwkSet = null; // clear
134                }
135                
136                return jwkSet;
137        }
138
139
140        @Override
141        public boolean requiresRefresh() {
142
143                return putTimestamp > -1 &&
144                        refreshTime > -1 &&
145                        new Date().getTime() > putTimestamp + TimeUnit.MILLISECONDS.convert(refreshTime, timeUnit);
146        }
147
148        
149        /**
150         * Returns the cache put timestamp.
151         *
152         * @return The cache put timestamp, negative if not specified.
153         */
154        public long getPutTimestamp() {
155                
156                return putTimestamp;
157        }
158        
159        
160        /**
161         * Returns {@code true} if the cached JWK set is expired.
162         *
163         * @return {@code true} if expired.
164         */
165        public boolean isExpired() {
166        
167                return putTimestamp > -1 &&
168                        lifespan > -1 &&
169                        new Date().getTime() > putTimestamp + TimeUnit.MILLISECONDS.convert(lifespan, timeUnit);
170        }
171        
172        
173        /**
174         * Returns the configured lifespan of the cached JWK.
175         *
176         * @param timeUnit The time unit to use.
177         *
178         * @return The configured lifespan, negative means no expiration.
179         */
180        public long getLifespan(final TimeUnit timeUnit) {
181                
182                if (lifespan < 0) {
183                        return lifespan;
184                }
185                
186                return timeUnit.convert(lifespan, timeUnit);
187        }
188
189
190        /**
191         * Returns the configured refresh time of the cached JWK.
192         *
193         * @param timeUnit The time unit to use.
194         *
195         * @return The configured refresh time, negative means no expiration.
196         */
197        public long getRefreshTime(final TimeUnit timeUnit) {
198
199                if (refreshTime < 0) {
200                        return refreshTime;
201                }
202
203                return timeUnit.convert(refreshTime, timeUnit);
204        }
205}