Spring Boot azureAD filter autoconfiguration - spring-boot

I few days ago I was able to configure the integration with Azure AD and spring boot.
I'm usisng the following dependencies to achieve that:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-active-directory-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>msal4j</artifactId>
</dependency>
</dependencies>
It works so nice and I was able to get the expected result, but now the problem.
I have to Security configurations. Each one are configured with spring profiles, for example:
spring:
profiles:
active: DDBBSecurized, local
This one enables the sucurity with DDBB and it was configuired before the integration with AzureAD, It works perfect
I also have
spring:
profiles:
active: ADDSecurized, local
that enables the integration of azure AD.
Before configuring Azure AD integration if I use DDBBSecurized it works nice and I also had a option that if I dont configure anyThing. spring.profiles.active: local, for example, it disable the security:
the way to achive that is the following:
#EnableWebSecurity
#Profile( "DDBBSecurized" )
public class DDBBSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private RestAuthenticationExceptionHandler restAuthenticationExceptionHandler;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().sessionManagement().sessionCreationPolicy( SessionCreationPolicy.STATELESS );
http.headers().frameOptions().disable();
//Filtro de autenticacion de peticiones
http.addFilterAfter( new JWTAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class );
//Filtros CORS
http.addFilterBefore( new CorsFilter(), ChannelProcessingFilter.class );
//Manejador de excpeciones de login
http.exceptionHandling().authenticationEntryPoint( restAuthenticationExceptionHandler );
//Configuracion Endpoints
http.authorizeRequests().antMatchers( HttpMethod.POST, "/auth/login**" ).permitAll()
.antMatchers( "/v2/api-docs", "/configuration/**","/swagger*/**","/webjars/**" ).permitAll()
.antMatchers( "/actuator/**" ).permitAll()
.anyRequest().authenticated();
}
}
I have my own JWT filter and login endpoint and I also had:
#EnableWebSecurity
#Profile( "!DDBBSecurized & !AzureAdSecurized" )
public class NonSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private RestAuthenticationExceptionHandler restAuthenticationExceptionHandler;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().sessionManagement().sessionCreationPolicy( SessionCreationPolicy.STATELESS );
http.headers().frameOptions().disable();
//Filtros CORS
http.addFilterBefore( new CorsFilter(), ChannelProcessingFilter.class );
//Manejador de excpeciones de login
http.exceptionHandling().authenticationEntryPoint( restAuthenticationExceptionHandler );
//Configuracion Endpoints
http.authorizeRequests().anyRequest().permitAll();
}
}
That works Perfect.
Now If i use ADDSecurized everything works perfect.
#EnableWebSecurity
#Profile("AzureAdSecurized")
public class AzureSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private RestAuthenticationExceptionHandler restAuthenticationExceptionHandler;
#Autowired
private AADAppRoleStatelessAuthenticationFilter aadAuthenticationFilter;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().sessionManagement().sessionCreationPolicy( SessionCreationPolicy.STATELESS );
http.headers().frameOptions().disable();
//Filtro de autenticacion de peticiones
http.addFilterAfter( aadAuthenticationFilter, UsernamePasswordAuthenticationFilter.class );
http.addFilterAfter( new AzureTokenGetFilter(), UsernamePasswordAuthenticationFilter.class );
//Filtros CORS
http.addFilterBefore( new CorsFilter(), ChannelProcessingFilter.class );
//Manejador de excpeciones de login
http.exceptionHandling().authenticationEntryPoint( restAuthenticationExceptionHandler );
//Configuracion Endpoints
http.authorizeRequests().antMatchers( HttpMethod.POST, "/auth/login**" ).permitAll()
.antMatchers( "/v2/api-docs", "/configuration/**", "/swagger*/**", "/webjars/**" ).permitAll()
.antMatchers( "/actuator/**" ).permitAll().anyRequest().authenticated();
}
}
But if I change to DDBBSecurized profile it is still passing the aadAuthenticationFilter filter of azure. even if this configuration is disable. It seems its autoconfigure and WebSecurityAdpater by its Own or something like That.
the properties I also have are:
security:
oauth2:
client:
registration:
azure:
client-id: XXXX-XXXX-XXXX-XXXX-XXXXXXXX
azure:
activedirectory:
tenant-id: XXXX-XXXX-XXXX-XXXX-XXXXXXXX
client-id: XXXX-XXXX-XXXX-XXXX-XXXXXXXX
scope: /User.Read
session-stateless: true
authority-url: https://login.microsoftonline.com/
Now for example I have configured DDBBSecurized And I can see in the log that the filter is being applied:
STARTUPLOG:
2020-03-26 20:10:02,279 INFO class=org.springframework.boot.StartupInfoLogger Starting Application on gggarrido10 with PID 8760 (D:\Proyectos\EvoSago\SOM-Back\admin-user\target\classes started by gggarrido in D:\Proyectos\EvoSago\SOM-Back)
2020-03-26 20:10:11,378 INFO class=org.springframework.boot.SpringApplication The following profiles are active: DDBBSecurized,local
2020-03-26 20:10:31,479 INFO class=org.springframework.context.support.PostProcessorRegistrationDelegate$BeanPostProcessorChecker Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$2e0e67bf] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2020-03-26 20:10:33,267 INFO class=org.springframework.boot.web.embedded.tomcat.TomcatWebServer Tomcat initialized with port(s): 8080 (http)
2020-03-26 20:10:34,434 INFO class=org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext Root WebApplicationContext: initialization completed in 22895 ms
2020-03-26 20:10:39,649 INFO class=org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar Registered '/actuator/jolokia' to jolokia-actuator-endpoint
2020-03-26 20:10:42,925 INFO class=org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver Exposing 17 endpoint(s) beneath base path '/actuator'
2020-03-26 20:10:43,850 INFO class=org.springframework.security.web.DefaultSecurityFilterChain Creating filter chain: any request, [es.indra.som.common.utilities.CorsFilter#26f5e45d, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter#704c3bdf, org.springframework.security.web.context.SecurityContextPersistenceFilter#1e6d30c0, org.springframework.security.web.header.HeaderWriterFilter#5529522f, org.springframework.security.web.authentication.logout.LogoutFilter#4d2f9e3c, es.indra.som.security.filter.JWTAuthenticationFilter#37986daf, org.springframework.security.web.savedrequest.RequestCacheAwareFilter#69d667a5, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter#7ab1ad9, org.springframework.security.web.authentication.AnonymousAuthenticationFilter#c82d925, org.springframework.security.web.session.SessionManagementFilter#1b60d324, org.springframework.security.web.access.ExceptionTranslationFilter#43a59289, org.springframework.security.web.access.intercept.FilterSecurityInterceptor#61993d18]
2020-03-26 20:10:45,610 INFO class=org.springframework.scheduling.concurrent.ExecutorConfigurationSupport Initializing ExecutorService 'applicationTaskExecutor'
2020-03-26 20:10:48,503 INFO class=org.springframework.scheduling.concurrent.ExecutorConfigurationSupport Initializing ExecutorService
2020-03-26 20:10:51,398 INFO class=org.springframework.boot.web.embedded.tomcat.TomcatWebServer Tomcat started on port(s): 8080 (http) with context path ''
2020-03-26 20:10:51,407 INFO class=org.springframework.boot.StartupInfoLogger Started Application in 53.341 seconds (JVM running for 56.018)
ERROR LOG BECAUSE THE ADD FILTER IS BEING APPLIED WHEN IT SHOULD'T
2020-03-26 20:11:16,144 ERROR class=com.microsoft.azure.spring.autoconfigure.aad.AADAppRoleStatelessAuthenticationFilter Failed to initialize UserPrincipal.
com.nimbusds.jose.proc.BadJOSEException: Signed JWT rejected: Another algorithm expected, or no matching key(s) found
at com.nimbusds.jwt.proc.DefaultJWTProcessor.process(DefaultJWTProcessor.java:384)
at com.nimbusds.jwt.proc.DefaultJWTProcessor.process(DefaultJWTProcessor.java:330)
at com.nimbusds.jwt.proc.DefaultJWTProcessor.process(DefaultJWTProcessor.java:321)
at com.microsoft.azure.spring.autoconfigure.aad.UserPrincipalManager.buildUserPrincipal(UserPrincipalManager.java:83)
at com.microsoft.azure.spring.autoconfigure.aad.AADAppRoleStatelessAuthenticationFilter.doFilterInternal(AADAppRoleStatelessAuthenticationFilter.java:58)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.boot.actuate.web.trace.servlet.HttpTraceFilter.doFilterInternal(HttpTraceFilter.java:88)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter
The point is that before only with DDBBSecurized and NoSecurity ot works perfect. Why for ADDfilter even if I disable it by profile is appliying the filter?
I also tried to
#SpringBootApplication(exclude = {SecurityAutoConfiguration.class , SecurityFilterAutoConfiguration.class,
AADAuthenticationFilterAutoConfiguration.class})
I also tried to delete the full AzureSecurityConfiguration.... but it didnt work, event if I delete the full class it pass the filter
But it did not work and also the app doesnt start because it need AADAuthenticationFilterAutoConfiguration to autoconfigure the filters provided by the library with the properties set in applicacion.yaml avoid the user to manually configure them.
Thanks in advance.

