spring security loadUserByUsername username empty after login url is not used for a few days - spring-security

#Autowired
private BCryptPasswordEncoder passwordEncoder;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(cUserDetailService)
.passwordEncoder(passwordEncoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/user/**").authenticated()
.and()
.csrf().disable()
.formLogin()
.usernameParameter("username")
.passwordParameter("password")
.successHandler(successHandler)
.failureHandler(failureHandler)
.and()
.logout()
.logoutSuccessHandler(logoutSuccessHandler)
.and()
.exceptionHandling()
.authenticationEntryPoint(authEntryPoint)
.accessDeniedHandler(accessDeniedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.maximumSessions(1)
.maxSessionsPreventsLogin(false);
}
public class CUserDetailService implements UserDetailsService {
#Autowired
private UserDetailDataEntityRepository userDetailDataEntityRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
log.info("username: " + username + ", " );
log.info(username == null);
Optional<UserDetailDataEntity> optional = userDetailDataEntityRepository.findByUsername(username);
if (optional.isPresent()) {
return optional.get();
} else {
throw new UsernameNotFoundException(username);
}
}
}
I used this config for my spring security, and got success login at first.
but then we find that if nobody access the server(even the login url) for a few days, and do login again the loadUserByUsername username will be empty and get login fail
FYI I used redis for session manage by adding dependency
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
and the login request is a form request

Related

JWT Bearer token not received?

I want to use Spring security to perform authentication and authorization on 2 separated server.
I've authenticated successfully and received a JWT token on the first server.
Now I am sending a request to the second server with the JWT authorization token, but the server can't see it; basically getHeader() from getJwtFromRequest(HttpServletRequest request) returns null.
This is the server code:
//imports...
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(
securedEnabled = true,
jsr250Enabled = true,
prePostEnabled = true
)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
CustomUserDetailsService customUserDetailsService;
#Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
#Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter();
}
#Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.userDetailsService(customUserDetailsService)
.passwordEncoder(passwordEncoder());
}
#Bean(BeanIds.AUTHENTICATION_MANAGER)
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/",
"/favicon.ico",
"/**/*.png",
"/**/*.gif",
"/**/*.svg",
"/**/*.jpg",
"/**/*.html",
"/**/*.css",
"/**/*.js")
.permitAll()
.antMatchers("/api/auth/**")
.permitAll()
.antMatchers("/api/user/checkUsernameAvailability", "/api/user/checkEmailAvailability")
.permitAll()
.antMatchers(HttpMethod.GET, "/api/polls/**", "/api/users/**")
.permitAll()
.anyRequest()
.authenticated();
// Add our custom JWT security filter
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
//imports...
public class JwtAuthenticationFilter extends OncePerRequestFilter {
#Autowired
private JwtTokenProvider tokenProvider;
#Autowired
private CustomUserDetailsService customUserDetailsService;
private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
try {
String jwt = getJwtFromRequest(request);
if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) {
Long userId = tokenProvider.getUserIdFromJWT(jwt);
UserDetails userDetails = customUserDetailsService.loadUserById(userId);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (Exception ex) {
logger.error("Could not set user authentication in security context", ex);
}
filterChain.doFilter(request, response);
}
private String getJwtFromRequest(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
// bearerToken prints null!
System.out.println("AUTHORIZATION: "+bearerToken);
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7, bearerToken.length());
}
return null;
}
}
But the token is present on the request:
The authorization header was stripped on the edge server

user impersonation using spring security in jhipster generated application

