Java tutorial
/** * Copyright (C) 2015 Zalando SE (http://tech.zalando.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.zalando.stups.tokens; import java.io.File; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.concurrent.ScheduledExecutorService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.NoUniqueBeanDefinitionException; import org.springframework.context.SmartLifecycle; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.zalando.stups.tokens.config.AccessTokensBeanProperties; import org.zalando.stups.tokens.config.CircuitBreakerConfiguration; import org.zalando.stups.tokens.config.TokenConfiguration; import org.zalando.stups.tokens.mcb.MCBConfig; /** * @author jbellmann */ public class AccessTokensBean implements AccessTokens, SmartLifecycle, BeanFactoryAware { static final String OAUTH2_ACCESS_TOKENS = "OAUTH2_ACCESS_TOKENS"; private final Logger logger = LoggerFactory.getLogger(AccessTokensBean.class); protected AccessTokens accessTokensDelegate; private final AccessTokensBeanProperties accessTokensBeanProperties; private volatile boolean running = false; private List<MetricsListener> metricsListeners = new ArrayList<MetricsListener>(0); public AccessTokensBean(final AccessTokensBeanProperties accessTokensBeanProperties) { this.accessTokensBeanProperties = accessTokensBeanProperties; } @Override public String get(final Object tokenId) throws AccessTokenUnavailableException { try { return accessTokensDelegate.get(tokenId); } catch (AccessTokenUnavailableException e) { logger.error("Token unavailable for service : {}", tokenId.toString()); throw e; } } @Override public AccessToken getAccessToken(final Object tokenId) throws AccessTokenUnavailableException { try { return accessTokensDelegate.getAccessToken(tokenId); } catch (AccessTokenUnavailableException e) { logger.error("Token unavailable for service : {}", tokenId.toString()); throw e; } } @Override public void invalidate(final Object tokenId) { accessTokensDelegate.invalidate(tokenId); } protected UserCredentialsProvider getUserCredentialsProvider() { return new JsonFileBackedUserCredentialsProvider( getCredentialsFile(accessTokensBeanProperties.getUserCredentialsFilename())); } protected ClientCredentialsProvider getClientCredentialsProvider() { return new JsonFileBackedClientCredentialsProvider( getCredentialsFile(accessTokensBeanProperties.getClientCredentialsFilename())); } protected File getCredentialsFile(final String credentialsFilename) { return new File(accessTokensBeanProperties.getCredentialsDirectory(), credentialsFilename); } private BeanFactory beanFactory; @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; } public void setMetricsListeners(List<MetricsListener> metricsListeners) { Assert.notNull(metricsListeners, "metricsListeners-list should never be null"); this.metricsListeners = metricsListeners; } @Override public synchronized void start() { if (isRunning()) { return; } logger.info("starting 'accessTokensBean' ..."); AccessTokensBuilder builder = null; if (isTestingConfigured()) { logger.info("Test-Tokens will be used"); builder = new FixedTokenAccessTokenBuilder(accessTokensBeanProperties.getAccessTokenUri(), getFixedToken()); } else { // default builder = Tokens.createAccessTokensWithUri(accessTokensBeanProperties.getAccessTokenUri()); } builder.usingClientCredentialsProvider(getClientCredentialsProvider()); builder.usingUserCredentialsProvider(getUserCredentialsProvider()); if (accessTokensBeanProperties.getTokenInfoUri() != null) { builder.tokenInfoUri(accessTokensBeanProperties.getTokenInfoUri()); } configureTokenRefresherCircuitBreaker(builder); configureTokenVerifierCircuitBreaker(builder); if (!metricsListeners.isEmpty()) { builder.metricsListener(new CompositeMetricsListener(metricsListeners)); } configureScheduler(builder); for (TokenConfiguration tc : accessTokensBeanProperties.getTokenConfigurationList()) { logger.info("configure scopes for service {}", tc.getTokenId()); AccessTokenConfiguration configuration = builder.manageToken(tc.getTokenId()); configuration.addScopes(new HashSet<Object>(tc.getScopes())); } // percentages builder.refreshPercentLeft(accessTokensBeanProperties.getRefreshPercentLeft()); builder.warnPercentLeft(accessTokensBeanProperties.getWarnPercentLeft()); // scheduling builder.schedulingPeriod(accessTokensBeanProperties.getRefresherSchedulingPeriod()); builder.schedulingTimeUnit(accessTokensBeanProperties.getRefresherSchedulingTimeUnit()); // tokenVerifier builder.tokenVerifierSchedulingPeriod(accessTokensBeanProperties.getVerifierSchedulingPeriod()); builder.tokenVerifierSchedulingTimeUnit(accessTokensBeanProperties.getVerifierSchedulingTimeUnit()); logger.info("Start 'accessTokenRefresher' ..."); accessTokensDelegate = builder.start(); running = true; logger.info("'accessTokenRefresher' started."); logger.info("'accessTokensBean' started."); } // @formatter:off protected void configureTokenRefresherCircuitBreaker(AccessTokensBuilder builder) { CircuitBreakerConfiguration cbc = accessTokensBeanProperties.getRefresherCircuitBreaker(); MCBConfig.Builder configBuilder = new MCBConfig.Builder().withErrorThreshold(cbc.getErrorThreshold()) .withTimeout(cbc.getTimeout()).withMaxMulti(cbc.getMaxMulti()).withTimeUnit(cbc.getTimeUnit()); if (StringUtils.hasText(cbc.getName())) { configBuilder = configBuilder.withName(cbc.getName()); } builder.tokenRefresherMcbConfig(configBuilder.build()); } protected void configureTokenVerifierCircuitBreaker(AccessTokensBuilder builder) { CircuitBreakerConfiguration cbc = accessTokensBeanProperties.getVerifierCircuitBreaker(); MCBConfig.Builder configBuilder = new MCBConfig.Builder().withErrorThreshold(cbc.getErrorThreshold()) .withTimeout(cbc.getTimeout()).withMaxMulti(cbc.getMaxMulti()).withTimeUnit(cbc.getTimeUnit()); if (StringUtils.hasText(cbc.getName())) { configBuilder = configBuilder.withName(cbc.getName()); } builder.tokenVerifierMcbConfig(configBuilder.build()); } // @formatter:on protected void configureScheduler(AccessTokensBuilder builder) { if (accessTokensBeanProperties.isUseExistingScheduler()) { ScheduledExecutorService scheduledExecutorService = null; try { scheduledExecutorService = this.beanFactory.getBean(ScheduledExecutorService.class); builder.existingExecutorService(scheduledExecutorService); } catch (NoUniqueBeanDefinitionException e) { scheduledExecutorService = this.beanFactory.getBean("scheduledExecutorService", ScheduledExecutorService.class); builder.existingExecutorService(scheduledExecutorService); } catch (NoSuchBeanDefinitionException ex) { logger.warn("'useExistingScheduler' was configured to 'true', but we did not find any bean."); } } } protected final boolean isTestingConfigured() { if (StringUtils.hasText(System.getenv(OAUTH2_ACCESS_TOKENS)) && StringUtils.hasText(accessTokensBeanProperties.getTestTokens())) { logger.warn( "'Test-Tokens' configured in yaml-file as also in ENV-VARIABLE 'OAUTH2_ACCESS_TOKENS' ! CONFIGURE ONLY ONE!"); return true; } else if (StringUtils.hasText(System.getenv(OAUTH2_ACCESS_TOKENS))) { return true; } else if (StringUtils.hasText(accessTokensBeanProperties.getTestTokens())) { return true; } return false; } protected String getFixedToken() { String token = System.getenv(OAUTH2_ACCESS_TOKENS); if (StringUtils.hasText(token)) { return token; } else { return accessTokensBeanProperties.getTestTokens(); } } @Override public synchronized void stop() { if (!isRunning()) { return; } logger.info("Stop 'accessTokenRefresher' ..."); accessTokensDelegate.stop(); running = false; logger.info("'accessTokenRefresher' stopped."); } @Override public boolean isRunning() { return running; } @Override public int getPhase() { return accessTokensBeanProperties.getPhase(); } @Override public boolean isAutoStartup() { return accessTokensBeanProperties.isAutoStartup(); } @Override public void stop(final Runnable callback) { stop(); callback.run(); } }