A dependency cycle was detected when trying to resolve the AuthenticationManager (Spring Security and Oauth) - spring

I'm getting following error when configuring spring security, can anyone help me? The current configuration have resource server and authentication servers in same server for testing, may this causing conflicts.
Caused by: org.springframework.beans.FatalBeanException: A dependency cycle was detected when trying to resolve the AuthenticationManager. Please ensure you have configured authentication.
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.validateBeanCycle(WebSecurityConfigurerAdapter.java:462)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.<init>(WebSecurityConfigurerAdapter.java:430)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.authenticationManagerBean(WebSecurityConfigurerAdapter.java:220)
at org.blanc.whiteboard.security.configuration.SecurityConfig$ApiWebSecurityConfig.configure(SecurityConfig.java:110)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.getHttp(WebSecurityConfigurerAdapter.java:199)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.init(WebSecurityConfigurerAdapter.java:283)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.init(WebSecurityConfigurerAdapter.java:68)
at org.blanc.whiteboard.security.configuration.SecurityConfig$ApiWebSecurityConfig$$EnhancerBySpringCGLIB$$2cbb9c9d.init(<generated>)
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.init(AbstractConfiguredSecurityBuilder.java:367)
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.doBuild(AbstractConfiguredSecurityBuilder.java:320)
at org.springframework.security.config.annotation.AbstractSecurityBuilder.build(AbstractSecurityBuilder.java:39)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration.springSecurityFilterChain(WebSecurityConfiguration.java:92)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$d6effe0e.CGLIB$springSecurityFilterChain$4(<generated>)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$d6effe0e$$FastClassBySpringCGLIB$$3d548252.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:312)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$d6effe0e.springSecurityFilterChain(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:166)
... 30 more
Web security
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public OAuth2AccessDeniedHandler oAuth2AccessDeniedHandler(){
return new OAuth2AccessDeniedHandler();
}
#Configuration
#Order(1)
public static class ApiWebSecurityConfig extends WebSecurityConfigurerAdapter{
#Autowired
private UserRepository userRepository;
#Autowired
private Validator validator;
#Bean
public PasswordEncoder passwordEncoder(){
return new StandardPasswordEncoder();
}
#Autowired
private OAuth2AccessDeniedHandler oAuth2AccessDeniedHandler;
#Autowired
private ClientDetailsService clientDetailsService;
#Bean
public OAuthRestEntryPoint oauthRestEntryPoint()
{
return new OAuthRestEntryPoint();
}
// #Bean(name = "authenticationManager")
// #Override
// public AuthenticationManager authenticationManagerBean()
// throws Exception {
// return super.authenticationManagerBean();
// }
#Bean
public ClientDetailsUserDetailsService clientDetailsUserDetailsService(){
return new ClientDetailsUserDetailsService(clientDetailsService);
}
#Bean
public UserDetailsService userDetailsService() {
return new UserServiceImpl(userRepository, validator, passwordEncoder());
}
#Bean
protected AuthenticationEntryPoint authenticationEntryPoint(){
OAuth2AuthenticationEntryPoint entryPoint = new OAuth2AuthenticationEntryPoint();
entryPoint.setTypeName("Basic");
entryPoint.setRealmName("test");
return entryPoint;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.anonymous().disable()
.antMatcher("/oauth/token")
.authorizeRequests().anyRequest().authenticated()
.and()
.httpBasic().authenticationEntryPoint(oauthRestEntryPoint())
.and()
.csrf().requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/token")).disable()
.exceptionHandling().accessDeniedHandler(oAuth2AccessDeniedHandler)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
ClientCredentialsTokenEndpointFilter filter = new ClientCredentialsTokenEndpointFilter();
filter.setAuthenticationManager(authenticationManagerBean());
filter.afterPropertiesSet();
http.addFilterBefore(filter, BasicAuthenticationFilter.class);
http.addFilterAfter(filter, SpringCrossOriginResourceSharingFilter.class);
}
}
#Configuration
#Order(2)
protected static class ResourceServerConfig extends WebSecurityConfigurerAdapter{
#Bean(name = "clientAuthenticationManager")
#Override
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
#Autowired
private OAuth2AccessDeniedHandler oAuth2AccessDeniedHandler;
#Bean
public OAuth2AuthenticationEntryPoint clientAuthenticationEntryPoint(){
OAuth2AuthenticationEntryPoint clientAuthenticationEntrypoint = new OAuth2AuthenticationEntryPoint();
clientAuthenticationEntrypoint.setTypeName("Basic");
return clientAuthenticationEntrypoint;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.anonymous().disable().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling().accessDeniedHandler(oAuth2AccessDeniedHandler)
.authenticationEntryPoint(clientAuthenticationEntryPoint())
.and()
.requestMatchers().antMatchers("/v1.0/users")
.and()
.authorizeRequests().antMatchers(HttpMethod.POST, "/v1.0/users").permitAll()
.and()
.csrf().disable();
}
}
}
Oauthserver config
#Configuration
#ComponentScan
#EnableResourceServer
#Import(SecurityConfig.class)
#ImportResource({
"classpath:META-INF/spring/oauth/client-details.xml"
})
public class OAuth2ServerConfig {
#Configuration
#EnableAuthorizationServer
protected static class OAuth2Config extends
AuthorizationServerConfigurerAdapter {
// #Autowired
// private AuthenticationManager authenticationManager;
#Autowired
private ClientCredentialsTokenEndpointFilter clientCredentialsTokenEndpointFilter(){
ClientCredentialsTokenEndpointFilter clientFilter = new ClientCredentialsTokenEndpointFilter();
// clientFilter.setAuthenticationManager(authenticationManager);
return clientFilter;
}
#Autowired
private ClientDetailsService clientDetailsService;
#Autowired
public OAuth2AccessTokenRepository oAuth2AccessTokenRepository;
#Autowired
public OAuth2RefreshTokenRepository oAuth2RefreshTokenRepository;
#Bean
public DefaultTokenServices tokenServices(){
final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setReuseRefreshToken(true);
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setClientDetailsService(clientDetailsService);
return defaultTokenServices;
}
#Bean
public OAuth2RepositoryTokenStore tokenStore() {
return new OAuth2RepositoryTokenStore(oAuth2AccessTokenRepository,
oAuth2RefreshTokenRepository);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer)
throws Exception {
oauthServer.tokenKeyAccess(
"isAnonymous || hasAuthority('ROLE_TRUSTED_CLIENT')")
.realm("test");
}
#Override
public void configure(ClientDetailsServiceConfigurer clients)
throws Exception {
clients.withClientDetails(clientDetailsService);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints
// .authenticationManager(authenticationManager)
.clientDetailsService(clientDetailsService).tokenServices(tokenServices())
.tokenStore(tokenStore());
}
}
}