I have deployed the jhipster app as two node setup. When I login node1
and transfer the asset to another node 2 with different use role but I don't know password of the node 2 user. The requirement is that admin / super users are able to login as any other user and switch to original user. I have tried with SwitchUserFilter using spring security
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
#Import(SecurityProblemSupport.class)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final TokenProvider tokenProvider;
private final CorsFilter corsFilter;
private final SecurityProblemSupport problemSupport;
#Bean
public SwitchUserFilter switchUserFilter() {
SwitchUserFilter switchUserFilter = new SwitchUserFilter();
switchUserFilter.setUserDetailsService(userDetailsService());
switchUserFilter.setSwitchUserUrl("/impersonate");
switchUserFilter.setSwitchFailureUrl("/switchUser");
return switchUserFilter;
}
public SecurityConfiguration(TokenProvider tokenProvider, CorsFilter corsFilter, SecurityProblemSupport problemSupport) {
this.tokenProvider = tokenProvider;
this.corsFilter = corsFilter;
this.problemSupport = problemSupport;
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(HttpMethod.OPTIONS, "/**")
.antMatchers("/swagger-ui/index.html")
.antMatchers("/test/**");
}
#Override
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.csrf()
.disable()
.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
.exceptionHandling()
.authenticationEntryPoint(problemSupport)
.accessDeniedHandler(problemSupport)
.and()
.headers()
.frameOptions()
.disable()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/authenticate").permitAll()
.antMatchers("/api/register").permitAll()
.antMatchers("/api/activate").permitAll()
.antMatchers("/api/account/reset-password/init").permitAll()
.antMatchers("/api/account/reset-password/finish").permitAll()
.antMatchers("/api/**").authenticated()
.antMatchers("/management/health").permitAll()
.antMatchers("/management/info").permitAll()
.antMatchers("/management/prometheus").permitAll()
.antMatchers("/switchUser").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN)
.and()
.apply(securityConfigurerAdapter());
// #formatter:on
}
#Bean
#Override
public UserDetailsService userDetailsService() {
UserDetails user =
User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("ROLE_ADMIN")
.build();
UserDetails admin = User.withDefaultPasswordEncoder()
.username("admin")
.password("admin")
.roles("ROLE_ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
private JWTConfigurer securityConfigurerAdapter() {
return new JWTConfigurer(tokenProvider);
}
}
After making SwitchUserFilter changes in SecurityConfiguration.java, how do I invoke /impersonate url? Should I create rest endpoint in UserResource.java?

Generate JWT after spring security kerberos authentication

I would like to generate a JWT token after a kerberos authentication.
My kerberos authentication works very well.
Here my spring security kerberos configuration :
#Configuration
#EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Value("${app.service-principal}")
private String servicePrincipal;
#Value("${app.keytab-location}")
private String keytabLocation;
#Bean
public AuthenticationManager customAuthenticationManager() throws Exception {
return authenticationManager();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(spnegoEntryPoint())
.and()
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").permitAll()
.and()
.logout()
.permitAll()
.and()
.addFilterBefore(
spnegoAuthenticationProcessingFilter(authenticationManagerBean()),
BasicAuthenticationFilter.class);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(kerberosAuthenticationProvider())
.authenticationProvider(kerberosServiceAuthenticationProvider());
}
#Bean
public KerberosAuthenticationProvider kerberosAuthenticationProvider() {
KerberosAuthenticationProvider provider = new KerberosAuthenticationProvider();
SunJaasKerberosClient client = new SunJaasKerberosClient();
client.setDebug(true);
provider.setKerberosClient(client);
provider.setUserDetailsService(dummyUserDetailsService());
return provider;
}
#Bean
public SpnegoEntryPoint spnegoEntryPoint() {
return new SpnegoEntryPoint("/login");
}
#Bean
public SpnegoAuthenticationProcessingFilter spnegoAuthenticationProcessingFilter(
AuthenticationManager authenticationManager) {
SpnegoAuthenticationProcessingFilter filter = new SpnegoAuthenticationProcessingFilter();
filter.setAuthenticationManager(authenticationManager);
return filter;
}
#Bean
public KerberosServiceAuthenticationProvider kerberosServiceAuthenticationProvider() {
KerberosServiceAuthenticationProvider provider = new KerberosServiceAuthenticationProvider();
provider.setTicketValidator(sunJaasKerberosTicketValidator());
provider.setUserDetailsService(dummyUserDetailsService());
return provider;
}
#Bean
public SunJaasKerberosTicketValidator sunJaasKerberosTicketValidator() {
SunJaasKerberosTicketValidator ticketValidator = new SunJaasKerberosTicketValidator();
ticketValidator.setServicePrincipal(servicePrincipal);
ticketValidator.setKeyTabLocation(new FileSystemResource(keytabLocation));
ticketValidator.setDebug(true);
//ticketValidator.setHoldOnToGSSContext(true);
return ticketValidator;
}
#Bean
public DummyUserDetailsService dummyUserDetailsService() {
return new DummyUserDetailsService();
}
}
Is there a simple solution to generate a jwt token after this authentication?
Following my internet search, I found nothing interesting.
Thanks for your answers !

Spring Security multiple entry points - login process URL not found

