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

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

Related

How do I implement conditional authentication in spring security based on user selection between LDAP and JDBC?

Hope you all are doing good and safe. I have an application which will allow a user to login either by using his LDAP credentials or using his credentials stored on database. I was able to configure separate jdbc and ldap authenticator but how can I implement it conditionally? Say, a user selects LDAP radio button on login page then it should trigger LDAP authentication and if user selects database authentication, then it should trigger jdbc authentication. Any help would be highly appreciated.
JDBC authenticator:-
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailsService userDetailsService;
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// TODO Auto-generated method stub
http.authorizeRequests()
.antMatchers("/admin").hasAnyRole("ADMIN")
.antMatchers("/user").hasAnyRole("ADMIN", "USER")
.antMatchers("/").permitAll()
.and().formLogin();
}
#Bean
public PasswordEncoder getPasswordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
**LDAP authenticator:-**
#EnableWebSecurity
public class ApplicationSecurityConfig extends WebSecurityConfigurerAdapter {
Logger logger = LoggerFactory.getLogger(this.getClass());
#Autowired
private UserDetailsService userDetailsService;
#Autowired
AuthenticationSuccessHandler authenticationSuccessHandler;
#Autowired
private AuthenticationFailureHandler authenticationFailureHandler;
#Bean
public AuthenticationFailureHandler authenticationFailureHandler() {
return new AuthenticationFailureHandler() {
String message = "";
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
if (exception.getClass().isAssignableFrom(UsernameNotFoundException.class)) {
message = "User Not Found";
} else if (exception.getClass().isAssignableFrom(DisabledException.class)) {
message = "Account Disabled";
} else if (exception.getClass().isAssignableFrom(BadCredentialsException.class)) {
message = "Bad Credentials";
}
else if (exception.getClass().isAssignableFrom(LockedException.class)) {
message = "Account Locked";
}
else {
message = "Internal Server Error";
}
response.sendRedirect("/WisoKeyinPortal/login?error=" + message);
}
};
}
#Bean
public UserDetailsService userDetailsService() {
return super.userDetailsService();
}
#Bean
public AuthenticationProvider authProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(new BCryptPasswordEncoder());
return authenticationProvider;
}
/*---------------------------For QA comment from here-------------------------------*/
#Bean public AuthenticationManager authenticationManager() { return new
ProviderManager(Arrays.asList(activeDirectoryLdapAuthenticationProvider()));
}
#Bean public AuthenticationProvider
activeDirectoryLdapAuthenticationProvider() {
ActiveDirectoryLdapAuthenticationProvider provider = new
ActiveDirectoryLdapAuthenticationProvider("xyz.com", "ldap://xyz.com");
provider.setConvertSubErrorCodesToExceptions(true);
provider.setUseAuthenticationRequestCredentials(true);
provider.setSearchFilter("sAMAccountName={1}"); return provider; }
/*----------------------------For QA comment ends here-----------------------------*/
#Override
protected void configure(HttpSecurity http) throws Exception {
String[] staticResources = { "/css/**", "/images/**", "/fonts/**", "/scripts/**", };
http.csrf().disable().authorizeRequests().antMatchers("/login**").permitAll().antMatchers(staticResources)
.permitAll().anyRequest().authenticated().and().formLogin().loginPage("/login").permitAll()
.successHandler(authenticationSuccessHandler).failureHandler(authenticationFailureHandler).and()
.logout().invalidateHttpSession(true).clearAuthentication(true)
.logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/login").permitAll();
//.and().sessionManagement().invalidSessionUrl("/login?error=session");
}
#Override
protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
//authManagerBuilder.inMemoryAuthentication().withUser("admin").password("pass").roles("ADMIN");
/*---------------------------For QA comment from here-------------------------------*/
authManagerBuilder.authenticationProvider(
activeDirectoryLdapAuthenticationProvider())
.userDetailsService(userDetailsService());
/*---------------------------For QA comment from here-------------------------------*/
}
}

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);
}
}

Oauth2 - java.lang.IllegalStateException: UserDetailsService is required. with refresh token

