Why can't I use Bean that I have created before? - spring

I have a pretty simple class and just want to create #Bean and inject it in the method. But when I use passwordEncoder - it can't find an instance of it. Same for daoAuthenticationProvider ( daoAuthenticationProvider bean uses passwordEncoder bean ).
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
UserService userService;
#Autowired
public SecurityConfig(UserService userService) {
this.userService = userService;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(daoAuthenticationProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.NEVER)
.and()
.csrf()
.disable();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(10);
}
#Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider daoProvider = new DaoAuthenticationProvider();
daoProvider.setPasswordEncoder(passwordEncoder);
daoProvider.setUserDetailsService(userService);
return daoProvider;
}
}

This looks like a compilation issue not a Spring problem. You would need to either have an instance named passwordEncoder or inject it by invoking the method passwordEncoder() as follows:
#Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
[...]
daoProvider.setPasswordEncoder(passwordEncoder());
[...]
}

Related

Spring Security OAuth2, How to custom Authorization code & access token

I want to customize the auth code, access token value longer in my way.
I do not use oauth authentication on Google, Facebook, and support ID password login through internal services through formlogin().
I've seen this( https://docs.spring.io/spring-security/site/docs/5.1.1.RELEASE/reference/htmlsingle/#oauth2Client-authorization-request-resolver )
Maybe this content is similar to the direction I want, but I can't make it as it is because I don't use clientRegistration Repository.
I am registering oauth client with internal services and serving through db (https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/test/resources/schema.sql)
I wish I could tell you how to change the auth code and access token.
this is SecurityConfig.java file
#EnableWebSecurity
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private ClientRegistrationRepository clientRegistrationRepository;
#Autowired
private LoginService loginService;
#Autowired
private LoginFailureHandler loginFailureHandler;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(loginService);
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(
"/webjars/**"
, "/static/**"
, "/_hcheck"
);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers("/login"
, "/logout"
, "/j_spring_security_check"
, "/oauth/authorize"
, "/clients/groups/**"
, "/clients/**"
, "/clients"
, "/sso/clients"
, "/api/**"
, "/secret/matches"
, "/auth/defaultToken"
, "/main"
).and()
.authorizeRequests()
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/j_spring_security_check")
.usernameParameter("j_username")
.passwordParameter("j_password")
.defaultSuccessUrl("/main")
.failureHandler(loginFailureHandler)
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/login")
.and().cors().configurationSource(configurationSource())
.and().csrf().disable()
;
}
private CorsConfigurationSource configurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("*");
config.setAllowCredentials(true);
config.addAllowedHeader("X-Requested-With");
config.addAllowedHeader("Content-Type");
config.addAllowedHeader("X-Auth-Token");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
return source;
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
This is OAuth2AuthConfig.java file
#Configuration
#EnableAuthorizationServer
public class OAuth2AuthConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
DatasourceConfig datasourceConfig;
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Bean
#Primary
public DefaultTokenServices tokenServices() {
final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(datasourceConfig.tokenStore());
defaultTokenServices.setSupportRefreshToken(false);
return defaultTokenServices;
}
#Override
public void configure(final AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("permitAll()")
.checkTokenAccess("permitAll()");
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(datasourceConfig.dataSource());
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.tokenStore(datasourceConfig.tokenStore())
.authenticationManager(authenticationManager)
.reuseRefreshTokens(false)
.authorizationCodeServices(jdbcAuthorizationCodeServices());
}
#Bean
public JdbcAuthorizationCodeServices jdbcAuthorizationCodeServices() {
return new JdbcAuthorizationCodeServices(datasourceConfig.dataSource());
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}

Why AuthenticationManager is throwing StackOverflowError?

I am getting StackOverflowError while calling authenticationManger.authenticate()
java.lang.StackOverflowError: null at
org.apache.commons.logging.LogAdapter$Slf4jLog.isDebugEnabled(LogAdapter.java:300)
~[spring-jcl-5.1.10.RELEASE.jar:5.1.10.RELEASE] at
org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:162)
~[spring-security-core-5.1.6.RELEASE.jar:5.1.6.RELEASE] at
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:503)
~[spring-security-config-5.1.6.RELEASE.jar:5.1.6.RELEASE]
I am trying to implement JWT in my application. I have created JWTTOkenUtil, Filter, Controller. But only Authentication manager is not working. I have tried with CustomAuthenticationManger as well but same error.
File AppConfig.java
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class AppConfig extends WebSecurityConfigurerAdapter{
#Autowired
private JwtUserDetailService jwtUserDetailService;
#Autowired
private JwtAuthenticationProvider jwtAuthenticationProvider;
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(jwtAuthenticationProvider);
//auth.userDetailsService(jwtUserDetailService).passwordEncoder(passwordEncoder());
}
#Bean
#Override
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests().antMatchers("/version").permitAll()
.anyRequest().authenticated()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(jwtRequestFilter(), UsernamePasswordAuthenticationFilter.class);
}
#Bean
public JwtRequestFilter jwtRequestFilter() {
return new JwtRequestFilter();
}
}
authenticationManager() and authenticationManagerBean() of WebSecurityConfigurerAdapter are two different methods, and you are calling authenticationManagerBean() method of your super class, which, as far as I know, depends on authenticationManager() method. This, in return creates a cyclic calls of methods, which finally results in StackOverflowError exception.
You could try just not override AuthenticationManager authenticationManager() method, or return a solid implementation when doing so.
You are overiding the wrong method authenticationManager(), it should be authenticationManagerBean() instead.
Instead overriding authenticationManager() method, you need to override authenticationManagerBean() method of WebSecurityConfigurerAdapter class.
This is a working configuration for me.
#RequiredArgsConstructor
#EnableWebSecurity
public class SecurityConfigurer extends WebSecurityConfigurerAdapter {
private final CustomUserDetailsService customUserDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailsService);
}
#Override
protected void configure (HttpSecurity http) throws Exception{
http
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/authenticate").permitAll()
.anyRequest().authenticated();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception{
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance();
}
}

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).

