Generate JWT after spring security kerberos authentication - spring-security

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 !

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?

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

Error using #PreAuthorize

I'm developing a Spring Boot application where I'm trying to use the #PreAuthorize annotation to filter access to the User resource so that an User only can access to his own resource. Here is my UserRepository:
#Repository
#RepositoryRestResource
public interface MyUserRepository extends PagingAndSortingRepository<MyUser, UUID> {
#Override
#PreAuthorize("principal.getId().equals(#uuid)")
MyUser findOne(UUID uuid);
MyUser findByUsername(#Param("username") String username);
MyUser findByEmail(#Param("email") String email);
}
You can see the stack trace here.
Somewhere in the stacktrace references the class WebSecurityConfig line 42. This is the method configureAuthentication of the following class:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private RestAuthenticationEntryPoint unauthorizedHandler;
#Autowired
private BasicUserDetailsService userDetailsService;
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Autowired
public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.userDetailsService(this.userDetailsService)
.passwordEncoder(passwordEncoder());
}
#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 http) throws Exception {
http
// 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()
.antMatchers(HttpMethod.POST, "/login").permitAll()
.antMatchers(HttpMethod.POST, "/myUsers").permitAll()
.antMatchers(HttpMethod.PUT).authenticated()
.antMatchers(HttpMethod.POST).authenticated()
.antMatchers(HttpMethod.DELETE).authenticated()
.antMatchers(HttpMethod.PATCH).authenticated()
.anyRequest().permitAll();
// Custom JWT based security filter
http.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
http.addFilterBefore(new CORSFilter(), ChannelProcessingFilter.class);
}
}
Thank you!
Updating to Spring boot 1.4 has solved the problem.

usernamepasswordauthenticationfilter not getting invoked in spring security with oauth2 and formlogin

Trying to make spring security oauth2 and form login work in a spring boot application.
I took cues from
https://github.com/spring-projects/spring-security-oauth/tree/master/samples/oauth2/sparklr
and
https://github.com/royclarkson/spring-rest-service-oauth/issues/11
Below is my configuration
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Inject
private AjaxAuthenticationSuccessHandler ajaxAuthenticationSuccessHandler;
#Inject
private AjaxAuthenticationFailureHandler ajaxAuthenticationFailureHandler;
#Inject
private AjaxLogoutSuccessHandler ajaxLogoutSuccessHandler;
#Inject
private UserDetailsService userDetailsService;
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Inject
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
#Bean
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
return new SecurityEvaluationContextExtension();
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/scripts/**/*.{js,html}")
.antMatchers("/bower_components/**")
.antMatchers("/i18n/**")
.antMatchers("/assets/**")
.antMatchers("/swagger-ui/index.html")
.antMatchers("/api/register")
.antMatchers("/api/activate")
.antMatchers("/api/account/reset_password/init")
.antMatchers("/api/account/reset_password/finish")
.antMatchers("/api/home/**")
.antMatchers("/api/product/**")
.antMatchers("/test/**")
.antMatchers("/devadmin/**")
.antMatchers("/signin")
.antMatchers("/static/api-guide.html");
}
#Override
#Order(Ordered.HIGHEST_PRECEDENCE)
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable().authorizeRequests().antMatchers("/web/**","/for","/admin","/here").authenticated()
.and()
.formLogin()
.loginProcessingUrl("/web/authentication")
.successHandler(ajaxAuthenticationSuccessHandler)
.failureHandler(ajaxAuthenticationFailureHandler)
.usernameParameter("j_username")
.passwordParameter("j_password")
.permitAll()
.and()
.logout()
.logoutUrl("/web/logout")
.logoutSuccessHandler(ajaxLogoutSuccessHandler)
.deleteCookies("JSESSIONID")
.permitAll()
.and()
.exceptionHandling()
;
}
#Configuration
#EnableAuthorizationServer
#EnableConfigurationProperties(SecurityConfigurationProperties.class)
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter implements EnvironmentAware {
private static final String ENV_OAUTH = "authentication.oauth.";
private static final String PROP_CLIENTID = "clientid";
private static final String PROP_SECRET = "secret";
private static final String PROP_TOKEN_VALIDITY_SECONDS = "tokenValidityInSeconds";
private RelaxedPropertyResolver propertyResolver;
#Inject
private DataSource dataSource;
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
#Inject
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints
.tokenStore(tokenStore())
.authenticationManager(authenticationManager);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient(propertyResolver.getProperty(PROP_CLIENTID))
.scopes("read", "write")
.authorities(AuthoritiesConstants.ADMIN, AuthoritiesConstants.USER)
.authorizedGrantTypes("password", "refresh_token")
.secret(propertyResolver.getProperty(PROP_SECRET))
.accessTokenValiditySeconds(propertyResolver.getProperty(PROP_TOKEN_VALIDITY_SECONDS, Integer.class, 1800));
}
#Override
public void setEnvironment(Environment environment) {
this.propertyResolver = new RelaxedPropertyResolver(environment, ENV_OAUTH);
}
}
#Order(2)
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.requestMatchers().antMatchers("/api/**")
.and()
.authorizeRequests().antMatchers("/api /**").access("#oauth2.hasScope('read') and hasRole('ROLE_USER')");
// #formatter:on
}
}
}
With above configuration oauth2 login works fine when I try authenticating via
/oauth/token
However login via
/web/authentication
always shows
405 Request method 'POST' not supported
usernamepasswordauthenticationfilter is not getting invoked.
After commenting the ResourceServerConfiguration part in above code,
form login via
/web/authentication
is working fine.
Also I can see usernamepasswordauthenticationfilter being invoked from the logs.
My question is that even the end points are configured different for oauth2 resource server and form login, why oauth2 is overriding the httpsecurity for formlogin and why not usernamepasswordauthenticationfilter being called when resource server is configured?

Resources