I am trying to implement oauth2 with a jwt in spring boot and the autentication works but when I want to get the refresh_token an error occurs that indicates the following ...
java.lang.IllegalStateException: UserDetailsService is required.
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$UserDetailsServiceDelegator.loadUserByUsername(WebSecurityConfigurerAdapter.java:464)
at org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper.loadUserDetails(UserDetailsByNameServiceWrapper.java:68)
at org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider.authenticate(PreAuthenticatedAuthenticationProvider.java:103)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:175)
at org.springframework.security.oauth2.provider.token.DefaultTokenServices.refreshAccessToken(DefaultTokenServices.java:150)
What am I doing wrong?
These are my files
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Value("${token.secret}")
private String secret;
#Value("${server.servlet.context-path}")
private String contextPath;
#Value("${oauth2.client.id}")
public String CLIENT_ID;
#Value("${oauth2.client.secret}")
public String CLIENT_SECRET;
#Value("${oauth2.scope.read}")
public String SCOPE_READ;
#Value("${oauth2.grant.types}")
public String GRANT_TYPES;
#Value("${oauth2.scopes}")
public String SCOPES;
#Value("${oauth2.access.token.validity}")
public Integer TOKEN_VALID_SECONDS;
#Value("${oauth2.refresh.token.validity}")
public Integer REFRESH_TOKEN_VALID_SECONDS;
#Autowired
private DataSource dataSource;
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Override
public void configure(final AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient(CLIENT_ID)
.secret(passwordEncoder().encode(CLIENT_SECRET))
.authorizedGrantTypes("password", "refresh_token", "client_credentials","authorization_code")
.scopes("read", "write", "trust")
.accessTokenValiditySeconds(TOKEN_VALID_SECONDS)
.refreshTokenValiditySeconds(REFRESH_TOKEN_VALID_SECONDS);
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
return defaultTokenServices;
}
#Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
final TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer()));
endpoints.tokenStore(tokenStore()).tokenEnhancer(tokenEnhancerChain).authenticationManager(authenticationManager);
}
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
#Bean
public TokenEnhancer tokenEnhancer() {
return new CustomTokenEnhancer();
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
And this is my SecurityConfig class
#EnableGlobalMethodSecurity(securedEnabled=true)
#Configuration
#RequiredArgsConstructor
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private final CustomUserDetailsService customUserDetailsService;
#Autowired
public BCryptPasswordEncoder passwordEncoder;
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailsService)
.passwordEncoder(passwordEncoder);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/oauth/**").permitAll()
.antMatchers("/oauth/token/**").permitAll()
.antMatchers("/api/**" ).authenticated()
.anyRequest().authenticated()
.and().formLogin().permitAll()
.and().csrf().disable();
}
}
public class CustomUserDetailsService implements UserDetailsService {
#Autowired
private UserService userService;
//login web service url describe on properties file
#Value("${loginServiceUri}")
public String loginServiceUri;
//login web service enabled
#Value("${loginWebServiceEnabled}")
public Boolean loginWebServiceEnabled;
#Override
public UserDetails loadUserByUsername(String username) {
log.debug("Trying to authenticate user with details....");
if (loginWebServiceEnabled && loginServiceUri != null){
//its necessary to call external Web Service to find the user and then look for
//into database
UserDto userDto = this.loginWebService(username);
if (userDto != null) {
// look for the user in data base
log.debug("User found at external login web service trying to look for at data base");
return lookUserDataBase(userDto.getUsername());
} else {
log.error("User not found at external login web service", username);
throw new UsernameNotFoundException(username);
}
} else {
// look for the user in data base
return lookUserDataBase(username);
}
}
/**
* Look for use in data base by user name
* #return
*/
private UserDetails lookUserDataBase(String userName) {
UserEntity user = userService.findEntityByUsername(userName);
if (user == null) {
log.error("User not found in data base", userName);
throw new UsernameNotFoundException(userName);
}
log.debug("User found in data base with userName: " + userName + " and authorities: " + user.getUserAuthority().toString());
return new UserAuthenticatedDetails(user);
}
/**
* Example Login Web Service call login
* #param name
* #return
*/
private UserDto loginWebService (String name){
xxxxxxxxxxx
}
}
Add these in your WebSecurityConfigurerAdapter class
#Autowired
public void setApplicationContext(ApplicationContext context) {
super.setApplicationContext(context);
AuthenticationManagerBuilder globalAuthBuilder = context
.getBean(AuthenticationManagerBuilder.class);
try {
globalAuthBuilder.userDetailsService(userDetailsService);
} catch (Exception e) {
e.printStackTrace();
}
}
There is a "local" AuthenticationManagerBuilder and a "global" AuthenticationManagerBuilder and we need to set it on the global version in order to have this information passed to these other builder contexts.
Read more about it here
I solved with this lines in SecurityConfig;
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
final TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer()));
endpoints.tokenStore(tokenStore()).tokenEnhancer(tokenEnhancerChain).authenticationManager(authenticationManager);
//this line solved the problem
endpoints.userDetailsService(customUserDetailsService);**
}
Either you configure some inMemory user as follows:
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user")
.password("password")
.roles("USER")
.and()
.withUser("manager")
.password("password")
.credentialsExpired(true)
.accountExpired(true)
.accountLocked(true)
.authorities("WRITE_PRIVILEGES", "READ_PRIVILEGES")
.roles("MANAGER");
}
or you implement a UserDetailService e.g. which looks up in the database for a user.

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 use the HttpServletRequest in #Service or #Dao layer to get the user presented credentials?

I have implemented the security layer in my project using Spring Boot. Now,I would like to know how to get the request parameters using HttpServletRequest in #Service or #Dao layer. I tried some way to get the request parameters and I could the username and password but I need to pass that in the Dao. My code:
Security Layer code:
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class ApplicationSecurity extends WebSecurityConfigurerAdapter{
#Autowired
UserDao userDao;
#Autowired
HttpServletRequest request;
#Autowired
#Qualifier("userDetailsService")
UserDetailsService userDetailsService;
UserDetails userDetails;
#Autowired
private RESTAuthenticationEntryPoint authenticationEntryPoint;
#Autowired
private RESTAuthenticationFailureHandler authenticationFailureHandler;
#Autowired
private RESTAuthenticationSuccessHandler authenticationSuccessHandler;
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/css/**", "/fonts/**", "/images/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
request.getParameter("username");
http.authorizeRequests().antMatchers("/", "/index.html","/home.html","/static/*","/home/*", "/login.html","/login").permitAll();
http.authorizeRequests().anyRequest().fullyAuthenticated().and().httpBasic().and().csrf().disable();
http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);
http.formLogin().usernameParameter("username").passwordParameter("password").loginProcessingUrl("/login/authenticate").successHandler(authenticationSuccessHandler);
http.formLogin().failureHandler(authenticationFailureHandler);
http.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).invalidateHttpSession(true);
http.exceptionHandling().accessDeniedHandler(accessDeniedHandler());
// CSRF tokens handling
http.addFilterAfter(new CsrfTokenResponseHeaderBindingFilter(), CsrfFilter.class);
http.addFilterBefore(tokenProcessingFilter(), RequestFetcher.class);
}
/**
* Configures the authentication manager bean which processes authentication
* requests.
*/
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// Dao based authentication
auth.userDetailsService(userDetailsService).passwordEncoder(new Md5PasswordEncoder());
}
private AccessDeniedHandler accessDeniedHandler() {
return new AccessDeniedHandler() {
#Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.getWriter().append("Access denied");
response.setStatus(403);
}
};
}
/**
* This is used to hash the password of the user
* when we need to use BCrypt.
*/
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(10);
}
/**
* This bean is load the user specific data when form login is used.
*/
#Bean
public UserDetailsService userDetailsService() {
return new MyCustomUserDetailsService(userDao);
}
#Bean
public RequestFetcher tokenProcessingFilter() throws Exception {
RequestFetcher tokenProcessingFilter = new RequestFetcher();
tokenProcessingFilter.setAuthenticationManager(authenticationManager());
return tokenProcessingFilter;
}
}
public class RequestFetcher extends UsernamePasswordAuthenticationFilter{
private String userName = "";
private String password = "";
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = this.getAsHttpRequest(request);
userName = httpRequest.getParameter("username");
System.out.println("===Username===" +userName);
password = httpRequest.getParameter("password");
System.out.println("===Password===" +password);
chain.doFilter(request, response);
}
private HttpServletRequest getAsHttpRequest(ServletRequest request){
if (!(request instanceof HttpServletRequest)) {
throw new RuntimeException("Expecting an HTTP request");
}
return (HttpServletRequest) request;
}
public String getUserName(){
return userName;
}
public void setUserName(String userName){
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Could anybody please help me to get the request parameters?

Resources