Spring Security work well when runtime, but got error while ddoing gradle build - spring

I've been make WebSecurity like this:
#Configuration
#EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
private final Environment environment;
private final UsersService usersService;
private final BCryptPasswordEncoder bCryptPasswordEncoder;
public WebSecurity(Environment environment, UsersService usersService, BCryptPasswordEncoder bCryptPasswordEncoder) {
this.environment = environment;
this.usersService = usersService;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(usersService)
.passwordEncoder(bCryptPasswordEncoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.headers().frameOptions().disable();
http.authorizeRequests()
.antMatchers("/users/**")
.hasIpAddress(environment.getProperty("app.gateway-ip"))
.and()
.addFilter(authenticateUser());
}
private AuthenticationFilter authenticateUser() throws Exception {
AuthenticationFilter authenticationFilter = new AuthenticationFilter(environment, usersService, authenticationManager());
authenticationFilter.setFilterProcessesUrl(environment.getProperty("app.auth.login.url-path"));
return authenticationFilter;
}
}
and an AuthenticationFilter like this:
public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private final Environment environment;
private final UsersService usersService;
public AuthenticationFilter(Environment environment, UsersService usersService, AuthenticationManager authenticationManager) {
this.environment = environment;
this.usersService = usersService;
super.setAuthenticationManager(authenticationManager);
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
try {
LoginRequestModel credentials = new ObjectMapper()
.readValue(request.getInputStream(), LoginRequestModel.class);
return getAuthenticationManager().authenticate(
new UsernamePasswordAuthenticationToken(
credentials.getEmail(),
credentials.getPassword(),
new ArrayList<>()
)
);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
#Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
String username = ((User) authResult.getPrincipal()).getUsername();
UserDto userDetails = usersService.getUserDetailsByEmail(username);
String token = Jwts.builder()
.setSubject(userDetails.getUserId())
.setExpiration(new Date(System.currentTimeMillis() + Long.parseLong(environment.getProperty("app.auth.token.expiration-time"))))
.signWith(SignatureAlgorithm.HS512, environment.getProperty("app.auth.token.secret"))
.compact();
response.addHeader("token", token);
response.addHeader("userId", userDetails.getUserId());
}
}
It all can work well in runtime, but when I tried to build it, the build failed because the test is error. When I try to run the test, I get this error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain' defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is java.lang.IllegalArgumentException: Pattern cannot be null or empty
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:658) ~[spring-beans-5.3.15.jar:5.3.15]
My test class only contain this code:
#SpringBootTest
class UserServiceApplicationTests {
#Test
void contextLoads() {
}
}
What I've done:
I've done adding some jaxb dependencies, but still not working

In your application you call
authenticationFilter.setFilterProcessesUrl(
environment.getProperty("app.auth.login.url-path")
);
Your build environment does not have the property app.auth.login.url-path.
The Framework tries to create an AntPathRequestMatcher with the patter provided but the pattern is empty because the property does not exist.

Related

Spring Security - How to catch Authenticatin Exception from custom Authentication provider

I'm trying the catch and customize Authentication exception thrown in Customized Authentication Filter but once the exception is thrown it always goes to the provider manager class and sends default spring API error response.
WebSecurity Config class
#Configuration
public static class RestAPISecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
AuthenticationEntry authenticationEntryPoint;
#Autowired
BasicAuthenticationProvider customAuthProvider;
#Autowired
AuthenticationFailureHandler accessDeniedHandler;
private final RequestMatcher PROTECTED_URLS = new OrRequestMatcher(
new AntPathRequestMatcher(API_PATH_IDENTIFIER));
#Value("${username}")
private String userName;
#Value("${password}")
private String password;
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthProvider);
auth.inMemoryAuthentication().withUser("abcd").password(passwordEncoder().encode("sample#123"))
.roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().and().authorizeRequests().antMatchers("/api")
.authenticated().and().exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers(SECURITY_EXCLUDED_PATHS);
}
}
AuthenticationProvider class:
#Component
public class BasicAuthenticationProvider implements AuthenticationProvider {
#Autowired
#Qualifier("handlerExceptionResolver")
private HandlerExceptionResolver resolver;
#Override
public Authentication authenticate(Authentication auth) throws UserAuthenticationException
{
String username = auth.getName();
String password = auth.getCredentials()
.toString();
AuthenticationException exception = null;
try {
if ("abcd".equals(username) && "Sample#123".equals(password)) {
return new UsernamePasswordAuthenticationToken
(username, password, Collections.emptyList());
} else {
throw new BadCredentialsException("invalid user");
}
}catch(AuthenticationException e)
{
exception = e;
throw exception;
}
}
#Override
public boolean supports(Class<?> auth) {
return auth.equals(UsernamePasswordAuthenticationToken.class);
}
}
AuthenticationEntryPOint class:
/**
*
* Authentication entry point to handle security exceptions
*
*/
#Component
public class AuthenticationEntry implements AuthenticationEntryPoint{
#Autowired
#Qualifier("handlerExceptionResolver")
private HandlerExceptionResolver resolver;
/**
*This handles security exceptions and redirects it to exception handler
*/
#Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws UserAuthenticationException {
httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
resolver.resolveException(httpServletRequest, httpServletResponse, null, new UserAuthenticationException("Not Authorized"));
}
}
you can do the exception in the filterChain