In your ResourceServerConfig, you've overridden authenticationManagerBean() but never configured the authenticationManager as instructed in the api reference, specifically
Override this method to expose the AuthenticationManager from
configure(AuthenticationManagerBuilder) to be exposed as a Bean.
For example ...
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(new MyCustomAuthProvider());
}
See the configure(AuthenticationManagerBuilder) reference for details.

Related

“error”: “invalid_grant”, “error_description”: “Bad credentials”

enter image description here
enter image description here
Photo 1: This is the error that appears in the postman when trying to validate
¨Photo 2 : In the Authorization I do not get the preview request
This is the code in Spring for the AuthorizationServerConfig class, code:
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter{
#Autowired
public BCryptPasswordEncoder passwordEncoder;
#Autowired
#Qualifier("authenticationManager")
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.tokenStore(tokenStore())
.accessTokenConverter(accessTokenConverter());
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory().withClient("angularapp")
.secret(passwordEncoder.encode("12345"))
.scopes("read", "write")
.authorizedGrantTypes("password","refresh_token")
.accessTokenValiditySeconds(3600)
.refreshTokenValiditySeconds(3600);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
return jwtAccessTokenConverter;
}
#Bean
public JwtTokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
}
This is the ResourceServerCoonfig class in spring attached code just in case this error:
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter{
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers(HttpMethod.GET,"/api/eventos").permitAll()
.anyRequest().authenticated();
}
}
and this is the code of the SpringSecurityConfig class, I also attach code:
#Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter{
#Autowired
private UserDetailsService usuarioService;
#Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
#Override
#Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(this.usuarioService).passwordEncoder(passwordEncoder());
}
#Bean("authenticationManager")
#Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager(); //To change body of generated methods, choose Tools | Templates.
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
.secret("{bcrypt}$2a$10$kwz.jnLVLwJOYTAp2r/oG.8tfAN/EC5dK1w5beLgfpuFT6Puprgq.")
use something like this, spring security changed plain text passwords to bcrypt
Check here

