Spring Security SessionRegistry returning empty list - spring

Friends I have search a lot and try every solution available on the internet, but my problem not solved.
I want check (in Spring Boot web application) currently user logged in with the credentials specify in the login page, if there is a session with username currently, then invalidate that first a login again for the request.
I want to ensure there will be one session for the user, if session exist then invalidate and login forcefully.
I am trying to get all the principle from the SessionRegistry, but it always returning [] empty list even after multiple user logged in the system.
Here is my spring security config
...
#Autowired private CustomUserDetailsService customUserDetailsService;
#Autowired private CustomUrlAuthenticationSuccessHandler customUrlAuthenticationSuccessHandler;
#Autowired private PasswordEncoder passwordEncoder;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authProvider());
}
#Bean
JCaptchaAuthenticationFilter jCaptchaAuthenticationFilter() throws Exception {
JCaptchaAuthenticationFilter jCaptchaAuthenticationFilter = new JCaptchaAuthenticationFilter();
jCaptchaAuthenticationFilter.setAuthenticationManager(authenticationManager());
jCaptchaAuthenticationFilter.setAuthenticationFailureHandler(customLoginFailureHandler());
jCaptchaAuthenticationFilter.setAuthenticationSuccessHandler(customUrlAuthenticationSuccessHandler);
return jCaptchaAuthenticationFilter;
}
#Bean
public DaoAuthenticationProvider authProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(customUserDetailsService);
authProvider.setPasswordEncoder(passwordEncoder);
return authProvider;
}
#Bean
public CustomLoginFailureHandler customLoginFailureHandler() {
CustomLoginFailureHandler customLoginFailureHandler = new CustomLoginFailureHandler("/login");
return customLoginFailureHandler;
}
#Override
protected void configure(HttpSecurity http) throws Exception {// #formatter:off
http.authorizeRequests().antMatchers("/js/**", "/fonts/**", "/css/**", "/images/**", "/favicon.ico").permitAll()
.antMatchers("/", "/register/**", "/email/**", "/captcha.png/**").permitAll().antMatchers("/login/**")
.permitAll()// Basically I'm allowing parameters for login so
// .antMatchers("/services/**").permitAll()
.antMatchers("/forgot/password/**", "/user/verify/**").permitAll().antMatchers("/user/resetPassword*")
.hasAuthority("CHANGE_PASSWORD_PRIVILEGE").anyRequest().authenticated().and()
.addFilterBefore(jCaptchaAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class).formLogin()
.loginPage("/login").permitAll().and()
.csrf().disable()
.sessionManagement().invalidSessionUrl("/invalidSession")
.maximumSessions(1)
.maxSessionsPreventsLogin(true)
.sessionRegistry(sessionRegistry()).and()
.sessionFixation().newSession().and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/")
.invalidateHttpSession(false).deleteCookies("JSESSIONID").permitAll();
http.headers().frameOptions().sameOrigin();
}
....
#Bean
SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
#Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
Here is i am getting sessions list
List<String> userList = sessionRegistry.getAllPrincipals().stream()
.filter(u -> !sessionRegistry.getAllSessions(u, true).isEmpty())
.map(Object::toString)
.collect(Collectors.toList());
But above code always return empty list. I have checked is there any double sessionRegistry loading by disabling sessionRepositry, but spring throw exception that bean not found.
Please help friends.

Related

Spring boot + LDAP form login, logout and validating the token after login

I am integrating spring boot with LDAP to Authenticate a user. So that only authenticated users can only access the API.
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
LdapAuthenticationProvider authenticationProvider(final LdapAuthenticator authenticator) {
return new LdapAuthenticationProvider(authenticator);
}
#Bean
BindAuthenticator authenticator(final BaseLdapPathContextSource contextSource) {
final BindAuthenticator authenticator = new BindAuthenticator(contextSource);
authenticator.setUserDnPatterns(new String[] {
"xx" });
return authenticator;
}
#Override
public void configure(final AuthenticationManagerBuilder auth) throws Exception {
auth.ldapAuthentication().userSearchFilter("(sAMAccountName={0})")
.contextSource(contextSource());
}
#Override
protected void configure(final HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.formLogin().and()
.authorizeRequests()
.anyRequest().fullyAuthenticated().and().logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login");
}
#Override
public void configure(final WebSecurity web) throws Exception {
web.debug(true);
}
#Bean
LdapContextSource contextSource() {
final LdapContextSource contextSource = new LdapContextSource();
contextSource.setUrl("xx);
contextSource.setBase("xx");
contextSource.setUserDn("xx");
contextSource.setPassword("xx");
contextSource.setPooled(true);
contextSource.afterPropertiesSet();
return contextSource;
}
#Bean
public LdapTemplate ldapTemplate() {
final LdapTemplate ldapTemplate = new LdapTemplate(
contextSource());
ldapTemplate.setIgnorePartialResultException(true);
return ldapTemplate;
}
}
I am using the inbuild form login.
Question
Who (which class) is responsible to create a success token and where is it stored and in successive calls how is it validated?
Now I am only redirecting the unauthenticated calls to the login page due to this it giving 200 success responses, How to override this and send 401
Edited:
I have one specific question
If there is no token, the user is stored in the session -> how subsequent requests are validated. Which all classes are used

Spring Security basic auth for REST Api single login needed?

I am using Spring Security basic auth for my REST API.
Initially I get unauthorized HTTP response status for unauthenticated secured routes.
If I provide the right credentials, I get a Ok HTTP response status, but after a single successful login, I can access all the secured routes without providing user credentials.
Here are my questions:
Is it the correct behaviour for basic authentication?
Why it happens?
My security config:
#Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserService userService;
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userService);
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
//J-
http.csrf().disable()
.authorizeRequests()
.antMatchers("/save")
.permitAll()
.and()
.authorizeRequests()
.antMatchers("/h2-console/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.httpBasic();
//J+
//adding support for h2 console, otherwise crashes
http.headers().frameOptions().disable();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(authenticationProvider());
}
}
and here is the UserDetailsService's loadByUsername() method:
#Override
public UserDetails loadUserByUsername(String username) {
User user = userRepository.findByUsername(username);
if (user == null) {
throw new UserNotFoundException(username);
} else if (UserStatus.Deactivated.equals(user.getStatus())) {
throw new UserDeactivatedException(username);
}
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), Collections.singleton(new SimpleGrantedAuthority("USER")));
}
https://www.baeldung.com/spring-security-session
Refer mentioned link. For Restful API’s use stateless session policy

Spring Oauth 2 Facebook Authentication Redirects User To My Home Page

I am trying to redirect a user who have been authenticated to another page other than the home page. I am using spring boot 1.5.6 and Oauth 2. User is authenticated but was redirected to the home page. I don't understand why this is happening. Please, someone should help me. Some answers to related problem on stackoverflow and the internet didn't help me.
Here is my SecurityConfig file
#Configuration
#EnableGlobalAuthentication
#EnableOAuth2Client
#EnableGlobalMethodSecurity(prePostEnabled = true)
#Order(2)
public class SecurityConfig extends WebSecurityConfigurerAdapter{
protected final Log logger = LogFactory.getLog(getClass());
#Autowired
private OAuth2ClientContext oauth2ClientContext;
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private GeneralConfig generalConfig;
#Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/user*")
.access("hasRole('CUSTOMER')")
.and()
.formLogin()
.loginPage("/loginUser")
.loginProcessingUrl("/user_login")
.failureUrl("/loginUser?error=loginError")
.defaultSuccessUrl("/customer/dashboard")
.and()
.logout()
.logoutUrl("/user_logout")
.logoutSuccessUrl("/loginUser").permitAll()
.deleteCookies("JSESSIONID")
.and()
.exceptionHandling()
.accessDeniedPage("/403")
.and()
.csrf().disable()
.addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).
passwordEncoder(bCryptPasswordEncoder());
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws
Exception {
auth.userDetailsService(userDetailsService);
}
#Bean
public FilterRegistrationBeanoauth2ClientFilterRegistration
(OAuth2ClientContextFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(filter);
registration.setOrder(-100);
return registration;
}
private Filter ssoFilter(ClientResources client, String path) {
OAuth2ClientAuthenticationProcessingFilter filter = new
OAuth2ClientAuthenticationProcessingFilter(path);
OAuth2RestTemplate template = new
OAuth2RestTemplate(client.getClient(), oauth2ClientContext);
filter.setRestTemplate(template);
UserInfoTokenServices tokenServices = new
UserInfoTokenServices(client.getResource().getUserInfoUri(),
client.getClient().getClientId());
tokenServices.setRestTemplate(template);
filter.setTokenServices(tokenServices);
return filter;
}
private Filter ssoFilter() {
CompositeFilter filter = new CompositeFilter();
List<Filter> filters = new ArrayList<>();
filters.add(ssoFilter(facebook(), "/signin/facebook"));
filters.add(ssoFilter(google(), "/signin/google"));
filter.setFilters(filters);
return filter;
}
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
#ConfigurationProperties("google")
public ClientResources google() {
return new ClientResources();
}
#Bean
#ConfigurationProperties("facebook")
public ClientResources facebook() {
return new ClientResources();
}
}
From the SecurityConfig I expect the user upon successful authentication to be redirected to customer/dashboard so that I can do further processing. I know the user is authenticated because I can access their data. It's not just redirecting to the right page
But instead it keep redirecting the user to the home page. What am I doing wrong? I also have another Security Config File for admin. I can provide it if required.
To change the default strategy, you have to set an AuthenticationSuccessHandler, see AbstractAuthenticationProcessingFilter#setAuthenticationSuccessHandler:
Sets the strategy used to handle a successful authentication. By default a SavedRequestAwareAuthenticationSuccessHandler is used.
Your modified code:
private Filter ssoFilter(ClientResources client, String path) {
OAuth2ClientAuthenticationProcessingFilter filter = new OAuth2ClientAuthenticationProcessingFilter(path);
OAuth2RestTemplate template = new OAuth2RestTemplate(client.getClient(), oauth2ClientContext);
filter.setRestTemplate(template);
UserInfoTokenServices tokenServices = new UserInfoTokenServices(client.getResource().getUserInfoUri(),client.getClient().getClientId());
tokenServices.setRestTemplate(template);
filter.setTokenServices(tokenServices);
filter.setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler("/customer/dashboard")‌​;
return filter;
}

Logout with Rest Template in Spring Security Application

I'm writing a client for my application. Spring stack is Spring 4 and Spring Security 4 (main parts).
I try to logout from my application in the following way:
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<String> entity = new HttpEntity<>("_csrf=" + csrfToken,
httpHeaders);
restTemplate.postForEntity(appUrl + "/logout", entity, String.class);
A RestTemplate object is created in the following way (before login of course):
new RestTemplate(new HttpComponentsClientHttpRequestFactory())
But I get the following exception on the server:
org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported at
org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping.handleNoMatch(RequestMappingInfoHandlerMapping.java:207) at
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.lookupHandlerMethod(AbstractHandlerMethodMapping.java:374) at
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:314) at
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:61) at
org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:352)
I was getting the following exception when I tried to login in the app. The only
way I managed to do it is getting login page and getting CSRF token from there. I tried to get token from the server in the following way and return it to the client:
#RequestMapping(value = "/api/csrf", method = RequestMethod.GET)
public String csrf(HttpServletRequest httpServletRequest) {
return ((CsrfToken) httpServletRequest.getAttribute(CsrfToken.class.getName())).getToken();
}
But with this token I was getting the same exception all the time.
Now I want to implement logout in any way at least but notes related to proper login with RestTemplate is appreciated too. Thanks!
UPDATE: adding security config
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final DataSource dataSource;
private final UserDetailsService splittingRolesUserDetails;
private final AccessDeniedHandler accessDeniedHandler;
#Autowired
public SecurityConfig(DataSource dataSource, UserDetailsService splittingRolesUserDetails,
AccessDeniedHandler accessDeniedHandler) {
this.dataSource = dataSource;
this.splittingRolesUserDetails = splittingRolesUserDetails;
this.accessDeniedHandler = accessDeniedHandler;
}
// overrides role prefix in case .access() in httpSecurity configuration
// just because it is needed in the task. hasRole() won't work
// as there are used different voters in AffirmativeBased.
// link to the related issue on GitHub:
// https://github.com/spring-projects/spring-security/issues/3701
#Bean
GrantedAuthorityDefaults grantedAuthorityDefaults() {
return new GrantedAuthorityDefaults("");
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.authenticationProvider(authenticationProvider())
.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery("select user_name, password, true from user where username=?");
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(splittingRolesUserDetails);
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
#Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.authorizeRequests()
.antMatchers("/login/**").permitAll()
.antMatchers("/api/csrf").permitAll()
.antMatchers("/api/ticket/event**").access("hasRole('" + Role.BOOKING_MANAGER.toString() + "')")
.anyRequest().access("hasRole('" + Role.REGISTERED_USER.toString() + "')")
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/event")
.permitAll()
.and()
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler)
.accessDeniedPage("/403")
.and()
.rememberMe()
.userDetailsService(splittingRolesUserDetails);
}
}
No need to send your token from an endpoint that is not secured, that contradicts the principle for which the token is used in the first place. You can store your token in a cookie with HTTP only access by adding this to your config:
.and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
You can then retrieve it from a cookie named XSRF-TOKEN.

