All Downloads are FREE. Search and download functionalities are using the official Maven repository.

redis.clients.authentication.core.TokenManager Maven / Gradle / Ivy

package redis.clients.authentication.core;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TokenManager {

    private TokenManagerConfig tokenManagerConfig;
    private IdentityProvider identityProvider;
    private TokenListener listener;
    private ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
    private ExecutorService executor = Executors.newSingleThreadExecutor();
    private boolean stopped = false;
    private ScheduledFuture scheduledTask;
    private int numberOfRetries = 0;
    private Exception lastException;
    private Logger logger = LoggerFactory.getLogger(getClass());
    private Token currentToken = null;
    private AtomicBoolean started = new AtomicBoolean(false);

    public TokenManager(IdentityProvider identityProvider, TokenManagerConfig tokenManagerConfig) {
        this.identityProvider = identityProvider;
        this.tokenManagerConfig = tokenManagerConfig;
    }

    public void start(TokenListener listener, boolean blockForInitialToken) {

        if (!started.compareAndSet(false, true)) {
            throw new AuthXException("Token manager already started!");
        }
        this.listener = listener;
        ScheduledFuture currentTask = scheduleNext(0);
        scheduledTask = currentTask;
        if (blockForInitialToken) {
            try {
                while (currentTask.get() == null) {
                    currentTask = scheduledTask;
                }
            } catch (RuntimeException e) {
                throw e;
            } catch (Exception e) {
                throw new TokenRequestException(unwrap(e), lastException);
            }
        }
    }

    public void stop() {
        stopped = true;
        scheduledTask.cancel(true);
        scheduler.shutdown();
        executor.shutdown();
    }

    public TokenManagerConfig getConfig() {
        return tokenManagerConfig;
    }

    private ScheduledFuture scheduleNext(long delay) {
        // Schedule the task to run after the calculated delay
        return scheduler.schedule(() -> renewToken(), delay, TimeUnit.MILLISECONDS);
    }

    protected Token renewToken() {
        if (stopped) {
            return null;
        }
        Token newToken = null;
        try {
            Future requestResult = executor.submit(() -> requestToken());
            newToken = requestResult.get(tokenManagerConfig.getTokenRequestExecTimeoutInMs(),
                TimeUnit.MILLISECONDS);
            currentToken = newToken;
            long delay = calculateRenewalDelay(newToken.getExpiresAt(), newToken.getReceivedAt());
            scheduledTask = scheduleNext(delay);
            listener.onTokenRenewed(newToken);
            return newToken;
        } catch (Exception e) {
            if (numberOfRetries < tokenManagerConfig.getRetryPolicy().getMaxAttempts()) {
                numberOfRetries++;
                scheduledTask = scheduleNext(tokenManagerConfig.getRetryPolicy().getdelayInMs());
            } else {
                TokenRequestException tre = new TokenRequestException(unwrap(e), lastException);
                listener.onError(tre);
                throw tre;
            }
        }
        return null;
    }

    protected Token requestToken() {
        lastException = null;
        try {
            return identityProvider.requestToken();
        } catch (Exception e) {
            lastException = e;
            logger.error("Request to identity provider failed with message: " + e.getMessage(), e);
            throw e;
        }
    }

    private Throwable unwrap(Exception e) {
        return (e instanceof ExecutionException) ? e.getCause() : e;
    }

    public Token getCurrentToken() {
        return currentToken;
    }

    public long calculateRenewalDelay(long expireDate, long issueDate) {
        long ttlLowerRefresh = ttlForLowerRefresh(expireDate);
        long ttlRatioRefresh = ttlForRatioRefresh(expireDate, issueDate);
        long delay = Math.min(ttlLowerRefresh, ttlRatioRefresh);

        return delay < 0 ? 0 : delay;
    }

    public long ttlForLowerRefresh(long expireDate) {
        return expireDate - tokenManagerConfig.getLowerRefreshBoundMillis()
                - System.currentTimeMillis();
    }

    protected long ttlForRatioRefresh(long expireDate, long issueDate) {
        long validDuration = expireDate - issueDate;
        long refreshBefore = validDuration
                - (long) (validDuration * tokenManagerConfig.getExpirationRefreshRatio());
        return expireDate - refreshBefore - System.currentTimeMillis();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy