Spring Security not letting unauthorized users reach the login page - spring

I am using Spring Security and trying to add a custom login form, the browser does get redirected to the correct URL but I get a message along the lines of
The page isn’t redirecting properly
and can't see the login page at all.
Under the network tab (when I press F12) I see multiple requests to my custom login page, so I'm guessing Spring sees I'm unauthorized then redirects me to the login page over and over effectively creating a loop.
This is the code for my security configuration:
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/showMyLoginPage")
.permitAll();
return http.build();
}
Tried removing the loginPage() bit, solving the issue but yielding the default login page.
requested image
Request and response show no info..
Controller I'm using
#Controller
public class MainController {
#RequestMapping("/")
public String testMapping()
{
return "home";
}
#RequestMapping("/showMyLoginPage")
public String loginPage()
{
return "users-login";
}
}
My debug log: https://pastebin.com/LagTN71L
My configuration classes: (won't show hibernate or c3p0)
#Configuration
#EnableWebMvc
#ComponentScan("com.user.springsecuritydemo")
public class MainConfig implements WebMvcConfigurer {
#Bean
InternalResourceViewResolver configuInternalResourceViewResolver()
{
return new InternalResourceViewResolver("/WEB-INF/view/", ".jsp");
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
registry
.addResourceHandler("/resources/**")
.addResourceLocations("/resources/");
}
}
public class SpringMVCDispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses()
{
// TODO Auto-generated method stub
return null;
}
#Override
protected Class<?>[] getServletConfigClasses()
{
return new Class[] { MainConfig.class };
}
#Override
protected String[] getServletMappings()
{
return new String[] { "/" };
}
}

Okay, I ended up fixing it, so basically my jsp page is under my /WEBINF/ directory, which was not allowed for everyone to access therefore the browser couldn't get to the login page...
This is my SecurityFilterChain method:
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception
{
http
.authorizeHttpRequests()
.requestMatchers("/WEB-INF/**")
.permitAll();
http.authorizeHttpRequests()
.anyRequest()
.authenticated();
http
.formLogin()
.loginPage("/login")
.permitAll();
return http.build();
}

Related

Spring Security, remote user becomes null after session timeout