Custom AuthenticationProvider not getting called

I am developing a spring boot 2 application.I am trying to implement spring security for that.I have used a custom AutenticationProvider for that.But it is not getting called .Spring authentication is working however. please help me to resolve this issue.I have tried many ways,but it wont worked.I am using jwt to create tokens .
WebSecurityConfigurerAdapter implementation class
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
#ComponentScan
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
#Autowired
private SecurmailSecurityProvider provider;
#Override
protected void configure(AuthenticationManagerBuilder authentication) throws Exception {
authentication.authenticationProvider( getKBServicesAuthenticationProvider());
}
#Bean
protected AuthenticationProvider getKBServicesAuthenticationProvider() {
return new SecurmailSecurityProvider();
}
#Bean
public JwtAuthenticationFilter authenticationTokenFilterBean() throws Exception {
return new JwtAuthenticationFilter();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().
authenticationProvider(provider).
authorizeRequests()
.antMatchers(MessageController.URL_AUTHENTICATE).permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http
.addFilterBefore(authenticationTokenFilterBean(), SecurityContextHolderAwareRequestFilter.class);
http.headers().frameOptions().disable();
}
Custom Authentication provider class
#Component
#Primary
public class SecurmailSecurityProvider implements AuthenticationProvider {
#Autowired
MessageClientRepository clientRepo;
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (authentication.isAuthenticated()) return authentication;
SmAuthenticationToken token = (SmAuthenticationToken) authentication;
if (token.getGuid() != null && !token.getGuid().trim().isEmpty()) {
MessageClient client = clientRepo.findByGuid(token.getGuid());
if (client != null) {
return new SmAuthenticationToken(client);
}
}
return null;
}
#Override
public boolean supports(Class<?> authentication) {
return (SmAuthenticationToken.class.isAssignableFrom(authentication));
}
Already you autowired the CustomAuthentication provider by using
#Autowired
private SecurmailSecurityProvider provider;
again you are creating bean and passing that CustomAuthentication provider
#Bean
protected AuthenticationProvider getKBServicesAuthenticationProvider() {
return new SecurmailSecurityProvider();
}
Instead below code
#Autowired
private SecurmailSecurityProvider provider;
#Override
protected void configure(AuthenticationManagerBuilder authentication) throws Exception {
authentication.authenticationProvider( getKBServicesAuthenticationProvider());
}
#Bean
protected AuthenticationProvider getKBServicesAuthenticationProvider() {
return new SecurmailSecurityProvider();
}
Use this code
#Autowired
private SecurmailSecurityProvider provider;
#Override
protected void configure(AuthenticationManagerBuilder authentication) throws Exception {
authentication.authenticationProvider(provider);
}
And also Custom Authentication Provider implementation should be like this below:
#Component
public class SecurmailSecurityProvider implements AuthenticationProvider {
#Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
String name = authentication.getName();
String password = authentication.getCredentials().toString();
if (shouldAuthenticateAgainstThirdPartySystem()) {
// use the credentials
// and authenticate against the third-party system
return new UsernamePasswordAuthenticationToken(
name, password, new ArrayList<>());
} else {
return null;
}
}
#Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}

Spring Boot Unit Testing with Spring Security

