Can't disable default login page of spring security - spring

I'm using spring boot 2.5.5 with spring cloud 2020.0.4 and in my gateway I want to apply a filter to check the token(jwt) is valid or not ? and authorize just one path before the first connection.
and even if I enable the web security or (exclude = { SecurityAutoConfiguration.class }) or http.httpBasic().disabled().. I'm always redirected to spring security login page (localhost:9092/login)
#Configuration
#EnableWebSecurity
public class SecurityTokenConfig extends WebSecurityConfigurerAdapter {
private static Logger logger = LoggerFactory.getLogger(SecurityTokenConfig.class);
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.exceptionHandling().authenticationEntryPoint((req, rsp, e) -> rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED)).and()
.addFilterAfter(new JwtTokenAuthenticationFilter(jwtConfig()), UsernamePasswordAuthenticationFilter.class)=
.authorizeRequests().antMatchers("/**/auth-api/**")
.permitAll();
// http.authorizeRequests().antMatchers("/resources/**", "/favicon.ico", "/logout").permitAll();
if (http.cors() != null) {
logger.info(new StringBuilder("Config").append(http.cors().toString()).toString());
} else {
logger.info(" Security Config cors conf is null");
}

Related

Spring Security with OAuth2(Keycloak) disable default login page

I have successfully configured Spring Boot Spring Security with Keycloak. Everything works fine. In order to login, I use the following URL: http://localhost:8081/realms/MY_REALM_NAME
But when I try to access the following page: http://localhost:8080/login I see the following page:
I'd like to disable/remove this page. How to properly configure it with Spring Security?
UPDATED
My SpringSecurity configuration:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfiguration extends VaadinWebSecurityConfigurerAdapter {
private final ClientRegistrationRepository clientRegistrationRepository;
private final GrantedAuthoritiesMapper authoritiesMapper;
private final ProfileService profileService;
SecurityConfiguration(ClientRegistrationRepository clientRegistrationRepository,
GrantedAuthoritiesMapper authoritiesMapper, ProfileService profileService) {
this.clientRegistrationRepository = clientRegistrationRepository;
this.authoritiesMapper = authoritiesMapper;
this.profileService = profileService;
SecurityContextHolder.setStrategyName(VaadinAwareSecurityContextHolderStrategy.class.getName());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
// Enable OAuth2 login
.oauth2Login(oauth2Login ->
oauth2Login
.clientRegistrationRepository(clientRegistrationRepository)
.userInfoEndpoint(userInfoEndpoint ->
userInfoEndpoint
// Use a custom authorities mapper to get the roles from the identity provider into the Authentication token
.userAuthoritiesMapper(authoritiesMapper)
)
// Use a Vaadin aware authentication success handler
.successHandler(new KeycloakVaadinAuthenticationSuccessHandler(profileService))
)
// Configure logout
.logout(logout ->
logout
// Enable OIDC logout (requires that we use the 'openid' scope when authenticating)
.logoutSuccessHandler(logoutSuccessHandler())
// When CSRF is enabled, the logout URL normally requires a POST request with the CSRF
// token attached. This makes it difficult to perform a logout from within a Vaadin
// application (since Vaadin uses its own CSRF tokens). By changing the logout endpoint
// to accept GET requests, we can redirect to the logout URL from within Vaadin.
.logoutRequestMatcher(new AntPathRequestMatcher("/logout", "GET"))
);
}
#Bean
#Primary
public SpringViewAccessChecker springViewAccessChecker(AccessAnnotationChecker accessAnnotationChecker) {
return new KeycloakSpringViewAccessChecker(accessAnnotationChecker, "/oauth2/authorization/keycloak");
}
private OidcClientInitiatedLogoutSuccessHandler logoutSuccessHandler() {
var logoutSuccessHandler = new OidcClientInitiatedLogoutSuccessHandler(clientRegistrationRepository);
logoutSuccessHandler.setPostLogoutRedirectUri("{baseUrl}");
return logoutSuccessHandler;
}
#Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
// Don't apply security rules on our static pages
web.ignoring().antMatchers("/session-expired");
}
#Bean
public PolicyFactory htmlSanitizer() {
// This is the policy we will be using to sanitize HTML input
return Sanitizers.FORMATTING.and(Sanitizers.BLOCKS).and(Sanitizers.STYLES).and(Sanitizers.LINKS);
}
}
Have tried formLogin().disable() method?
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
//your config here
.and().formLogin().disable();
}