Related

Spring Boot OAuth2 login endpoint not working. Getting 404 when hitting default path

I want to implement OAuth2 in my Spring Boot App.
I added
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
<version>2.3.7.RELEASE</version>
</dependency>
Basic config for GitHub (for example):
spring:
security:
oauth2:
client:
registration:
github:
client-id: xxx
client-secret: xxx
And basic WebSecurity config allowing all endpoints:
#Configuration
public class OAuth2SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf().disable()
.antMatcher("/**").authorizeRequests()
.antMatchers("/**").permitAll()
.and()
.oauth2Login();
}
}
When client-id/secret is not provided, an exception occurs so the config is picked up properly.
But I can't access the oauth login page which should be http://localhost:8080/oauth2/authorization/github, I have an 404 instead.

spring webflux - don't create session for specific paths

My spring webflux service exposes a health-check endpoint, which is called every few seconds. spring-security is configured, and currently each health-check call creates a new session, which fills the SessionStore quickly.
#Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
return http
.authorizeExchange()
.pathMatchers("/actuator/*").permitAll() // disable security for health-check
.anyExchange().authenticated()
...
.and().build();
}
logs:
2020-07-23 21:58:03.805 DEBUG 4722 --- [ctor-http-nio-3] o.s.w.s.adapter.HttpWebHandlerAdapter : [b185e815-1] HTTP GET "/actuator/health"
2020-07-23 21:58:03.845 DEBUG 4722 --- [ctor-http-nio-3] o.s.w.s.s.DefaultWebSessionManager : Created new WebSession.
Is it possible to configure spring-session or spring-security to not create sessions for specific paths?