Spring - Add a check for 3rd parameter during authentication

At a glance, I have API Back-end App written in Spring Boot which uses JWT for secured data transmission. I want to add 3rd parameter for authorization, so I should have login, password and storeID parameters. I am inspired by this answer How implement Spring security when login page having more field apart from user name and password? but when I followed proposed solution my 3rd parameter in not used. My impression is that I am missing something important in Security Config. Could you please point to my mistake?
SecurityConfig
#SuppressWarnings("SpringJavaAutowiringInspection")
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private AuthenticationDetailsSource<HttpServletRequest, ?> webAuthenticationDetailsSourceImpl;
#Autowired
public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.authenticationProvider(myAuthProvider());
}
#Bean
public CustomUserDetailsAuthenticationProvider myAuthProvider() throws Exception {
CustomUserDetailsAuthenticationProvider provider = new CustomUserDetailsAuthenticationProvider();
provider.setPasswordEncoder(passwordEncoder());
provider.setUserDetailsService(userDetailsService);
return provider;
}
#Bean
public UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter() throws Exception {
UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter = new UsernamePasswordAuthenticationFilter();
usernamePasswordAuthenticationFilter.setAuthenticationManager(authenticationManager());
usernamePasswordAuthenticationFilter.setAuthenticationDetailsSource(webAuthenticationDetailsSourceImpl);
return usernamePasswordAuthenticationFilter;
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public JwtAuthenticationTokenFilter authenticationTokenFilterBean() throws Exception {
JwtAuthenticationTokenFilter authenticationTokenFilter = new JwtAuthenticationTokenFilter();
authenticationTokenFilter.setAuthenticationManager(authenticationManagerBean());
return authenticationTokenFilter;
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
// we don't need CSRF because our token is invulnerable
.csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
// don't create session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
// allow anonymous resource requests
.antMatchers(
HttpMethod.GET,
"/",
"/*.html",
"/favicon.ico",
"/**/*.html",
"/**/*.css",
"/**/*.js"
).permitAll()
.antMatchers("/auth/**").permitAll()
.anyRequest().authenticated();
// Custom JWT based security filter
httpSecurity
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
// disable page caching
httpSecurity.headers().cacheControl();
}
}
I was under impression I can check against storeID field in WebAuthenticationDetailsSourceImpl, but looks like it has never been executed because I don't see anything related in log.
WebAuthenticationDetailsSourceImpl:
#Component
public class WebAuthenticationDetailsSourceImpl implements AuthenticationDetailsSource<HttpServletRequest, JwtAuthenticationRequest> {
#Override
public JwtAuthenticationRequest buildDetails(HttpServletRequest context) {
System.out.println("___#####_____");
System.out.println(context);
System.out.println("___#####_____");
return new JwtAuthenticationRequest();
}
}
cuz you don't insert "your" usernamePasswordAuthenticationFilter that set webAuthenticationDetailsSourceImpl to Spring Security's authentication filter chain.
perhaps current your authentication filter chain is
~
JwtAuthenticationTokenFilter
(Spring Security's original)UsernamePasswordAuthenticationFilter
~
hence,if you want to retrieve your additional parameter in "your" usernamePasswordAuthenticationFilter add this filter too like a JwtAuthenticationTokenFilter
but , if you want to simply retrieve parameter at JwtAuthenticationTokenFilter
use setAuthenticationDetailsSource at there
#Bean
public JwtAuthenticationTokenFilter authenticationTokenFilterBean() throws Exception {
JwtAuthenticationTokenFilter authenticationTokenFilter = new JwtAuthenticationTokenFilter();
authenticationTokenFilter.setAuthenticationManager(authenticationManagerBean());
authenticationTokenFilter.setAuthenticationDetailsSource(webAuthenticationDetailsSourceImpl);
return authenticationTokenFilter;
}

Resources