I have a simple application that I have setup with spring security using a custom MySql Database. Now I'm writing test cases for it and they seems to fail on login page and anything that works after the login. My question is how do I write test cases for it to check the successful login and the subsequent requests?
My Security Config:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
#Autowired
private DataSource dataSource;
#Value("${spring.queries.users-query}")
private String usersQuery;
#Value("${spring.queries.roles-query}")
private String rolesQuery;
#Autowired
private CustomAuthenticationSuccessHandler successHandler;
/** Providing the queries and data source for security*/
#Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception
{
auth.
jdbcAuthentication()
.usersByUsernameQuery(usersQuery)
.authoritiesByUsernameQuery(rolesQuery)
.dataSource(dataSource)
.passwordEncoder(bCryptPasswordEncoder);
}
/** Defining fine grained access for ADMIN and CUSTOMER user */
#Override
protected void configure(HttpSecurity http) throws Exception {
http.
authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/login").permitAll()
.antMatchers("/registration").permitAll()
.antMatchers("/user/**").hasAuthority(AppRole.CUSTOMER.toString())
.antMatchers("/health/**").hasAuthority(AppRole.ADMIN.toString())
.antMatchers("/admin/**").hasAuthority(AppRole.ADMIN.toString()).anyRequest()
.authenticated().and().csrf().disable().formLogin()
.loginPage("/login").failureUrl("/login?error=true")
.successHandler(successHandler)
.usernameParameter("username")
.passwordParameter("password")
.and().logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/").and().exceptionHandling()
.accessDeniedPage("/access-denied");
}
/** Defining ant matchers that should ignore the paths and provide no access to any one */
#Override
public void configure(WebSecurity web) throws Exception
{
web
.ignoring()
.antMatchers("/resources/**", "/static/**", "/css/**", "/js/**", "/images/**");
}
}
My Custom Success Handler:
#Component
#Configuration
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler
{
/** Getting reference to UserService */
#Autowired
private UserService userService;
#Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, Authentication authentication)
throws IOException, ServletException, RuntimeException
{
HttpSession session = httpServletRequest.getSession();
User authUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
com.crossover.techtrial.java.se.model.User user = userService.findUserByUsername(authUser.getUsername());
session.setAttribute("userId", user.getUserId());
session.setAttribute("username", authUser.getUsername());
session.setAttribute("accountId", user.getAccountId());
//set our response to OK status
httpServletResponse.setStatus(HttpServletResponse.SC_OK);
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
authorities.forEach(authority ->
{
if(authority.getAuthority().equals(AppRole.ADMIN.toString()))
{
session.setAttribute("role", AppRole.ADMIN);
try
{
//since we have created our custom success handler, its up to us to where
//we will redirect the user after successfully login
httpServletResponse.sendRedirect("/admin/home");
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
else if (authority.getAuthority().equals(AppRole.CUSTOMER.toString()))
{
session.setAttribute("role", AppRole.CUSTOMER);
try
{
//since we have created our custom success handler, its up to us to where
//we will redirect the user after successfully login
httpServletResponse.sendRedirect("/user/home");
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
});
}
}
After some seraching I tried to write test cases like this but they don't seem to be working:
#RunWith(SpringRunner.class)
#SpringBootTest
public class TrialApplicationTests
{
#Autowired
private WebApplicationContext webApplicationContext;
#Autowired
private FilterChainProxy springSecurityFilterChain;
#Autowired
private MockHttpServletRequest request;
private MockMvc mockMvc;
#Test
public void contextLoads()
{
}
#Before
public void setup()
{
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
.addFilters(springSecurityFilterChain)
.build();
}
#Test
public void verifiesLoginPageLoads() throws Exception
{
mockMvc.perform(MockMvcRequestBuilders.get("/"))
.andExpect(MockMvcResultMatchers.model().hasNoErrors())
.andExpect(MockMvcResultMatchers.view().name("login"))
.andExpect(MockMvcResultMatchers.status().isOk());
}
#Test
public void testUserLogin() throws Exception
{
HttpSession session = mockMvc.perform(post("/login")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.param("username", "test")
.param("password", "test123")
)
.andExpect(MockMvcResultMatchers.status().isOk())
//.andExpect(redirectedUrl("/user/home"))
.andReturn()
.getRequest()
.getSession();
request.setSession(session);
SecurityContext securityContext = (SecurityContext) session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
SecurityContextHolder.setContext(securityContext);
}
#Test
public void testRetrieveUserBookings() throws Exception
{
testUserLogin();
mockMvc.perform(MockMvcRequestBuilders.get("user/bookings"))
.andExpect(MockMvcResultMatchers.model().hasNoErrors())
.andExpect(MockMvcResultMatchers.model().attributeExists("bookings"))
.andExpect(MockMvcResultMatchers.view().name("user/bookings"))
.andExpect(content().string(containsString("Booking")));
}
}
I searched on the net and there are links WithMockUser and UserDetails, but the problem is as you can see I'm setting a my primary key userId in the session in my custom success handler. So I would also need to get the session in my test. Please tell me the simplest way to write tests that will work, possibly with code since I'm new with security and all such.
UPDATE:
I changed the code as suggested but still getting the 404 error on my testRetrieveUserBookings. Any more ideas?
#RunWith(SpringRunner.class)
#ContextConfiguration
#SpringBootTest
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
#TestExecutionListeners(listeners={ServletTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class,
WithSecurityContextTestExecutionListener.class})
public class TrialApplicationTests
{
#Autowired
private WebApplicationContext webApplicationContext;
MockMvc mockMvc;
#Autowired
ForestApiClient apiClient;
#Autowired
AccountClient accountClient;
#Autowired
AirlineClient airlineClient;
#Autowired
UserService userService;
private final String INTEGRATION_ACCOUNT = "account1";
private MockHttpSession mockSession;
private Authentication authentication;
#Test
public void contextLoads()
{
}
#Before
public void setup()
{
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
//.addFilters(springSecurityFilterChain)
.build();
mockSession = new MockHttpSession(webApplicationContext.getServletContext(), UUID.randomUUID().toString());
mockSession.setAttribute("userId", 3);
mockSession.setAttribute("accountId", "ZWR26539");
}
#Test
public void testVerifiesLoginPageLoads() throws Exception
{
mockMvc.perform(MockMvcRequestBuilders.get("/"))
.andExpect(MockMvcResultMatchers.model().hasNoErrors())
.andExpect(MockMvcResultMatchers.view().name("login"))
.andExpect(MockMvcResultMatchers.status().isOk());
}
#Test
public void testRegistration() throws Exception
{
mockMvc.perform(post("/registration")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.param("username", "test2")
.param("password", "test123")
.param("email", "crossovertestuser#gmail.com")
.param("address", "Some Address")
.param("accountCurrency", "USD")
)
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.model().hasNoErrors())
.andExpect(MockMvcResultMatchers.model().attributeExists("user"))
.andExpect(MockMvcResultMatchers.view().name("registration"))
.andExpect(content().string(containsString("User has been registered successfully")));
}
#Test
#WithMockUser(username="test",roles={"USER","ADMIN"})
public void testRetrieveUserBookings() throws Exception
{
mockMvc.perform(MockMvcRequestBuilders.get("user/bookings"))
.andExpect(MockMvcResultMatchers.model().hasNoErrors())
.andExpect(MockMvcResultMatchers.model().attributeExists("bookings"))
.andExpect(MockMvcResultMatchers.view().name("user/bookings"))
.andExpect(content().string(containsString("Booking")));
}
}
If your problem is only getting session inside the test, then you can go for MockHttpSession.
#Before
public void setUp() throws Exception {
mock = MockMvcBuilders.webAppContextSetup(wac).addFilters(springSecurityFilterChain).build();
MockHttpSession httpSession = new MockHttpSession(webAppContext.getServletContext(), UUID.randomUUID().toString());
}
#Test
public void test1(){
mock.perform(get("/").session(mockSession)).perfor();
}

How to Control Sequence of Bean Creating and Component Scanning In Spring Boot

Updated
I am Beginner to Spring and I tried to implement spring security application using Java Based Configuration. But now I have to Control sequence of bean creating and component scanning of application.
This is my configuration class
#EnableWebSecurity
#Configuration
class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(this.userDetailsService).passwordEncoder(passwordEncoder());
}
#Bean
public Md5PasswordEncoder passwordEncoder() {
return new Md5PasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.headers().cacheControl();
http.csrf().disable()
.authorizeRequests()
.antMatchers("/authProxy").permitAll()
.antMatchers(HttpMethod.POST,"/login").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(new JWTLoginFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new JWTAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
and here is the JWTLoginFilter
public class JWTLoginFilter extends AbstractAuthenticationProcessingFilter {
private TokenAuthenticationService tokenAuthenticationService;
public JWTLoginFilter(AuthenticationManager authenticationManager) {
super(new AntPathRequestMatcher("/login"));
setAuthenticationManager(authenticationManager);
tokenAuthenticationService = new TokenAuthenticationService();
}
#Override
public Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse)
throws AuthenticationException, IOException, ServletException {
AccountCredentials credentials = new ObjectMapper().readValue(httpServletRequest.getInputStream(), AccountCredentials.class);
final Authentication authentication = getAuthenticationManager()
.authenticate(new UsernamePasswordAuthenticationToken(credentials.getUsername(),
credentials.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(credentials.getUsername(), credentials.getPassword());
return getAuthenticationManager().authenticate(token);
}
#Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication)
throws IOException, ServletException {
String name = authentication.getName();
tokenAuthenticationService.addAuthentication(response, name);
}
}
This is working fine.
But all thing going wrong When I try to declare JWTLoginFilter as service with #Service annotation and while I am trying to Autowire that.
The Changes that I did as Follows.
this is configuration class.
#EnableWebSecurity
#Configuration
class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(this.userDetailsService).passwordEncoder(passwordEncoder());
}
#Bean
public Md5PasswordEncoder passwordEncoder() {
return new Md5PasswordEncoder();
}
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Autowired
JWTLoginFilter jwtLoginFilter;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.headers().cacheControl();
http.csrf().disable()
.authorizeRequests()
.antMatchers("/authProxy").permitAll()
.antMatchers(HttpMethod.POST,"/login").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(jwtLoginFilter, UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new JWTAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
And this is my new JWTLoginFilter
#Service
public class JWTLoginFilter extends AbstractAuthenticationProcessingFilter {
#Autowired
AuthenticationManager authenticationManager;
private TokenAuthenticationService tokenAuthenticationService;
public JWTLoginFilter() {
super(new AntPathRequestMatcher("/login"));
setAuthenticationManager(authenticationManager);
tokenAuthenticationService = new TokenAuthenticationService();
}
#Override
public Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse)
throws AuthenticationException, IOException, ServletException {
AccountCredentials credentials = new ObjectMapper().readValue(httpServletRequest.getInputStream(), AccountCredentials.class);
final Authentication authentication = getAuthenticationManager()
.authenticate(new UsernamePasswordAuthenticationToken(credentials.getUsername(),
credentials.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(credentials.getUsername(), credentials.getPassword());
return getAuthenticationManager().authenticate(token);
}
#Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication)
throws IOException, ServletException {
String name = authentication.getName();
tokenAuthenticationService.addAuthentication(response, name);
}
}
This Code gives runtime error called
Error starting Tomcat context. Exception: org.springframework.beans.factory.BeanCreationException. Message: Error creating bean with name 'JWTLoginFilter' defined in file [/media/dilanka/Stuff/CODEBASE/Inspection-Application/Inspection-AuthProxy/target/classes/com/shipxpress/inspection/security/jwt/JWTLoginFilter.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: authenticationManager must be specified
The error is as my thought at the beginning, ComponentScan Scanning and initiating JWTLoginFilter. But at that time AuthenticationManager bean has not created. So It is not auto wiring.
So I have to create AuthenticationManager bean before scanning JWTLoginFilter, But It is not possible because it has to create in class that extended by WebSecurityConfigurerAdapter and spring allows one WebSecurityConfigurerAdapter extended class. So I can't initiate it in another class.
Also
#Override
protected void configure(HttpSecurity http) throws Exception {}
has to declare in WebSecurityConfigurerAdapter extended class and this method use jwtLoginFilter. So all
#Autowired
JWTLoginFilter jwtLoginFilter;
and
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
and
#Override
protected void configure(HttpSecurity http) throws Exception {
http.headers().cacheControl();
http.csrf().disable()
.authorizeRequests()
.antMatchers("/authProxy").permitAll()
.antMatchers(HttpMethod.POST,"/login").permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(jwtLoginFilter, UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new JWTAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
has to define it in WebSecurityConfig extends WebSecurityConfigurerAdapter class and has to Control sequence of bean creating and component scanning of the application. Does anyone have an idea? please help me.
updated-->
I Tried to implement JWTLoginFilter as follows,
#Service
public class JWTLoginFilter extends AbstractAuthenticationProcessingFilter {
private TokenAuthenticationService tokenAuthenticationService;
#Autowired
public JWTLoginFilter(AuthenticationManager authenticationManager) {
super(new AntPathRequestMatcher("/login"));
}
...
}
But it gives the following error
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| JWTLoginFilter defined in file [/media/dilanka/Stuff/CODEBASE/Inspection-Application/DR-136812421-dbchangesSendAsMail/Inspection-Application/Inspection-AuthProxy/target/classes/com/shipxpress/inspection/security/jwt/JWTLoginFilter.class]
↑ ↓
| webSecurityConfig (field com.shipxpress.inspection.security.jwt.JWTLoginFilter com.shipxpress.inspection.config.WebSecurityConfig.jwtLoginFilter)
└─────┘
I think the problem is, If we auto wire Constructor as above, Then JWTLoginFilter can't create without creating Configuration beans creating. But Configuration beans needs JWTLoginFilter bean. So it can't create without JWTLoginFilter bean.
Thanks.
#Autowired annotation will be processed after constructor of bean has been called. So your exception does not depend on the sequence of bean creating. If you need to invoke setAuthenticationManager from constructor you can apply #Autowired to the constructor:
#Service
public class JWTLoginFilter extends AbstractAuthenticationProcessingFilter {
AuthenticationManager authenticationManager;
private TokenAuthenticationService tokenAuthenticationService;
#Autowired
public JWTLoginFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager; //if you will need this instance in future
super(new AntPathRequestMatcher("/login"));
setAuthenticationManager(authenticationManager);
tokenAuthenticationService = new TokenAuthenticationService();
}
...
}
Then appropriate bean will be passed to the constructor automatically.
Another solution is to make all initialization in the #PostConstruct method. This method will be called just after #Autowired annotation has been processed:
#Service
public class JWTLoginFilter extends AbstractAuthenticationProcessingFilter {
#Autowired
AuthenticationManager authenticationManager;
private TokenAuthenticationService tokenAuthenticationService;
public JWTLoginFilter(){
super(new AntPathRequestMatcher("/login"));
}
#PostConstruct
public void postConstruct() {
setAuthenticationManager(authenticationManager);
tokenAuthenticationService = new TokenAuthenticationService();
}
...
}
Spring Boot has multiple conditional annotations to use like #ConditionalOnBean to control the sequencing of bean creation
Look into package org.springframework.boot.autoconfigure.condition for all the conditionals available
For the your example, best way is to have constructor injection of AuthenticationManager in JWTLoginFilter

Spring Security authenticationmanager must be specified - for custom filter

I’m trying to create a custom username password authentication filter since I need to validate passwords from two different sources. I’m using Spring Boot 1.2.1 and Java configuration. The error I get when deploying is
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'customUsernamePasswordAuthenticationFilter' defined in file [/Users/rjmilitante/Documents/eclipse-workspace/login-service/bin/com/elsevier/eols/loginservice/CustomUsernamePasswordAuthenticationFilter.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: authenticationManager must be specified
…
Caused by: java.lang.IllegalArgumentException: authenticationManager must be specified
I’m not sure what I’m missing. I have been trying to set authenticationManager for this filter in my SecurityConfig. My code looks like
my filter:
#Component
public class CustomUsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public CustomUsernamePasswordAuthenticationFilter(RequestMatcher requiresAuthenticationRequestMatcher) {
super(requiresAuthenticationRequestMatcher);
// TODO Auto-generated constructor stub
}
public CustomUsernamePasswordAuthenticationFilter() {
super(new AntPathRequestMatcher("/login","POST"));
// TODO Auto-generated constructor stub
}
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
// String dbValue = request.getParameter("dbParam");
// request.getSession().setAttribute("dbValue", dbValue);
System.out.println("attempting to authentificate");
while (request.getAttributeNames().hasMoreElements()) {
String e = (String) request.getAttributeNames().nextElement();
System.out.println("param name : " + e + " and param value : " + request.getAttribute(e));
}
return null;
}
}
my security config:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean(name="loginService")
public LoginService loginService(){
return new LoginServiceImpl();
}
#Bean( name="myAuthenticationManager")
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
CustomUsernamePasswordAuthenticationFilter customUsernamePasswordAuthenticationFilter() throws Exception {
CustomUsernamePasswordAuthenticationFilter customUsernamePasswordAuthenticationFilter = new CustomUsernamePasswordAuthenticationFilter();
customUsernamePasswordAuthenticationFilter.setAuthenticationManager(authenticationManagerBean());
return customUsernamePasswordAuthenticationFilter;
}
#Autowired
private myAuthenticationProvider myAuthenticationProvider;
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
/*.addFilterBefore(customUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)*/;
}
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(myAuthenticationProvider);
}
}
Can anyone take a look? not sure what’s up with it.
The documentation for AbstractAuthenticationProcessingFilter states that you must set an AuthenticationManager.
I suggest you try adding the following code inside your CustomUsernamePasswordAuthenticationFilter class:
#Override
#Autowired
public void setAuthenticationManager(AuthenticationManager authenticationManager) {
super.setAuthenticationManager(authenticationManager);
}
I actually got past the error. I just had to remove the #Component annotation from my custom filter.

Resources