i am new to spring and i'm working on spring boot REST with spring security and currently I implemented JWT token. I have some questions but can't seem to find an answer to them. I tried adding a refresh token.
At first i thought i will store it in database with user, but spring security does everything automatically and i can't seem to find how to store it at a given field of table user.
So, moving on i decided i will try sticking with spring security automation and I set refresh token expiration time to 10 seconds to test if it expires, but sadly it does not work as intended - I can use refresh token for as long as I want and generate new tokens with it.
So here I have a couple of questions:
1. How do i make refresh token expire after given time? Here's my security config
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Value("${security.signing-key}")
private String signingKey;
#Value("${security.encoding-strength}")
private Integer encodingStrength;
#Value("${security.security-realm}")
private String securityRealm;
#Autowired
private UserDetailsService userDetailsService;
#Bean
#Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
#Bean
public PasswordEncoder passwordEncoder() {
PasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().httpBasic()
.realmName(securityRealm).and().csrf().disable();
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(signingKey);
return converter;
}
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
defaultTokenServices.setRefreshTokenValiditySeconds(10);
return defaultTokenServices;
}
}
Is it possible to pass refresh token to database and manually check if token is valid, because that was my first idea.
I did find an answer, just forgot to update my ticket. So here it goes, by default JwtTokenStore does not support refresh tokens. Here's JwtTokenStore source code.
So what this means, is that enabling token in settings, won't actually make it work. What i did, was create my own JWT token store that extends JwtTokenStore and write my own refresh token logic.
public class MyJwtTokenStore extends JwtTokenStore {
#Autowired
UserRepository userRepository;
public MyJwtTokenStore(JwtAccessTokenConverter jwtTokenEnhancer) {
super(jwtTokenEnhancer);
}
#Override
public void storeRefreshToken(OAuth2RefreshToken refreshToken, OAuth2Authentication authentication) {
String username = authentication.getUserAuthentication().getName();
User user = userRepository.findByEmail(username);
user.setToken(refreshToken.getValue());
userRepository.save(user);
}
#Override
public OAuth2RefreshToken readRefreshToken(String token) {
OAuth2Authentication authentication = super.readAuthentication(token);
String username = authentication.getUserAuthentication().getName();
User user = userRepository.findByEmail(username);
if (!token.equals(user.getToken())) {
return null;
}
OAuth2RefreshToken refreshToken = new DefaultOAuth2RefreshToken(token);
return refreshToken;
}
#Override
public void removeRefreshToken(OAuth2RefreshToken token) {
OAuth2Authentication authentication = super.readAuthentication(token.getValue());
String username = authentication.getUserAuthentication().getName();
User user = userRepository.findByEmail(username);
user.setToken(null);
userRepository.save(user);
}
}
After this, i just updated my TokenStore Bean
#Bean
public TokenStore tokenStore() {
MyJwtTokenStore jwtTokenStore = new MyJwtTokenStore(accessTokenConverter());
return jwtTokenStore;
// return new JwtTokenStore(accessTokenConverter());
}
And at the end I added remaining settings to my AuthorizationServerConfigurerAdapter class to support refresh token and give it time of validity.
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Value("${security.jwt.client-id}")
private String clientId;
#Value("${security.jwt.client-secret}")
private String clientSecret;
#Value("${security.jwt.grant-type}")
private String grantType;
#Value("${security.jwt.grant-type-other}")
private String grantTypeRefresh;
#Value("${security.jwt.scope-read}")
private String scopeRead;
#Value("${security.jwt.scope-write}")
private String scopeWrite = "write";
#Value("${security.jwt.resource-ids}")
private String resourceIds;
#Autowired
private TokenStore tokenStore;
#Autowired
private JwtAccessTokenConverter accessTokenConverter;
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private AppUserDetailsService userDetailsService;
#Autowired
private PasswordEncoder passwordEncoder;
#Override
public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
configurer.inMemory()
.withClient(clientId)
.secret(passwordEncoder.encode(clientSecret))
.authorizedGrantTypes(grantType, grantTypeRefresh).scopes(scopeRead, scopeWrite)
.resourceIds(resourceIds).autoApprove(false).accessTokenValiditySeconds(1800) // 30min
.refreshTokenValiditySeconds(86400); //24 hours
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
enhancerChain.setTokenEnhancers(Arrays.asList(accessTokenConverter));
endpoints.tokenStore(tokenStore).accessTokenConverter(accessTokenConverter).tokenEnhancer(enhancerChain)
.reuseRefreshTokens(false).authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
}
#Bean
public FilterRegistrationBean corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*"); // http://localhost:4200
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
}
}
Related
I'm trying to setup a simple Oauth2 Server with Spring Boot with only client_credentials flow for now, using in memory users and clients etc. Basically the most basic project so I can build on it. Haven't used Oauth2 with Spring for some time so I'm a bit stuck. I can get access tokens but it seems Spring does not actually validate the username/password sent by the client. Here are the two config classes (AuthorizationServerConfigurerAdapter, WebSecurityConfigurerAdapter):
#Configuration
#EnableAuthorizationServer
public class OAuthConfiguration extends AuthorizationServerConfigurerAdapter {
private final AuthenticationManager authenticationManager;
private final PasswordEncoder passwordEncoder;
private final UserDetailsService userService;
#Value("${jwt.signing-key}")
private String jwtSigningKey;
#Value("${jwt.accessTokenValidititySeconds}")
private int accessTokenValiditySeconds;
#Value("${jwt.refreshTokenValiditySeconds}")
private int refreshTokenValiditySeconds;
public OAuthConfiguration(AuthenticationManager authenticationManager, PasswordEncoder passwordEncoder, UserDetailsService userService) {
this.authenticationManager = authenticationManager;
this.passwordEncoder = passwordEncoder;
this.userService = userService;
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("test-client-id")
.secret(passwordEncoder.encode("test-client-secret"))
.accessTokenValiditySeconds(accessTokenValiditySeconds)
.refreshTokenValiditySeconds(refreshTokenValiditySeconds)
.authorizedGrantTypes("client_credentials")
.scopes("read", "write")
.resourceIds("api");
}
#Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.accessTokenConverter(accessTokenConverter())
.userDetailsService(userService)
.authenticationManager(authenticationManager);
}
#Bean
JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(jwtSigningKey);
return converter;
}
}
and:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
private final CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
public WebSecurityConfiguration(CustomAuthenticationEntryPoint customAuthenticationEntryPoint) {
this.customAuthenticationEntryPoint = customAuthenticationEntryPoint;
}
#Bean
public DaoAuthenticationProvider authenticationProvider(UserDetailsService userDetailsService) {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder(passwordEncoder());
provider.setUserDetailsService(userDetailsService);
return provider;
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
#Override
public UserDetailsService userDetailsServiceBean() throws Exception {
return super.userDetailsServiceBean();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user1")
.password("$2a$10$sWszOXuTlN0amQi8vXp4cerb.tJUQo.4FzLAnTCsSqChsYhlLdQWW")
.roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors().disable().csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and().exceptionHandling().authenticationEntryPoint(customAuthenticationEntryPoint).accessDeniedHandler(new CustomAccessDeniedHandler());
}
}
So I can call the "/oauth/token" endpoint with any username/password I get an access token. However the client ID and client secret are being validated.
Any help is appreciated
It's the default behaviour with grant_type client_credentials. So, you don't need to pass the username and password to the token endpoint with this grant_type. In this flow, AuthorizationServer will only validate the client Id and client secret.
POST /token
Host: authorization-server.com
grant_type=client_credentials
&client_id=xxxxxxxxxx
&client_secret=xxxxxxxxxx
I`m developing a microservice structure using spring-boot, this structure has an external oauth2 Authorization Server and multiples Resource Servers.
My problem is, each http request to my resources, calls a url to my Authorization Server, to validate the token ( .../oauth/check_token/). This way there is a lot of requests. There is a way to validate/check this token only when it is expired?
My Resource servers:
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Value("${security.oauth2.client.client-id}")
private String clientId;
#Value("${security.oauth2.client.client-secret}")
private String clientSecret;
#Value("${security.oauth2.resource.id}")
private String resourceId;
#Value("${security.oauth2.resource.token-info-uri}")
private String tokenInfoUri;
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(ADMIN_ANT_MATCHER).hasRole("ADMIN")
.antMatchers(PROTECTED_ANT_MATCHER).hasRole("USER")
.and()
.csrf().disable();
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenServices(tokenService()).resourceId(resourceId).stateless(true);
}
#Bean
#Primary
public RemoteTokenServices tokenService() {
RemoteTokenServices tokenService = new RemoteTokenServices();
tokenService.setCheckTokenEndpointUrl(tokenInfoUri);
tokenService.setClientId(clientId);
tokenService.setClientSecret(clientSecret);
return tokenService;
}
}
Authorization Server:
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Value("${security.oauth2.client.client-id}")
private String clientId;
#Value("${security.oauth2.client.client-secret}")
private String clientSecret;
#Value("${security.oauth2.resource.id}")
private String resourceId;
#Value("${security.oauth2.client.access-token-validity-seconds}")
private Integer tokenValidateSeconds;
#Value("${security.oauth2.client.token-secret}")
private String tokenSecret;
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private TokenStore tokenStore;
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private OauthAccessTokenRepository oauthAccessTokenRepository;
#Autowired
private OauthRefreshTokenRepository oauthRefreshTokenRepository;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.tokenStore(this.tokenStore)
.tokenEnhancer(tokenEnhancer())
.authenticationManager(this.authenticationManager)
.userDetailsService(userDetailsService);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient(clientId)
.authorizedGrantTypes("client_credentials", "password", "refresh_token")
.authorities("ROLE_USER","ROLE_ADMIN")
.scopes("read","write","trust")
.resourceIds(resourceId)
.accessTokenValiditySeconds(tokenValidateSeconds)
.secret(bCryptPasswordEncoder().encode(clientSecret));
}
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.checkTokenAccess("isAuthenticated()");
}
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setSupportRefreshToken(true);
tokenServices.setTokenStore(this.tokenStore);
return tokenServices;
}
#Bean
public TokenEnhancer tokenEnhancer() {
return new TokenEnhancer() {
#Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
CustomUser user = (CustomUser) authentication.getPrincipal();
String token = JwtTokenHelper.generateToken(
user.getIdUser(),
user.getTenantID(),
user.getIdEntity(),
user.getIdBusinessUnit(),
user.getProfile(),
tokenValidateSeconds,
tokenSecret
);
((DefaultOAuth2AccessToken) accessToken).setValue(token);
return accessToken;
}
};
}
}
You can remove the need to use the check_token endpoint, by using signed JWT tokens.
When the resource server receive a JWT token, it verify it's signature by using a public key, and the expiration date by checking the corresponding field in the JSON object.
For this you can use the JwtAccessTokenConverter, JwtTokenStore and the nimbus-jose-jwt library.
The downside of this approach is that you cannot revoke a token. It's then preferable to have short lived tokens.
I currently have a microservices architecture secured by an authentication server and a resource server using Oauth2 protocol with my users stored in a database. To authenticate I use spring-security-oauth2 configured to return JWT tokens and these tokens travel in the request headers between my microservices.
Now I have a new requirement that I would like to be able to authenticate with Google using OpenID connect as well.
I have been researching how to do it but I haven't found a solution using spring-security-oauth2 because I want to keep my security core and avoid change it for this new requirement, this means I want to use my JWT certificate to validate the tokens that are flying between my microservices.
I suppose that I have to register the user with Google OpenId flow and use it to login with my current flow, but I don't know how to integrate with the web frontend, and how to register them.
I'm working with Spring Boot 1.5.4 and Spring Cloud 1.2.1
This is my current configuration:
MyAuthorizationServer.java
#Configuration
#EnableAuthorizationServer
public class MyAuthorizationServer extends AuthorizationServerConfigurerAdapter {
#Value("${keyStore.location}")
private Resource resource;
#Value("${keyStore.password}")
private String password;
#Value("${keyStore.alias}")
private String alias;
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Autowired
private DataSource dataSource;
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource);
}
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
KeyStoreKeyFactory keyStoreKeyFactory =
new KeyStoreKeyFactory(resource, password.toCharArray());
converter.setKeyPair(keyStoreKeyFactory.getKeyPair(alias));
return converter;
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
return defaultTokenServices;
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(
Arrays.asList(tokenEnhancer(), accessTokenConverter()));
endpoints.tokenStore(tokenStore())
.tokenEnhancer(tokenEnhancerChain)
.authenticationManager(authenticationManager);
}
#Bean
public TokenEnhancer tokenEnhancer() {
return new CustomTokenEnhancer();
}
}
MyResourceServer.java
#Configuration
#EnableResourceServer
public class MyResourceServer extends ResourceServerConfigurerAdapter {
#Autowired
private DefaultTokenServices tokenServices;
#Override
public void configure(final HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.authorizeRequests()
.antMatchers("/admin/** ").permitAll()
.anyRequest().authenticated();
}
#Override
public void configure(ResourceServerSecurityConfigurer config) {
config.tokenServices(tokenServices);
}
}
MyWebServerSecurity.java
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class MyWebServerSecurity extends WebSecurityConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Autowired
public void globalUserDetails(final AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource).passwordEncoder(passwordEncoder());
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/oauth/token").permitAll()
.antMatchers("/oauth/authorize").permitAll()
.anyRequest().authenticated().and().csrf().disable();
}
}
Thanks for your help.
Regards
I have implemented the JWT Application
I am using JWT 0.9.1 version
I am able to generate the Json web token, but when I pass to the http://localhost:8080/api/v1/greeting method I am always getting the same error like 401 Unauthorized.
SpringSecurityConfig.java
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
#Autowired
private UserDetailsService jwtUserDetailsService;
#Autowired
private JwtRequestFilter jwtRequestFilter;
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// configure AuthenticationManager so that it knows from where to load
// user for matching credentials
// Use BCryptPasswordEncoder
auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());
}
/*#Override
protected void configure(HttpSecurity http) throws Exception{
http.csrf().disable().authorizeRequests().antMatchers("/").permitAll();
}*/
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable()
// dont authenticate this particular request
.authorizeRequests().antMatchers("/api/v1/authenticate", "/api/v1/register","/api/v1/basicauth")
/*.permitAll().antMatchers(HttpMethod.OPTIONS, "/**")*/
// all other requests need to be authenticated
.permitAll().anyRequest().authenticated().and().
// make sure we use stateless session; session won't be used to
// store user's state.
exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// Add a filter to validate the tokens with every request
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
}
GreetingController.java
#CrossOrigin(origins = "http://localhost:4200")
#RestController
#RequestMapping("/api/v1")
public class GreetingController {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
#RequestMapping("/greeting")
public Greeting greeting(#RequestParam(value = "name", defaultValue = "World") String name) {
return new Greeting(counter.incrementAndGet(), String.format(template, name));
}
}
I am using oauth2 security in spring boot with 2.1.5 version. When I send a request to issue token, I am receiving an only the same token that got before. I cannot get a token until the token is expired. After that, I can get a new token, but again the same situation.
I tried to change the token store from JdbcTokenStore to InMemoryTOkenStore. Besides that, I changed the authentication mechanism AuthenticationProvider to UserDetailsService.But nothing happened.
#Configuration
public class OAuth2SecurityConfiguration {
#Configuration
#EnableResourceServer
public static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
private final TokenStore tokenStore;
public ResourceServerConfiguration(TokenStore tokenStore) {
this.tokenStore = tokenStore;
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.tokenStore(tokenStore).resourceId(Constants.SERVER_RESOURCE_ID);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(Constants.API_BASE_PATH + "/**").authenticated()
.and().csrf().disable();
}
}
#Configuration
#EnableAuthorizationServer
public static class OAuth2AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
private final AuthenticationManager authenticationManager;
private final DataSource dataSource;
private final PasswordEncoder passwordEncoder;
#Value("${jwt.key.password:my_pay_jwt_password}")
private String keyStorePassword;
public OAuth2AuthorizationServerConfiguration(AuthenticationManager authenticationManager, DataSource dataSource, PasswordEncoder passwordEncoder) {
this.authenticationManager = authenticationManager;
this.dataSource = dataSource;
this.passwordEncoder = passwordEncoder;
}
#Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
#Bean
public JwtAccessTokenConverter tokenEnhancer() {
// For getting user information in getPrincipal()
DefaultUserAuthenticationConverter duac = new DefaultUserAuthenticationConverter();
DefaultAccessTokenConverter datc = new DefaultAccessTokenConverter();
datc.setUserTokenConverter(duac);
JwtAccessTokenConverter converter = new CustomAccessTokenConverter();
converter.setAccessTokenConverter(datc); // IMPORTANT
KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("static/jwt.jks"), keyStorePassword.toCharArray());
converter.setKeyPair(keyStoreKeyFactory.getKeyPair("jwt"));
PublicKey publicKey = keyStoreKeyFactory.getKeyPair("jwt").getPublic();
String publicKeyString = Base64.encodeBase64String(publicKey
.getEncoded());
converter.setVerifierKey(publicKeyString);
return converter;
}
#Bean
#Primary
public AuthorizationServerTokenServices defaultAuthorizationServerTokenServices() {
DefaultTokenServices tokenServices = new LockingTokenServices();
tokenServices.setAuthenticationManager(this.authenticationManager);
tokenServices.setTokenStore(tokenStore());
tokenServices.setTokenEnhancer(tokenEnhancer());
tokenServices.setSupportRefreshToken(true);
tokenServices.setReuseRefreshToken(false);
return tokenServices;
}
#Override
public void configure(AuthorizationServerSecurityConfigurer security) {
security
.checkTokenAccess("permitAll()")
.tokenKeyAccess("isAuthenticated()")
.allowFormAuthenticationForClients()
.passwordEncoder(NoOpPasswordEncoder.getInstance());
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource)
.passwordEncoder(passwordEncoder);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.reuseRefreshTokens(false)
.accessTokenConverter(tokenEnhancer())
.authenticationManager(authenticationManager)
.tokenStore(tokenStore()).approvalStoreDisabled();
endpoints.exceptionTranslator(exception -> {
if (exception instanceof OAuth2Exception) {
OAuth2Exception oAuth2Exception = (OAuth2Exception) exception;
if (OAuth2Exception.INVALID_GRANT.equals(oAuth2Exception.getOAuth2ErrorCode())) {
oAuth2Exception.addAdditionalInformation("error_description", "Invalid username or password");
}
return ResponseEntity
.status(oAuth2Exception.getHttpErrorCode())
.body(oAuth2Exception);
} else {
throw exception;
}
});
}
}
}