Springboot + Oauth2 - Failed to find access token

Am getting Failed to find access token for token 9ccc7637-04af-469d-93b8-209cbfac4e49 issue printed in a console when i call http://localhost:8081/oauth/token . Please find attached images for reference .
I gave my best but could find the issue .
Where i click oauth\token the token details are getting stored in database , but still throws error.
Unable to do API calls with access token created.
Please find below code and correct me .
Configuration
public class AppConfig {
#Value("${spring.datasource.url}")
private String datasourceUrl;
#Value("${spring.datasource.driver-class-name}")
private String dbDriverClassName;
#Value("${spring.datasource.username}")
private String dbUsername;
#Value("${spring.datasource.password}")
private String dbPassword;
#Bean
public DataSource dataSource() {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(dbDriverClassName);
dataSource.setUrl(datasourceUrl);
dataSource.setUsername(dbUsername);
dataSource.setPassword(dbPassword);
return dataSource;
}
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource());
}
}
#Configuration
#EnableAuthorizationServer
public class OAuthConfiguration extends AuthorizationServerConfigurerAdapter {
#Autowired
private final AuthenticationManager authenticationManager;
#Autowired
private final BCryptPasswordEncoder passwordEncoder;
#Autowired
private final UserDetailsService userService;
#Autowired
private TokenStore tokenStore;
public OAuthConfiguration(AuthenticationManager authenticationManager, BCryptPasswordEncoder passwordEncoder, UserDetailsService userService) {
this.authenticationManager = authenticationManager;
this.passwordEncoder = passwordEncoder;
this.userService = userService;
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient("my-trusted-client")
.authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
.scopes("read","write","trust")
.resourceIds("oauth2-resource")
.accessTokenValiditySeconds(50)
.refreshTokenValiditySeconds(1000)
.secret(passwordEncoder.encode("secret"));
}
#Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.userDetailsService(userService)
.authenticationManager(authenticationManager)
.tokenStore(tokenStore);
}
#Bean
public OAuth2AccessDeniedHandler oauthAccessDeniedHandler() {
return new OAuth2AccessDeniedHandler();
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
}
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.requestMatchers().antMatchers("/**").and()
.authorizeRequests()
.antMatchers("/**").access("hasRole('ADMIN') or hasRole('USER')")
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
}
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailsService userDetails;
#Autowired
DataSource dataSource;
#Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource).
usersByUsernameQuery("select username, password, enabled from users where username=?").
authoritiesByUsernameQuery("select username, roles from users where username=?");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/oauth/token").permitAll()
.antMatchers("/**").authenticated()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.csrf().disable();
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder( bCryptPasswordEncoder() );
provider.setUserDetailsService(userDetails);
return provider;
}
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
/*
* #Autowired // here is configuration related to spring boot basic public void
* configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
* auth.inMemoryAuthentication() // static users
* .withUser("User").password(bCryptPasswordEncoder().encode("User")).
* roles("USER") .and()
* .withUser("Admin").password(bCryptPasswordEncoder().encode("Admin[")).
* roles("ADMIN"); }
*/
#Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetails)
.passwordEncoder(bCryptPasswordEncoder());
}
}
error in console :
enter image description here

Spring OAuth security - Implicit flow