How to use WebSecurity adapter with Spring-Security-OAuth2

I am trying to achieve authentication system using OAuth2 as well as simple Spring Security(Web Security adapter). But as I am trying to configure, I am not able to use both the services together. As per configuration file code shared below, But It will work either OAuth2 or simple auth using spring security(Web Security adapter). I want both the authentication system should work based on URL identification.
Thanks in advance!
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, proxyTargetClass = true)
public class ConfigurationClass {
// Its working as simple auth spring security
#EnableWebSecurity
#Configuration
#Order(1)
protected static class StatelessAuthenticationSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private TokenAuthenticationService tokenAuthenticationService;
#Autowired
private OtpManage OtpManage;
#Autowired
private RoleRepository RoleRepository;
public StatelessAuthenticationSecurityConfig() {
super(true);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// allow anonymous resource requests
.antMatchers("/").permitAll()
// allow anonymous POSTs to login
.antMatchers(HttpMethod.POST, "/user/registration").permitAll()
.antMatchers(HttpMethod.POST, "/user/changepassword").permitAll()
.antMatchers(HttpMethod.POST, "/user/resetpassword").permitAll()
// .antMatchers(HttpMethod.POST,
// "/api/otpResetPassword").permitAll()
.antMatchers(HttpMethod.POST, "/user/saveusergroup").permitAll()
.antMatchers(HttpMethod.POST, "/user/bugreport").permitAll()
.antMatchers(HttpMethod.POST, "/user/createtoken").permitAll()
// .anyRequest().authenticated().and()
.anyRequest().hasAnyRole("USER","SYSTEM_ADMIN","ADMIN").and()
// custom JSON based authentication by POST of
// {"username":"<name>","password":"<password>"} which sets the
// token header upon authentication
.addFilterBefore(new StatelessLoginFilter("/api/login", tokenAuthenticationService, userDetailsService,
authenticationManager(), OtpManage), UsernamePasswordAuthenticationFilter.class)
// custom Token based authentication based on the header
// previously given to the client
.addFilterBefore(new StatelessAuthenticationFilter(tokenAuthenticationService),
UsernamePasswordAuthenticationFilter.class);
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
}
#Override
protected UserDetailsService userDetailsService() {
return userDetailsService;
}
}
// Its not working, But if I removed #Order(1) annotation from StatelessAuthenticationSecurityConfig class then this one will work as default
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Autowired
private CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
#Autowired
private CustomLogoutSuccessHandler customLogoutSuccessHandler;
#Override
public void configure(HttpSecurity http) throws Exception {
System.out.println("#EnableResourceServer");
http
.exceptionHandling()
.authenticationEntryPoint(customAuthenticationEntryPoint)
.and()
.logout()
.logoutUrl("/oauth/logout")
.logoutSuccessHandler(customLogoutSuccessHandler)
.and()
.csrf()
.requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/authorize"))
.disable()
.headers()
.frameOptions().disable().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/hello/").permitAll()
.antMatchers("/secure/**").authenticated();
}
}
#Configuration
#EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter implements EnvironmentAware {
private static final String ENV_OAUTH = "authentication.oauth.";
private static final String PROP_CLIENTID = "clientid";
private static final String PROP_SECRET = "secret";
private static final String PROP_TOKEN_VALIDITY_SECONDS = "tokenValidityInSeconds";
private RelaxedPropertyResolver propertyResolver;
#Autowired
private DataSource dataSource;
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints
.tokenStore(tokenStore())
.authenticationManager(authenticationManager);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
System.out.println("#AuthorizationServerConfigurerAdapter");
clients
.inMemory()
.withClient(propertyResolver.getProperty(PROP_CLIENTID))
.scopes("read", "write")
.authorities(Authorities.ROLE_ADMIN.name(), Authorities.ROLE_USER.name())
.authorizedGrantTypes("password", "refresh_token")
.secret(propertyResolver.getProperty(PROP_SECRET))
.accessTokenValiditySeconds(propertyResolver.getProperty(PROP_TOKEN_VALIDITY_SECONDS, Integer.class, 1800));
}
#Override
public void setEnvironment(Environment environment) {
this.propertyResolver = new RelaxedPropertyResolver(environment, ENV_OAUTH);
}
}
}
Update:
I have made few changes to my code with #EnableOAuth2Client, #Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) and I have achieved what exactly I want to do. But now the issue is I am not able call to post url: "/api/login" with user credentials. I am getting error as url not found. as per my code in WebSecurityConfig class, I have added filter in configure(HttpSecurity http) method for loginFilter class which extends AbstractAuthenticationProcessingFilter. But this filter which is mapped with "/api/login" url not working at all. Why this one filter is not working I don`t understand. Someone could you help me regarding the same.
#WebSecurityConfigClass
/**
* Implementation of HttpSecurity configure method
* Implementation custom JSON based authentication by POST of {"username":"<name>","password":"<password>"} which sets the token header upon authentication
* #author Santosh
*
*/
#EnableOAuth2Client
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled=true, securedEnabled = true, proxyTargetClass = true)
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private TokenAuthenticationService tokenAuthenticationService;
#Autowired
private MessageSource messages;
#Autowired
private RESTAuthenticationEntryPoint authenticationEntryPoint;
#Autowired
private RESTAuthenticationSuccessHandler restAuthenticationSuccessHandler;
#Autowired
private RESTAuthenticationFailureHandler restAuthenticationFailureHandler;
#Autowired
private CustomAccessDeniedHandler accessDeniedHandler;
public WebSecurityConfig() {
super(true);
}
/*#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN");
auth.inMemoryAuthentication().withUser("testUser").password("testUser").roles("USER");
}
*/
#Override
protected void configure(HttpSecurity http) throws Exception {
// setup security
http
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler)
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.authorizeRequests()
.anyRequest()
.fullyAuthenticated()
.and().httpBasic();
http
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler)
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.anonymous().and()
.servletApi().and()
.headers().and()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/api/login").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.and()
.authorizeRequests()
.anyRequest().hasAnyRole("USER").and()
//all other request need to be authenticated
// custom JSON based authentication by POST of {"username":"<name>","password":"<password>"} which sets the token header upon authentication
.addFilterBefore(new LoginFilter("/api/login", tokenAuthenticationService, userDetailsService, authenticationManager(), restAuthenticationSuccessHandler, restAuthenticationFailureHandler), UsernamePasswordAuthenticationFilter.class)
// custom Token based authentication based on the header previously given to the client
.addFilterBefore(new ApplicationFilter (tokenAuthenticationService, messages), UsernamePasswordAuthenticationFilter.class);
}
// To allow Pre-flight [OPTIONS] request from browser
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
web.ignoring()//allow anonymous GETs to API
.antMatchers(HttpMethod.GET, "/api/status/**");
}
#Bean
public RequestContextListener requestContextListener(){
return new RequestContextListener();
}
#Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
#Bean
public CustomBasicAuthenticationEntryPoint getBasicAuthEntryPoint(){
return new CustomBasicAuthenticationEntryPoint();
}
#Bean(name="authenticationManagerBean")
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
#OAuth2ServerConfiguration
#Configuration
public class OAuth2ServerConfiguration {
private static final String RESOURCE_ID = "restservice";
private static final String ROLE_ADMIN = "ADMIN";
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Autowired
private CustomOAuth2AccessDeniedHandler accessDeniedHandler;
#Autowired
private RESTOAuth2AuthenticationEntryPoint restAuthenticationEntryPoint;
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/hello").permitAll()
.antMatchers("/users/current/**","/oauth/token","/oauth/authorize","/oauth/refresh_token").permitAll()
.antMatchers("/api/greeting").authenticated().and().exceptionHandling()
.accessDeniedHandler(accessDeniedHandler)
.authenticationEntryPoint(restAuthenticationEntryPoint);
}
}
#Configuration
#EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private DataSource dataSource;
#Autowired
private TokenStore tokenStore;
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
// #Autowired
// private UserApprovalHandler userApprovalHandler;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(this.tokenStore).authenticationManager(this.authenticationManager)
.userDetailsService(userDetailsService);
// .userApprovalHandler(userApprovalHandler)
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// jdbc(dataSource)
clients.inMemory().withClient("clientapp").authorizedGrantTypes("password", "refresh_token")
.authorities("USER").scopes("read", "write").resourceIds(RESOURCE_ID).secret("123456")
.accessTokenValiditySeconds(20)// Access token is only valid
// for 2 minutes.
.refreshTokenValiditySeconds(1200);// Refresh token is only
// valid for 10
// minutes.;
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setSupportRefreshToken(true);
tokenServices.setTokenStore(this.tokenStore);
return tokenServices;
}
}
}
On your WebSecurityAdapter you want to build requestMatchers to determine on which requests that instance of HttpSecurity will invoke.
For example :
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers().antMatchers("/secure/path", "/more/secure/path");
// Rest of your configuration.
}

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

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.

Resources