spring boot actuator endpoints with Keycloak security

we have a spring boot project (2.3.0.RELEASE) with actuator endpoints and we are introducing keycloak to the project with KeycloakWebSecurityConfigurerAdapter how can I prevent actuator endpoints being secured by the keycloak filter chain.
We would like to have the "/actuator/**" endpoints secured by basic auth.
Currently we have a custom WebSecurityConfigurerAdapter with #Order(1) where we apply the basic auth to "/actuator/**" and then we have with #Order(2) antotated the KeycloakWebSecurityConfigurerAdapter
so 2 filter chains gets registered and when I call the actuator endpoints the second filter chain fails as unauthorised 401
is it possible to prevent handling the "/actuator/**" resorce path on the second filter chain?
First actuator security configuration.
#Configuration
#Order(1)
public class ActuatorWebSecurityConfig extends WebSecurityConfigurerAdapter {
private final String username;
private final String password;
private final PasswordEncoder encoder;
public ActuatorWebSecurityConfig(
#Value("${spring.security.user.name}") String username,
#Value("${spring.security.user.password}") String password,
Optional<PasswordEncoder> encoder) {
this.username = username;
this.password = password;
this.encoder = encoder.orElseGet(PasswordEncoderFactories::createDelegatingPasswordEncoder);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser(username)
.password(encoder.encode(password))
.roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.antMatcher("/actuator/**")
.authorizeRequests(authorize -> authorize.anyRequest().authenticated())
.httpBasic(Customizer.withDefaults());
}
}
second keycloak securoty configuration
#Order(2)
#KeycloakConfiguration
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
private final String swaggerUrl;
private final CorsFilter corsFilter;
private final CustomSecurityConfig customSecurityConfig;
#Autowired
public SecurityConfig(
#Value("${springdoc.swagger-ui.url:#{null}}") String swaggerUrl,
CorsFilter corsFilter,
CustomSecurityConfig customSecurityConfig) {
this.swaggerUrl = swaggerUrl;
this.corsFilter = corsFilter;
this.customSecurityConfig = customSecurityConfig;
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
KeycloakAuthenticationProvider keycloakProvider = keycloakAuthenticationProvider();
keycloakProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakProvider);
}
#Bean
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new NullAuthenticatedSessionStrategy();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.csrf().disable()
.requestMatcher(new NegatedRequestMatcher(new AntPathRequestMatcher("/actuator/**")));
.headers().frameOptions().disable()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/public/**", "/resources/**", "/resources/public/**").permitAll()
.antMatchers(OPTIONS, "/**").permitAll();
.authorizeRequests()
.antMatchers("/**")
.authenticated();
}
}
I have tried with on keycloak config
.antMatchers("/actuator/**").permitAll();
and with
http.requestMatcher(new NegatedRequestMatcher(new AntPathRequestMatcher("/actuator/**")));
but nothing works I receive unauthorised 401 for actuator
the registered filter chains :
2022-01-18 17:38:44,688 INFO org.springframework.security.web.DefaultSecurityFilterChain [main] Creating filter chain: Ant [pattern='/actuator/**'], [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter#25c6a9de, org.springframework.security.web.context.SecurityContextPersistenceFilter#56f3f9da, org.springframework.security.web.header.HeaderWriterFilter#33dcbdc2, org.springframework.security.web.csrf.CsrfFilter#522fdf0c, org.springframework.security.web.authentication.logout.LogoutFilter#365ad794, org.springframework.security.web.authentication.www.BasicAuthenticationFilter#23df16cf, org.springframework.security.web.savedrequest.RequestCacheAwareFilter#227cba85, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter#b38dc7d, org.springframework.security.web.authentication.AnonymousAuthenticationFilter#142422a4, org.springframework.security.web.session.SessionManagementFilter#2f0b7b6d, org.springframework.security.web.access.ExceptionTranslationFilter#74bca236, org.springframework.security.web.access.intercept.FilterSecurityInterceptor#30587737]
2022-01-18 17:38:44,691 INFO org.springframework.security.web.DefaultSecurityFilterChain [main] Creating filter chain: NegatedRequestMatcher [requestMatcher=Ant [pattern='/actuator/**']], [com.betex.auth.filters.CorsFilter#20a9f5fb, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter#10e28d97, org.springframework.security.web.context.SecurityContextPersistenceFilter#c6b08a5, org.springframework.security.web.header.HeaderWriterFilter#5f05cd7e, org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter#2a54c92e, org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter#55b62db8, org.springframework.security.web.authentication.logout.LogoutFilter#274f51ad, org.springframework.security.web.savedrequest.RequestCacheAwareFilter#54980154, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter#25874884, org.keycloak.adapters.springsecurity.filter.KeycloakSecurityContextRequestFilter#8cb7185, org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticatedActionsFilter#4dac40b, org.springframework.security.web.authentication.AnonymousAuthenticationFilter#37d43b9b, org.springframework.security.web.session.SessionManagementFilter#11e8e183, org.springframework.security.web.access.ExceptionTranslationFilter#56f1db5f, org.springframework.security.web.access.intercept.FilterSecurityInterceptor#78543f0d]
When you extend KeycloakWebSecurityConfigurerAdapter, the adapter register a Bean of type KeycloakAuthenticationProcessingFilter. This filter is registered in the Spring Security's SecurityFilterChain, and because it's a Bean, it is also automatically registered by Spring Boot in the original chain, therefore even if Spring Security doesn't apply it, it will be applied later on in original the filter chain.
Try disabling this filter from being registered by Spring Boot, like so:
#Bean
public FilterRegistrationBean registration(KeycloakAuthenticationProcessingFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean(filter);
registration.setEnabled(false);
return registration;
}
In addition, if you are using OAuth 2, you may consider using spring-security-oauth2-resource-server and simplifying your Resource Server's configuration. Take a look at the documentation. This way you don't need to extend the custom adapter, just rely on the out-of-the-box configuration from Spring Security.

Spring Security ignore few urls few urls basic auth remaining all JWTTokenAuth

In my application, i need to implement different spring securities based on different URL. for /app/healthcheck need to ignore security, for /app/manage need to have basic authentication, for remaining all other /api/** need JWT Token authentication. Implemented like below
#Configuration
#EnableWebSecurity
public class WebSecurityConfig {
#Bean
WebSecurityConfigurerAdapter defaultConfig() {
return new WebSecurityConfigurerAdapter() {
#Override
protected void configure(HttpSecurity http) throws Exception {
configureHttpSecurity(http.csrf().disable().headers().frameOptions().disable().and(),
authenticationManager());
}
};
}
void configureHttpSecurity(HttpSecurity http, AuthenticationManager authenticationManager) throws Exception {
http.authorizeRequests().antMatchers("/app/healthcheck").permitAll().anyRequest()
.authenticated().and()
.addFilterBefore(new MyJWTAuthenticationFilter(authenticationManager),
UsernamePasswordAuthenticationFilter.class)
.logout().permitAll();
}
#Bean
public UserAuthenticationProvider springAuthenticationProvider() {
return new UserAuthenticationProvider();
}
}
#Configuration
#EnableWebSecurity
#Order(Ordered.HIGHEST_PRECEDENCE)
public class BasicSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.cors();
http.antMatcher("/app/manage")
.authorizeRequests().anyRequest().authenticated()
.and()
.httpBasic();
}
}
in application.yml added
spring:
profiles: dev
security:
user:
name: ${admin}
password: ${password}
when i run the app, /app/healthcheck ignoring security, remaining all other asking for JWT authentication. but /app/manage also triggering JWT authentication instead of basic auth. If i comment Token auth, basic is working perfect.
am new to spring security please let me know what am i missing.
Thank You.

Spring (boot) Security preauthentication with permitted resources still authenticated

I am using Spring Boot 1.5.6 (also have tried with 1.5.4).
I am using a
RequestHeaderAuthenticationFilter
and a
PreAuthenticatedAuthenticationProvider
to secure my spring mvc web app and also permit access to both a controller path and static resources.
In my
RequestHeaderAuthenticationFilter
set up I want
setExceptionIfHeaderMissing(true);
so that I know if the header variable has been sent in the request.
When I try to access any of the permitted resources, Spring Security always looks for the header variable in the request and throws a
PreAuthenticatedCredentialsNotFoundException
Why is spring security still trying to look up the preauthenticated principal even though I am trying to access a permitted (non-protected) resource?
How can I circumvent this behaviour?
My java config for WebSecurityConfigurerAdapter is below
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
private static final Logger log = LoggerFactory.getLogger(SecurityConfig.class);
#Autowired
protected UserDetailsService userDetailsService;
#Bean
public PreAuthenticatedAuthenticationProvider preAuthenticatedAuthenticationProvider(){
log.info("Configuring pre authentication provider");
UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken> wrapper =
new UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken>(
userDetailsService);
PreAuthenticatedAuthenticationProvider it = new PreAuthenticatedAuthenticationProvider();
it.setPreAuthenticatedUserDetailsService(wrapper);
return it;
}
#Bean
public RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter() throws Exception{
RequestHeaderAuthenticationFilter it = new RequestHeaderAuthenticationFilter();
it.setAuthenticationManager(authenticationManager());
it.setExceptionIfHeaderMissing(true);
return it;
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
log.info("configure authentication provider");
auth.authenticationProvider(preAuthenticatedAuthenticationProvider());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
log.info("Configure HttpSecurity");
http
.authorizeRequests()
.antMatchers("/permitted/**", "/css/**", "/js/**", "/images/**", "/webjars/**")
.permitAll()
.anyRequest()
.authenticated()
.and().addFilter(requestHeaderAuthenticationFilter())
;
}
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/permitted/**", "/css/**", "/js/**", "/images/**", "/webjars/**");
}
}
I had the same problem and it turned out it was related to the fact that in addition to being registered in the SecurityFilterChain, Spring Boot was also registering the RequestHeaderAuthenticationFilter with the Servlet Context. The solution is to use a FilterRegistrationBean to prevent Boot from auto registering the filter with the Servlet Context.
More details here:
Spring Boot Security PreAuthenticated Scenario with Anonymous access

Spring Boot Management security works differently with port set

I'm trying to configure a Spring Boot application (1.2.3, but this also fails with the 1.2.4.BUILD-SNAPSHOT version) with Actuator support. I want to use the Actuator security config for controlling access to the management endpoints, and our own authentication for the rest of the application.
Here is my security config:
#Configuration
#EnableWebSecurity
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
{
#Autowired
private CustomAuthenticationProvider customAuthProvider;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth.authenticationProvider(customAuthProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.authorizeRequests()
.regexMatchers(API_DOC_REGEX).permitAll()
.regexMatchers(String.format(PATH_REGEX, PUBLIC_ACCESS)).permitAll()
.regexMatchers(String.format(PATH_REGEX, INTERNAL_ACCESS)).access("isAuthenticated() && authentication.hasOrigin('INTERNAL')")
.regexMatchers(String.format(PATH_REGEX, EXTERNAL_AUTHENTICATED_ACCESS)).authenticated()
.antMatchers("/**").denyAll()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER)
.and()
.addFilterAfter(customAuthProcessingFilter(), BasicAuthenticationFilter.class)
.csrf().disable();
}
}
This works correctly when I don't set a management port, but when I set the management port, the management URLs return 401 responses. If I comment out the line .antMatchers("/**").denyAll(), then everything goes through without requiring authentication at all. So it looks like it is using my application's security config for the Actuator endpoints when I set a custom port, but I'm not sure why.
How do I get it to use it's own security when running on a custom port?
Expanding on the comment from #M. Deinum, adding another adapter for the Management stuff (even though it already has one) seems to have fixed it. This is the class I ended up with:
#Order(0)
#Configuration
public class ManagementSecurityConfig extends WebSecurityConfigurerAdapter
{
#Autowired
ManagementServerProperties managementProperties;
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.requestMatchers()
.requestMatchers(new RequestMatcher()
{
#Override
public boolean matches(HttpServletRequest request)
{
return managementProperties.getContextPath().equals(request.getContextPath());
}
})
.and()
.authorizeRequests()
.anyRequest().hasRole("ADMIN")
.and()
.httpBasic();
}
}

Resources