Here is my Spring Security config
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private String sLogoutUrl_;
private String sLoginPage_;
private String sLoginSuccessUrl_;
public WebSecurityConfig() {
sLogoutUrl_ = LnProperty.getSecurity(LnProperty.LOGOUTURL);
sLoginPage_ = LnProperty.getSecurity(LnProperty.LOGINPAGE);
sLoginSuccessUrl_ = LnProperty.getSecurity(LnProperty.LOGINSUCCESSURL);
}
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(username -> {
TomcatUser tomcatUser = LnProperty.getUser(username);
if (tomcatUser == null) {
throw new UsernameNotFoundException(username);
}
return new User(username, passwordEncoder().encode(tomcatUser.getPassword()), tomcatUser.getRoles());
});
}
#Override
protected void configure(final HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage(sLoginPage_)
.loginProcessingUrl(sLoginPage_)
.defaultSuccessUrl(sLoginSuccessUrl_, true)
.failureHandler(authenticationFailureHandler(sLoginPage_))
.and()
.logout()
.logoutUrl(sLogoutUrl_)
.logoutSuccessHandler(logoutSuccessHandler(sLoginPage_))
.deleteCookies("JSESSIONID");
}
#Bean
public AuthenticationFailureHandler authenticationFailureHandler(String failureUrl) {
return new CustomAuthenticationFailureHandler(failureUrl);
}
#Bean
public LogoutSuccessHandler logoutSuccessHandler(String successUrl) {
return new CustomLogoutSuccessHandler(successUrl);
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
I tried adding this to htpp but didn't work.
.and()
.rememberMe()
.alwaysRemember(true);
Is there a way to stay logged in even after session timeout? It's fine if session attributes are cleared but I want the remote user not to be nulled after session timeout. Only logout the user if the logout url is entered, the browser is closed, or cookies/caches are deleted.

Wrong redirection in Spring MVC app

Im going to be quick. I have a Spring MVC project, and Im using Spring Security, so after I successfully log in the server redirects me to the application context instead of the index page. Any idea why this is happening, I suspect it may be a security problem, but so far I haven´t figure it out, so please I need help on this one.
My login form action is this: ${loginUrl}
And the redirection problem only happens the first time i try to log in, if I log out and log in again the server redirects me correctly.
Here is my code:
Web Security Config class:
#EnableWebSecurity
#Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
ServicioInicioSesion inicioSesion;
#Autowired
MessageSource messageSource;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/addUsuarios").permitAll()
.antMatchers("/roles/**", "/usuarios/**").hasAuthority("Administrador")
.antMatchers("/editarPerfil").authenticated()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").defaultSuccessUrl("/index")
.permitAll()
.and()
.logout()
.invalidateHttpSession(true)
.clearAuthentication(true)
.logoutSuccessUrl("/login")
.and()
.exceptionHandling().accessDeniedPage("/403");
}
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/static/**");
}
#Bean(name = "authenticationManager")
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
auth.setUserDetailsService(inicioSesion);
auth.setMessageSource(messageSource);
auth.setPasswordEncoder(passwordEncoder());
return auth;
}
#Bean
public PasswordEncoder p`enter code here`asswordEncoder() {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
return passwordEncoder;
}
}
Index Controller class
#Controller
public class IndexController {
#RequestMapping(value = "/index", method = RequestMethod.GET)
public String showIndex() {
return "index";
}
}
Alberto. Try this one:
1 - replace value = "/index" by value = {"/","/index"}
2 - remove method parameter
#RequestMapping(value = {"/","/index"})
When you submit authentication form in the request you have POST data, but in your case you have RequestMethod.GET

Auth websocket session after manual web auth

I am using Spring Security with STOMP WebSocket on SpringBoot. Auth on websocket worked fine with this config when I used simple login form:
#EnableWebSecurity
#Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/webjars/**", "/resources/**").permitAll()
.antMatchers("/register").anonymous()
.anyRequest()
.fullyAuthenticated()
.and()
.formLogin()
.loginPage("/login")
.successHandler(customLoginSuccessHandler)
.failureUrl("/login?error")
.permitAll()
.and()
.csrf().disable()
.logout().logoutSuccessHandler(customLogoutSuccessHandler);
}
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
#Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages
.nullDestMatcher().authenticated()
.simpTypeMatchers(CONNECT).authenticated()
.simpSubscribeDestMatchers(Channel.SYSTEM_ERROR.value()).permitAll()
.simpDestMatchers("/app/publish*").hasRole("USER")
.simpSubscribeDestMatchers("/user/**", "/topic/**", "/system/*").hasRole("USER")
.anyMessage().denyAll();
}
But when I wanted to manually auth client after register new user in RegisterController:
#RequestMapping(value = "/register", method = RequestMethod.POST)
public String signup(#Valid #ModelAttribute SignupForm signupForm, Errors errors) {
if (errors.hasErrors()) {
return SIGNUP_VIEW_NAME;
}
User user = signupForm.createAccount();
try {
userService.persist(user);
} catch (EntityExistsException ex) {
errors.rejectValue("login", "user.exists");
return SIGNUP_VIEW_NAME;
}
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(user, null, Collections.singletonList(new SimpleGrantedAuthority("USER"))));
return "redirect:/";
}
I've got problem with auth websocket. When I get redirected to page where websocket connects I am getting org.springframework.security.access.AccessDeniedException: Access is denied
So. Problem was in define Role. In controller when I defined new SimpleGrantedAuthority("USER") it should be "ROLE_USER" because Spring adds refix ROLLE_ by default. Sure we can change default behaviour of this by add next in WebSecurity configuration
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**", "/favicon.ico");
web.expressionHandler(new DefaultWebSecurityExpressionHandler() {
#Override
protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, FilterInvocation fi) {
WebSecurityExpressionRoot root = (WebSecurityExpressionRoot) super.createSecurityExpressionRoot(authentication, fi);
root.setDefaultRolePrefix(""); //remove the prefix ROLE_
return root;
}
});
}
. Yes, dummy mistake but so common. So I will leave it here

Unable to use Session Management with Spring Boot

I have declared the following functions in an open source core banking solution based on Spring boot (Fineract) to limit the number of concurrent sessions per user to 1. My WebSecurity.java file is as follows:
#EnableWebSecurity
#Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/**").permitAll()
.anyRequest().authenticated()
.and()
.sessionManagement()
.maximumSessions(1)
.maxSessionsPreventsLogin(true)
.sessionRegistry(sessionRegistry());
}
// Work around https://jira.spring.io/browse/SEC-2855
#Bean
public SessionRegistry sessionRegistry() {
SessionRegistry sessionRegistry = new SessionRegistryImpl();
return sessionRegistry;
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("mifos").password("password").roles("USER");
}
// Register HttpSessionEventPublisher
#Bean
public static ServletListenerRegistrationBean httpSessionEventPublisher() {
return new ServletListenerRegistrationBean(new HttpSessionEventPublisher());
}
}
The SecurityWebApplicationInitializer.java is as follows:
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class[] { WebSecurityConfig.class };
}
}
However, I am still able to log into the system with multiple private browser windows opened. My assumption is that the problem is either with the SpringSecurityFilterChain not being registered with war, or with the way I am chaining the functions of the HttpSecurity object. Since I did not declare a customized login form or have defined any expired URL pages, I had to edit the steps shown in the following link: https://github.com/spring-projects/spring-boot/issues/1537 . Any leads on how to diagnose this issue? Thanks in advance.

How to configure custom authentication filter in spring security - using java config

I'm trying to configure a custom filter for spring security based authentication. It's a simple override of the usernamepasswordfilter. My problem is I don't know how to configure it using java configuration. Every time I hit "/admin/login" - it's entering my filter and causing an exception rather than going to the login page - but the antmatchers should be allowing access to /admin/login.
If I disable my filter, it works fine. I've read a few of the related questions but none seem to lead me to an answer.
Can anyone advise how to fix my configuration below to support the custom filter?
/**
* the security configuration.
*/
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
DataSource dataSource;
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
UserNotifier userNotifier() {
UserNotifier us = new UserNotifier();
return us;
}
#Bean
AuthenticationProvider customAuthenticationProvider() {
SystemUserAuthenticationProvider impl = new SystemUserAuthenticationProvider();
/* other properties etc */
return impl ;
}
#Bean
SystemUserService systemUserService(){
SystemUserService systemUserService = new SystemUserService();
return systemUserService;
}
#Bean
SystemAuthenticationFilter systemAuthenticationFilter() throws Exception {
SystemAuthenticationFilter f = new SystemAuthenticationFilter();
f.setAuthenticationManager(this.authenticationManager());
f.setPasswordParameter("password");
f.setUsernameParameter("email");
f.setPostOnly(true);
f.setAuthenticationFailureHandler(exceptionMappingAuthenticationFailureHandler());
f.setAuthenticationSuccessHandler(savedRequestAwareAuthenticationSuccessHandler());
f.setFilterProcessesUrl("/login");
return f;
}
#Bean
SavedRequestAwareAuthenticationSuccessHandler savedRequestAwareAuthenticationSuccessHandler(){
SavedRequestAwareAuthenticationSuccessHandler sv = new SavedRequestAwareAuthenticationSuccessHandler();
sv.setDefaultTargetUrl("/admin/customers");
return sv;
}
#Bean
AuditorAware<SystemUser> auditorAware(){
SystemUserAuditorAware adw = new SystemUserAuditorAware();
return adw;
}
#Bean
ExceptionMappingAuthenticationFailureHandler exceptionMappingAuthenticationFailureHandler(){
ExceptionMappingAuthenticationFailureHandler ex = new ExceptionMappingAuthenticationFailureHandler();
Map<String, String> mappings = new HashMap<String, String>();
mappings.put("org.springframework.security.authentication.CredentialsExpiredException", "/admin/login?reset");
mappings.put("org.springframework.security.authentication.LockedException", "/admin/login?locked");
mappings.put("org.springframework.security.authentication.BadCredentialsException", "/admin/login?error");
mappings.put("org.springframework.security.core.userdetails.UsernameNotFoundException", "/admin/login?error");
ex.setExceptionMappings(mappings);
return ex;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthenticationProvider());
}
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**")
;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/admin/login", "/admin/login/new**", "/admin/register", "/admin/logout", "/assets/**", "/admin/session/timeout").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().permitAll()
.and()
.formLogin()
.failureHandler(exceptionMappingAuthenticationFailureHandler())
.loginProcessingUrl("/login")
.loginPage("/admin/login")
.usernameParameter("username")
.passwordParameter("password")
.defaultSuccessUrl("/admin/orders")
.and()
.logout()
.logoutUrl("/logout")
.and()
.requiresChannel()
.antMatchers("/admin/**").requiresSecure()
.and()
.addFilterBefore(systemAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
Never mind, I fixed it by the changing the regex on the login processing url. It seemed to be interfering with the previous antmatcher.
So by changing the login processing url in the form login and custom filter configurations to "log_in", the login page now remains accessible without authorisation.

Resources