I am trying to port Spring boot 1.5 application to Spring Boot 2
Now I can not get the OAuth2 access token.
This is the code that I have successfully used with Spring Boot 1.5:
public static String loginAndGetAccessToken(String username, String password, int port) { ResourceOwnerPasswordResourceDetails resourceDetails = new ResourceOwnerPasswordResourceDetails(); resourceDetails.setUsername(username); resourceDetails.setPassword(password); resourceDetails.setAccessTokenUri(String.format("http://localhost:%d/api/oauth/token", port)); resourceDetails.setClientId("clientapp"); resourceDetails.setClientSecret("123456"); resourceDetails.setGrantType("password"); resourceDetails.setScope(Arrays.asList("read", "write")); DefaultOAuth2ClientContext clientContext = new DefaultOAuth2ClientContext(); OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails, clientContext); restTemplate.setMessageConverters(Arrays.asList(new MappingJackson2HttpMessageConverter())); return restTemplate.getAccessToken().toString(); }
it fails with the following exception:
java.lang.IllegalStateException: An OAuth 2 access token must be obtained or an exception thrown. at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainAccessToken(AccessTokenProviderChain.java:124) at org.springframework.security.oauth2.client.OAuth2RestTemplate.acquireAccessToken(OAuth2RestTemplate.java:221) at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:173)
It looks like http://localhost:%d/api/oauth/token endpoint is protected right now and not accessible
This is my configuration:
OAuth2ServerConfig
@Configuration public class OAuth2ServerConfig { public static final String RESOURCE_ID = "restservice"; public static final String EXAMPLE_CLIENT_ID = "example_client_id"; @Value("${jwt.access.token.converter.signing.key}") private String jwtAccessTokenConverterSigningKey; @Value("${jwt.access.token.validity.seconds}") private int accessTokenValiditySeconds; @Autowired private UserDetailsService userDetailsService; @Bean @Primary public DefaultTokenServices tokenServices() { DefaultTokenServices tokenServices = new DefaultTokenServices(); tokenServices.setTokenStore(tokenStore()); tokenServices.setSupportRefreshToken(true); tokenServices.setAccessTokenValiditySeconds(accessTokenValiditySeconds); return tokenServices; } @Bean public JwtAccessTokenConverter accessTokenConverter() { JwtAccessTokenConverter converter = new UserAwareAccessTokenConverter(); converter.setSigningKey(jwtAccessTokenConverterSigningKey); DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter(); DefaultUserAuthenticationConverter userTokenConverter = new DefaultUserAuthenticationConverter(); userTokenConverter.setUserDetailsService(userDetailsService); accessTokenConverter.setUserTokenConverter(userTokenConverter); converter.setAccessTokenConverter(accessTokenConverter); return converter; } @Bean public TokenStore tokenStore() { return new JwtTokenStore(accessTokenConverter()); } @Configuration @EnableAuthorizationServer protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter { @Autowired @Qualifier("authenticationManagerBean") private AuthenticationManager authenticationManager; @Value("${jwt.access.token.validity.seconds}") private int accessTokenValiditySeconds; @Autowired private TokenStore tokenStore; @Autowired private TokenEnhancer tokenEnhancer; @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { // @formatter:off endpoints .tokenStore(tokenStore) .tokenEnhancer(tokenEnhancer) .authenticationManager(this.authenticationManager); // @formatter:on } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { // @formatter:off clients .inMemory() .withClient("clientapp") .authorizedGrantTypes("password","refresh_token") .authorities("ROLE_CLIENT") .scopes("read", "write") .resourceIds(RESOURCE_ID) .secret("123456") .and() .withClient(EXAMPLE_CLIENT_ID) .authorizedGrantTypes("implicit") .scopes("read", "write") .autoApprove(true) .and() .withClient("my-trusted-client") .authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit") .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT") .scopes("read", "write", "trust") .accessTokenValiditySeconds(accessTokenValiditySeconds); // @formatter:on } } @Configuration @EnableResourceServer protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter { @Autowired private ResourceServerTokenServices tokenService; @Override public void configure(ResourceServerSecurityConfigurer resources) { // @formatter:off resources .resourceId(RESOURCE_ID) .tokenServices(tokenService); // @formatter:on } @Override public void configure(HttpSecurity http) throws Exception { // @formatter:off http .antMatcher("/v1.0/**").authorizeRequests() .antMatchers("/v1.0/search/**").permitAll() .antMatchers("/v1.0/users/**").permitAll() .antMatchers("/v1.0/decisions/**").permitAll() .antMatchers("/v1.0/votes/**").permitAll() .antMatchers("/v1.0/likes/**").permitAll() .antMatchers("/v1.0/likeables/**").permitAll() .antMatchers("/v1.0/flags/**").permitAll() .antMatchers("/v1.0/flagtypes/**").permitAll() .antMatchers("/v1.0/flaggables/**").permitAll() .antMatchers("/v1.0/comments/**").permitAll() .antMatchers("/v1.0/commentables/**").permitAll() .antMatchers("/v1.0/subscribables/**").permitAll() .antMatchers("/v1.0/favoritables/**").permitAll() .antMatchers("/v1.0/import/**").permitAll() .antMatchers("/v1.0/tags/**").permitAll() .antMatchers("/v1.0/medias/**").permitAll() .antMatchers("/swagger**").permitAll() .anyRequest().authenticated() .and() .csrf().disable() .sessionManagement().sessionCreationPolicy(STATELESS); // @formatter:on } } }
Webmvcconfig
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); } @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/").setViewName("index"); registry.addViewController("/login").setViewName("login"); } @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/**").addResourceLocations("classpath:/static/"); registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/"); registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); } }
WebSecurityConfig
@Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Value("${logout.success.url}") private String logoutSuccessUrl; @Override protected void configure(HttpSecurity http) throws Exception { // @formatter:off http .cors() .and() .csrf().ignoringAntMatchers("/v1.0/**", "/logout") .and() .authorizeRequests() .antMatchers("/oauth/authorize").authenticated() //Anyone can access the urls .antMatchers("/images/**").permitAll() .antMatchers("/signin/**").permitAll() .antMatchers("/v1.0/**").permitAll() .antMatchers("/auth/**").permitAll() .antMatchers("/actuator/health").permitAll() .antMatchers("/actuator/**").hasAuthority(Permission.READ_ACTUATOR_DATA) .antMatchers("/login").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") .loginProcessingUrl("/login") .failureUrl("/login?error=true") .usernameParameter("username") .passwordParameter("password") .permitAll() .and() .logout() .logoutUrl("/logout") .logoutSuccessUrl(logoutSuccessUrl) .permitAll(); // @formatter:on } /** * Configures the authentication manager bean which processes authentication requests. */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder()); } @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowedOrigins(Arrays.asList("*")); configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS")); configuration.setAllowedHeaders(Arrays.asList("authorization", "content-type", "x-auth-token")); configuration.setExposedHeaders(Arrays.asList("x-auth-token")); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; } }
What needs to be changed there to make it work with Spring Boot 2?