Spring boot client fails to register Spring boot admin (version 2.x)

I am running spring boot application with basic authentication enabled and spring boot admin with UI security enabled .
My spring boot client fails to register to the spring boot admin server . Below are the logs :
2018-08-23 15:17:09.676 DEBUG 4992 --- [gistrationTask1] o.s.web.client.RestTemplate : Created POST request for "http://localhost:9001/instances"
2018-08-23 15:17:09.699 DEBUG 4992 --- [gistrationTask1] o.s.web.client.RestTemplate : Setting request Accept header to [application/json, application/*+json]
2018-08-23 15:17:09.724 DEBUG 4992 --- [gistrationTask1] o.s.web.client.RestTemplate : Writing [Application(name=spring-boot-application, managementUrl=http://localhost:8001/relay/actuator, healthUrl=http://localhost:8001/relay/actuator/health, serviceUrl=http://localhost:8001/relay)] as "application/json" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter#12c0c0b3]
2018-08-23 15:17:09.864 DEBUG 4992 --- [gistrationTask1] s.n.www.protocol.http.HttpURLConnection : sun.net.www.MessageHeader#5953ec3b8 pairs: {POST /instances HTTP/1.1: null}{Accept: application/json}{Content-Type: application/json}{Authorization: Basic YWRtaW46YWRtaW4=}{User-Agent: Java/1.8.0_161}{Host: localhost:9001}{Connection: keep-alive}{Content-Length: 287}
2018-08-23 15:17:10.124 DEBUG 4992 --- [gistrationTask1] s.n.www.protocol.http.HttpURLConnection : sun.net.www.MessageHeader#126c0bea10 pairs: {null: HTTP/1.1 403}{Cache-Control: no-cache, no-store, max-age=0, must-revalidate}{Pragma: no-cache}{Expires: 0}{X-Content-Type-Options: nosniff}{X-Frame-Options: DENY}{X-XSS-Protection: 1 ; mode=block}{Content-Type: text/plain}{Transfer-Encoding: chunked}{Date: Thu, 23 Aug 2018 09:47:10 GMT}
2018-08-23 15:17:10.128 DEBUG 4992 --- [gistrationTask1] o.s.web.client.RestTemplate : POST request for "http://localhost:9001/instances" resulted in 403 (null); invoking error handler
2018-08-23 15:17:10.138 WARN 4992 --- [gistrationTask1] d.c.b.a.c.r.ApplicationRegistrator : Failed to register application as Application(name=spring-boot-application, managementUrl=http://localhost:8001/relay/actuator, healthUrl=http://localhost:8001/relay/actuator/health, serviceUrl=http://localhost:8001/relay) at spring-boot-admin ([http://localhost:9001/instances]): 403 null. Further attempts are logged on DEBUG level
Below are my webSecurity config class from admin server
#SpringBootApplication
#EnableAdminServer
#EnableAutoConfiguration
#Configuration
public class SpringStarterAdminApplication {
public static void main(String[] args) {
SpringApplication.run(SpringStarterAdminApplication.class, args);
}
// Added for spring boot security login ui for admin
public static class SecuritySecureConfig extends WebSecurityConfigurerAdapter {
private final String adminContextPath;
public SecuritySecureConfig(AdminServerProperties adminServerProperties) {
this.adminContextPath = adminServerProperties.getContextPath();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setTargetUrlParameter("redirectTo");
successHandler.setDefaultTargetUrl(adminContextPath + "/");
http.authorizeRequests()
.antMatchers(adminContextPath + "/assets/**").permitAll()
.antMatchers(adminContextPath + "/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage(adminContextPath + "/login").successHandler(successHandler).and()
.logout().logoutUrl(adminContextPath + "/logout").and()
.httpBasic().and()
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.ignoringAntMatchers(
"/instances",
"/actuator/**"
);
// #formatter:on
}
}
Not sure what is preventing the client to register to admin Server .
The inner configuration class should be annotated with #Configuration too.
It's even better if you refactor it into a separate class.

Migration to Spring Boot 2 from 1.5.7 - Request method POST not supported - csrf already disabled

We've migrated our software from spring boot 1.5.7 to spring boot 2.
We're using JSF by including joinfaces-parent in our pom.xml.
At the startup, all works perfectly, but login call does not work:
Request method 'POST' not supported
It is probably a Spring Security issue? CSRF is already disabled.
Here's our SecurityConfig file:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
...
#Override
protected void configure(HttpSecurity http) {
try {
http.csrf().disable().authorizeRequests()
.antMatchers("/javax.faces.resource/**", Page.LOGIN.getUrlForSecurityContext())
.permitAll()
.and()
........
// *** login configuration
.formLogin()
.loginPage(Page.LOGIN.getUrlForSecurityContext()).permitAll()
.failureUrl(Page.LOGIN.getUrlForSecurityContext() + "?error=true")
.usernameParameter("username")
.passwordParameter("password")
.successHandler(authenticationSuccessHandler)
.and()
...........
// #formatter:on
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
.......
}
The login request does not arrives to our backend.
I found out that this error is generated from the dispatcher.forward function, called from xhtml. Here the function:
public void login() throws ServletException, IOException {
final ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
final RequestDispatcher dispatcher = ((ServletRequest) context.getRequest()).getRequestDispatcher("/login");
dispatcher.forward((ServletRequest) context.getRequest(), (ServletResponse) context.getResponse());
FacesContext.getCurrentInstance().responseComplete();
}
Here more logs when the error message happens:
[io.undertow.servlet] (default task-3) Initializing Spring FrameworkServlet 'dispatcherServlet'
16:02:20,926 INFO [org.springframework.web.servlet.DispatcherServlet] (default task-3) FrameworkServlet 'dispatcherServlet': initialization started
16:02:20,938 INFO [org.springframework.web.servlet.DispatcherServlet] (default task-3) FrameworkServlet 'dispatcherServlet': initialization completed in 12 ms
16:02:20,949 WARN [org.springframework.web.servlet.PageNotFound] (default task-3) Request method 'POST' not supported
16:02:20,973 ERROR [org.springframework.boot.web.servlet.support.ErrorPageFilter] (default task-3) Cannot forward to error page for request [/login] as the response has already been committed. As a result, the response may have the wrong status code. If your application is running on WebSphere Application Server you may be able to resolve this problem by setting com.ibm.ws.webcontainer.invokeFlushAfterService to false
Thanks in advice!
Spring Security configuration looks ok for me. There is something wrong with your login controller. I suppose your login method is called in response to POST request from the client. Then it tries to forward this POST to render login page and finally throws an exception. Obviously it should be GET request instead of POST.

Spring Boot with WSO2 OAuth2 - logoutSuccessUrl is not working

We are implementing the service using Spring Boot (1.2.2) with WSO2 IS (5.x) as OAuth2 Identity provider.
As part of logout we wanted to run some cleaning activities and then redirect to login page. Following is the Spring Security Configuration class
#Configuration
#EnableWebMvcSecurity
public class SecurityConfiguration extends OAuth2SsoConfigurerAdapter {
private final Logger log = LoggerFactory.getLogger(this.getClass());
#Autowired
private OAuth2ClientContext oAuth2ClientContext;
#Autowired
private MmaLogoutHandler logoutHandler;
#Override
public void match(RequestMatchers matchers) {
matchers.anyRequest();
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logoff", "GET"))
.logoutSuccessUrl("/#/home")
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID","remember-me")
.permitAll()
.and()
.addFilterAfter(csrfHeaderFilter(), CsrfFilter.class)
.addFilterBefore(customerAuthorizationFilter(), AbstractPreAuthenticatedProcessingFilter.class);
}
When the logout is called, the log shows that spring security has cleared the session, but it fails to redirect -
2015-09-01 14:23:05.983 DEBUG 12936 --- [nio-8443-exec-8] o.s.s.w.a.logout.LogoutFilter : Logging out user 'org.springframework.security.oauth2.provider.OAuth2Authentication#e6269aa6: Principal: mrpink_bd3d5b71-b212-11e4-ac24-22000b4791d2; Credentials: [PROTECTED]; Authenticated: true; Details: remoteAddress=127.0.0.1, sessionId=<SESSION>, tokenType=bearertokenValue=<TOKEN>; Granted Authorities: ROLE_USER' and transferring to logout destination
2015-09-01 14:23:05.984 DEBUG 12936 --- [nio-8443-exec-8] o.s.s.w.a.l.SecurityContextLogoutHandler : Invalidating session: B7B50DC106F50EDA84ACFEF229DE167B
2015-09-01 14:23:05.984 DEBUG 12936 --- [nio-8443-exec-8] .s.s.w.a.l.SimpleUrlLogoutSuccessHandler : Using default Url: /#/home
2015-09-01 14:23:05.984 DEBUG 12936 --- [nio-8443-exec-8] .s.s.w.a.l.SimpleUrlLogoutSuccessHandler : Response has already been committed. Unable to redirect to /#/home
2015-09-01 14:23:05.984 DEBUG 12936 --- [nio-8443-exec-8] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
As per log the redirection fails and the page is not actually redirected.
Is this due to OAuth2 or there is already default log out handler with Spring boot that is needed to be overridden?

Resources