I rewrite the security configuration class from this tutorial.
I try to enter the entries without login, the server redirect to the login page well, but submit the user credentials to login processing URL return page not found. How should I fix it?
My Spring Security configuration:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration {
#Autowired
#Qualifier("customUserDetailsService")
UserDetailsService userDetailsService;
#Autowired
PersistentTokenRepository tokenRepository;
#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
auth.authenticationProvider(authenticationProvider());
}
#Configuration
#Order(1)
ublic static class MobileSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/mobile/**")
.authorizeRequests()
.anyRequest().hasRole("MOBILE")
.and()
.formLogin()
.loginPage("/mobile_login")
.loginProcessingUrl("/mobile_login_processing_url")
.usernameParameter("ssoId")
.passwordParameter("password")
.defaultSuccessUrl("/mobile/menu")
.and()
.logout()
.logoutUrl("/mobile_logout")
.logoutSuccessUrl("/mobile_login?logout")
.deleteCookies("JSESSIONID")
.and()
.exceptionHandling()
.accessDeniedPage("/Access_Denied")
.defaultAuthenticationEntryPointFor(authenticationEntryPoint(), new AntPathRequestMatcher("/mobile/**"));
}
#Bean
Public AuthenticationEntryPoint authenticationEntryPoint(){
return new LoginUrlAuthenticationEntryPoint("/mobile_login");
}
}
#Configuration
#Order(2)
public static class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
PersistentTokenRepository tokenRepository;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/web/**").hasRole("ADMIN")
.and()
.formLogin()
.loginPage("/web_login")
.loginProcessingUrl("/web_login_processing_url")
.usernameParameter("ssoId")
.passwordParameter("password")
.defaultSuccessUrl("/web/list")
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/web_login?logout")
.deleteCookies("JSESSIONID")
.and()
.exceptionHandling().accessDeniedPage("/Access_Denied");
}
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
#Bean
public PersistentTokenBasedRememberMeServices getPersistentTokenBasedRememberMeServices() {
PersistentTokenBasedRememberMeServices tokenBasedservice = new PersistentTokenBasedRememberMeServices(
"remember-me", userDetailsService, tokenRepository);
return tokenBasedservice;
}
#Bean
public AuthenticationTrustResolver getAuthenticationTrustResolver() {
return new AuthenticationTrustResolverImpl();
}
}
Your login processing URL /mobile_login_processing_url is unavailable.
You configured a formLogin, which adds a UsernamePasswordAuthenticationFilter for a HttpSecurity, see FormLoginConfigurer:
The following Filters are populated
UsernamePasswordAuthenticationFilter
but your HttpSecurityis restricted to the pattern /mobile/**, see HttpSecurity#antMatcher:
Allows configuring the HttpSecurity to only be invoked when matching the provided ant pattern.
so with URL /mobile_login_processing_url the HttpSecurityis not invoked and therefore the UsernamePasswordAuthenticationFilter is never applied. Without this filter, the form login is not processible, see UsernamePasswordAuthenticationFilter:
Processes an authentication form submission.
You have to change your login processing URL to /mobile/mobile_login_processing_url. See your modified configuration:
#Configuration
#Order(1)
ublic static class MobileSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/mobile/**")
.authorizeRequests()
.anyRequest().hasRole("MOBILE")
.and()
.formLogin()
.loginPage("/mobile_login")
.loginProcessingUrl("/mobile/mobile_login_processing_url")
.usernameParameter("ssoId")
.passwordParameter("password")
.defaultSuccessUrl("/mobile/menu")
.and()
.logout()
.logoutUrl("/mobile_logout")
.logoutSuccessUrl("/mobile_login?logout")
.deleteCookies("JSESSIONID")
.and()
.exceptionHandling()
.accessDeniedPage("/Access_Denied")
.defaultAuthenticationEntryPointFor(authenticationEntryPoint(), new AntPathRequestMatcher("/mobile/**"));
}
#Bean
Public AuthenticationEntryPoint authenticationEntryPoint(){
return new LoginUrlAuthenticationEntryPoint("/mobile_login");
}
}

spring security add Granted autherity

I got some code from Internet.
Here is it:
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
CustomerBean customerBean = customerService.getCustomerBeanByEmail(userName);
if (customerBean == null) {
throw new UsernameNotFoundException("Invalid username or password");
} else if(!CustomerStatus.ACTIVATED.equals(customerBean.getStatus())) {
throw new LockedException("User account is locked");
}
return createCustomer(customerBean);
}
public void signIn(CustomerBean customer) {
SecurityContextHolder.getContext().setAuthentication(authenticate(customer));
}
private Authentication authenticate(CustomerBean customerBean) {
return new UsernamePasswordAuthenticationToken(createCustomer(customerBean), customerBean.getPassword(), createAuthority());
}
private User createCustomer(CustomerBean customerBean) {
return new CustomerDetailsImpl(customerBean, createAuthority());
}
private Set<GrantedAuthority> createAuthority() {
Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
return grantedAuthorities;
}
and my Configure method
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customerDetailsServiceImpl).passwordEncoder(new ShaPasswordEncoder(256));
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/resources/**").permitAll()
.antMatchers("/app/**").permitAll()
.antMatchers("/403").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").permitAll()
.failureUrl("/loginError")
.defaultSuccessUrl("/app/home", true)
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/logoutUser")
.permitAll()
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
.and()
.exceptionHandling().accessDeniedPage("/403")
.and()
.csrf().disable();
}
My question is: how to add the role to specific url?
Like has_user, has_admin what to add in code?
You can add the required roles for specific urls in the authorizeRequests section at the beginning of configure(HttpSecurity http) like
.antMatchers("/your/user/**").hasRole("user")
.antMatchers("/your/admin/url").hasRole("admin")

Resources