Is it possible to implement OAuth implicit flow with spring security? I want to create both auth and resource server in the same application. I need standard auth endpoints for authentication and authorization and some custom endpoints for handling with users (create/update/list...).
Requirements:
implicit flow
custom login page (/my_login_page)
silent mode for obtaining token (/oauth/authorize?...&prompt=none)
secured custom endpoints with OAuth (/users)
I'm stuck with configuration. Whatever I do, the requirements above never work together.
Spring WebSecurityConfig
#Configuration
#Order(-10)
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private MyAuthenticationProvider authenticationProvider;
private MyAuthenticationDetailsSource authenticationDetailsSource;
#Autowired
public SecurityConfig(MyAuthenticationProvider authenticationProvider, MyAuthenticationDetailsSource authenticationDetailsSource) {
this.authenticationProvider = authenticationProvider;
this.authenticationDetailsSource = authenticationDetailsSource;
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(authenticationProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.NEVER)
.sessionFixation().newSession()
.and()
.authorizeRequests()
.antMatchers("/assets/**", "/swagger-ui.html", "/webjars/**", "/swagger-resources/**", "/v2/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/my_login_page")
.loginProcessingUrl("/my_process_login")
.usernameParameter("my_username")
.passwordParameter("pmy_assword")
.authenticationDetailsSource(authenticationDetailsSource)
.permitAll();
}
}
Spring AuthorizationServerConfig
#Configuration
#EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
private ResourceLoader resourceLoader;
private AuthProps authProps;
#Autowired
public OAuth2AuthorizationServerConfig(ResourceLoader resourceLoader, AuthProps authProps) {
this.resourceLoader = resourceLoader;
this.authProps = authProps;
}
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
#Bean
#Qualifier("jwtAccessTokenConverter")
public JwtAccessTokenConverter accessTokenConverter() {
KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(resourceLoader.getResource(authProps.getAuthServerPrivateCertPath()), authProps.getAuthServerPrivateCertKey().toCharArray());
JwtAccessTokenConverter converter = new MYJwtAccessTokenConverter();
converter.setKeyPair(keyStoreKeyFactory
.getKeyPair(authProps.getAuthServerPrivateCertAlias()));
final Resource resource = resourceLoader.getResource(authProps.getAuthServerPublicCertPath());
String publicKey;
try {
publicKey = IOUtils.toString(resource.getInputStream());
} catch (final IOException e) {
throw new RuntimeException(e);
}
converter.setVerifierKey(publicKey);
return converter;
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
return defaultTokenServices;
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.tokenStore(tokenStore())
.accessTokenConverter(accessTokenConverter());
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("my-secured-client")
.secret("foo")
.authorizedGrantTypes("implicit")
.scopes("read", "write")
.resourceIds("my-resource")
.authorities("CLIENT")
.redirectUris(
"http://localhost:4200"
)
.accessTokenValiditySeconds(300)
.autoApprove(true);
}
}
Spring ResourceServerConfig
#Configuration
#EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
private AuthProps authProps;
private TokenStore tokenStore;
private DefaultTokenServices tokenServices;
#Autowired
public OAuth2ResourceServerConfig(AuthProps authProps, TokenStore tokenStore, DefaultTokenServices tokenServices) {
this.authProps = authProps;
this.tokenStore = tokenStore;
this.tokenServices = tokenServices;
}
#Override
public void configure(final ResourceServerSecurityConfigurer config) {
config
.resourceId("my-resource")
.tokenStore(tokenStore)
.tokenServices(tokenServices);
}
#Override
public void configure(final HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.antMatchers("/**").authenticated()
.and()
.csrf().disable();
}
}
I placed WebSecurityConfig before ResourceServerConfig otherwise login page doesn't work. But now I can't access my custom endpoint for users (I'm redirected to the login page). If I place ResourceServerConfig before WebSecurityConfig login page stop working. I get 404 not found response when I submit login page form.
I also have an issue with silent mode to obtain a new access token. When calling /oauth/authorize with still valid access_token I'm redirected to the login page.
Finally I found a solution:
ResourceServerConfig have to be before WebSecurityConfig
loginProcessingUrl should be /oauth/authorize
Silent refresh works by default until session is valid (login form)
Custom endpoint for logout where invalidate current session
EDITED:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private MyAuthenticationProvider authenticationProvider;
private MyAuthenticationDetailsSource authenticationDetailsSource;
#Autowired
public SecurityConfig(MyAuthenticationProvider authenticationProvider, MyAuthenticationDetailsSource authenticationDetailsSource) {
this.authenticationProvider = authenticationProvider;
this.authenticationDetailsSource = authenticationDetailsSource;
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) {
auth
.authenticationProvider(authenticationProvider);
}
#Override
public void configure(WebSecurity web) {
web
.debug(true)
.ignoring()
.antMatchers(HttpMethod.OPTIONS)
.antMatchers("/my-custom-login-page", "/my-custom-logout-page")
.antMatchers("/assets/**", "/swagger-ui.html", "/webjars/**", "/swagger-resources/**", "/v2/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/my-custom-login-page")
.loginProcessingUrl("/oauth/authorize")
.usernameParameter("myUsernameParam")
.passwordParameter("myPasswordParam")
.authenticationDetailsSource(authenticationDetailsSource)
.permitAll()
.and()
.csrf().disable();
}
}
#Configuration
#EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
private ResourceLoader resourceLoader;
private AuthProps authProps;
#Autowired
public OAuth2AuthorizationServerConfig(ResourceLoader resourceLoader, AuthProps authProps) {
this.resourceLoader = resourceLoader;
this.authProps = authProps;
}
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
#Bean
#Qualifier("jwtAccessTokenConverter")
public JwtAccessTokenConverter accessTokenConverter() {
KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(resourceLoader.getResource(authProps.getAuthServerPrivateCertPath()), authProps.getAuthServerPrivateCertKey().toCharArray());
JwtAccessTokenConverter converter = new MyJwtAccessTokenConverter();
converter.setKeyPair(keyStoreKeyFactory.getKeyPair(authProps.getAuthServerPrivateCertAlias()));
final Resource resource = resourceLoader.getResource(authProps.getAuthServerPublicCertPath());
String publicKey;
try {
publicKey = IOUtils.toString(resource.getInputStream());
} catch (final IOException e) {
throw new RuntimeException(e);
}
converter.setVerifierKey(publicKey);
return converter;
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
return defaultTokenServices;
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.tokenStore(tokenStore())
.accessTokenConverter(accessTokenConverter());
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient(authProps.getAuthServerClientId())
.secret(authProps.getAuthServerClientSecret())
.authorizedGrantTypes("implicit")
.scopes("read", "write")
.resourceIds(authProps.getAuthServerResourceId())
.authorities("CLIENT")
.redirectUris(
"http://localhost:4200/#/login",
"http://localhost:4200/assets/silent-refresh.html",
"http://localhost:8080/my-api/webjars/springfox-swagger-ui/oauth2-redirect.html"
)
.accessTokenValiditySeconds(authProps.getAuthServerAccessTokenValiditySeconds())
.autoApprove(true);
}
}
#Configuration
#EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
private AuthProps authProps;
private TokenStore tokenStore;
private DefaultTokenServices tokenServices;
#Autowired
public OAuth2ResourceServerConfig(AuthProps authProps, TokenStore tokenStore, DefaultTokenServices tokenServices) {
this.authProps = authProps;
this.tokenStore = tokenStore;
this.tokenServices = tokenServices;
}
#Override
public void configure(final ResourceServerSecurityConfigurer config) {
config.resourceId(authProps.getAuthServerResourceId()).tokenStore(tokenStore);
config.resourceId(authProps.getAuthServerResourceId()).tokenServices(tokenServices);
}
#Override
public void configure(final HttpSecurity http) throws Exception {
http
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.anyRequest().hasRole(AppRole.ROLE_APP_USER.split("ROLE_")[1])
.and()
.csrf().disable();
}
}
#Controller
public class MainController {
#Autowired
public MainController() {
...
}
#GetMapping("/my-custom-login-page")
public ModelAndView loginPage(HttpServletRequest request, HttpServletResponse response) {
ModelAndView mv = new ModelAndView("login-page");
return mv;
}
#GetMapping("/my-custom-logout-page")
public ModelAndView logoutPage(HttpServletRequest request) {
ModelAndView mv = new ModelAndView("logout-page");
HttpSession session = request.getSession(false);
if (Objects.isNull(session)) {
mv.addObject("msg", "NO SESSION");
return mv;
}
session.invalidate();
mv.addObject("msg", "SUCCEEDED");
return mv;
}
}
In addition to #user3714967 answer, I add some tips maybe It helps someone. The problem is that we are defining multiple HttpSecurity (The resourceServer is a WebSecurityConfigurerAdapter with order 3). The solution is to use HttpSecurity.requestMatchers() with the specific value.
Example
First Class:
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers().antMatchers("url1", "url2", ...).and()
.authorizeRequests()
.antMatchers(...).and()...
}
}
Second Class:
#Configuration
#EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers("url3", "url4", ...)
.and()
.authorizeRequests()
.antMatchers(...).and()...
}
}
}
This will be useful when we have more than flow (password && implicit flows for my case).

Spring Boot OAuth2 "Full authentication is required to access this resource" after access-token retrieving

I am writing Spring Boot with OAuth2 application. My classes are:
AuthorizationServerConfig.class
<pre>
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends
AuthorizationServerConfigurerAdapter {
private static String REALM="CRM_REALM";
private static final int TEN_DAYS = 60 * 60 * 24 * 10;
private static final int ONE_DAY = 60 * 60 * 24;
private static final int THIRTY_DAYS = 60 * 60 * 24 * 30;
#Autowired
private DataSource dataSource;
#Autowired
private TokenStore tokenStore;
#Autowired
private UserApprovalHandler userApprovalHandler;
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Autowired
private CrmUserDetailsService crmUserDetailsService;
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws
Exception {
// clients.jdbc(dataSource);
clients.inMemory()
.withClient("crmClient1")
.secret("crmSuperSecret")
.authorizedGrantTypes("password", "refresh_token")
.authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
.scopes("read", "write", "trust")
//.accessTokenValiditySeconds(ONE_DAY)
.accessTokenValiditySeconds(300)
.refreshTokenValiditySeconds(THIRTY_DAYS);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints.tokenStore(tokenStore).userApprovalHandler(userApprovalHandler)
.authenticationManager(authenticationManager)
.userDetailsService(crmUserDetailsService);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer)
throws Exception {
oauthServer.realm(REALM);
}
}
</pre>
ResourceServerConfig.class
<pre>
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
//-- define URL patterns to enable OAuth2 security
http.
anonymous().disable()
.requestMatchers().antMatchers("/api/**")
.and().authorizeRequests()
.antMatchers("/api/**").access("hasRole('ADMIN') or hasRole('USER')")
.and().exceptionHandling().accessDeniedHandler(new
OAuth2AccessDeniedHandler());
}
}
</pre>
SecurityConfig.class
<pre>
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Autowired
private ClientDetailsService clientDetailsService;
#Autowired
private CrmUserDetailsService crmUserDetailsService;
#Override
#Order(Ordered.HIGHEST_PRECEDENCE)
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf().disable()
.authorizeRequests()
.antMatchers("/about").permitAll()
.antMatchers("/signup").permitAll()
.antMatchers("/oauth/token").permitAll()
//.antMatchers("/api/**").authenticated()
.anyRequest().authenticated()
.and()
.httpBasic()
.realmName("CRM_REALM");
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth.userDetailsService(crmUserDetailsService)
.passwordEncoder(passwordEncoder());
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
#Bean
#Autowired
public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore
tokenStore){
TokenStoreUserApprovalHandler handler = new
TokenStoreUserApprovalHandler();
handler.setTokenStore(tokenStore);
handler.setRequestFactory(new
DefaultOAuth2RequestFactory(clientDetailsService));
handler.setClientDetailsService(clientDetailsService);
return handler;
}
#Bean
#Autowired
public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception {
TokenApprovalStore store = new TokenApprovalStore();
store.setTokenStore(tokenStore);
return store;
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
</pre>
SecurityWebApplicationInitializer.class
<pre>
public class SecurityWebApplicationInitializer extends
AbstractSecurityWebApplicationInitializer {
}
</pre>
MethodSecurityConfig.class
<pre>
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration
{
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
</pre>
SignupService.class
<pre>
#Service
#Transactional
public class SignupService {
#Autowired
private UserRepository userRepository;
#Autowired
PasswordEncoder passwordEncoder;
public User addUser(User user) {
user.setPassword(passwordEncoder.encode(user.getPassword()));
return userRepository.save(user);
}
/**
*
* set up a default customer with two roles USER and ADMIN
*
*/
#PostConstruct
private void setupDefaultUser() {
if (userRepository.count() == 0) {
userRepository.save(new User("crmadmin",
passwordEncoder.encode("adminpass"),
Arrays.asList(new UserRole("USER"), new
UserRole("ADMIN"))));
}
}
}
</pre>
After I send request localhost:8080/oauth/token and get access_token and refresh_token later when I try send api request with Authorization: Bearer (access_token) I got error:
<pre>
{
"timestamp": 1534343851414,
"status": 401,
"error": "Unauthorized",
"message": "Full authentication is required to access this resource",
"path": "/api/customers"
}
</pre>
Could you help me?

Spring OAuth with JWT - authorization to be performed only based on JWT in authorization server

In my system I use JWT tokens so that authorization of requests could be performed based on JWT only, with no need to call database to fetch roles etc. I use OAuth, and my services are Resource servers which works fine and I'm satisfied with that. The problem I have is with my uaa-service, which is both Authorization and Resource server.
I've noticed that when I send requests to uaa-service I can inject #AuthenticatedPrincipal into my controller method and I have access to all user fields, not only those which are present in JWT. It means that Spring somehow maintains session or maybe in the background fetches user data from database. Here are my settings:
#Configuration
#EnableResourceServer
#Slf4j
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
log.info("Configuring resource server");
http
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/register").permitAll().anyRequest().authenticated();
}
#Autowired
public void setJwtAccessTokenConverter(JwtAccessTokenConverter jwtAccessTokenConverter) {
jwtAccessTokenConverter.setAccessTokenConverter(bitcoinTokenConverter());
}
#Bean
DefaultAccessTokenConverter bitcoinTokenConverter() {
return new CustomTokenConverter();
}
And
#Configuration
#EnableAuthorizationServer
public class OAuth2AuthServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private CustomUserDetailsService customUserDetailsService;
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
KeyPair keyPair = new KeyStoreKeyFactory(new ClassPathResource(keystoreName), keystorePassword.toCharArray())
.getKeyPair(keystoreAlias);
converter.setKeyPair(keyPair);
return converter;
}
#Bean
public TokenEnhancer tokenEnhancer() {
return new CustomTokenEnhancer();
}
#Bean
public DefaultAccessTokenConverter accessTokenConverter() {
return new DefaultAccessTokenConverter();
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), jwtAccessTokenConverter()));
endpoints
.authenticationManager(authenticationManager)
.userDetailsService(customUserDetailsService)
.tokenEnhancer(tokenEnhancerChain);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}
and
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private CustomUserDetailsService customUserDetailsService;
#Autowired
private ApplicationEventPublisher applicationEventPublisher;
#Bean
FilterRegistrationBean forwardedHeaderFilter() {
FilterRegistrationBean filterRegBean = new FilterRegistrationBean();
filterRegBean.setFilter(new ForwardedHeaderFilter());
filterRegBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return filterRegBean;
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests().antMatchers("/register").permitAll().anyRequest().authenticated();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailsService).passwordEncoder(new BCryptPasswordEncoder());
auth.authenticationEventPublisher(new DefaultAuthenticationEventPublisher(applicationEventPublisher));
}
Where did I make a mistake? In my SecurityConfig.java I have
auth.userDetailsService(customUserDetailsService).passwordEncoder(new BCryptPasswordEncoder());
so that the login could be performed by fetchining user from database and validating password but it looks like it may also cause that incoming requests are not handled only based on JWT.

Resources