Authentication with Spring-Boot-Admin and Eureka discovery - spring-boot

SBA version 2.0.1
Spring-Cloud Finchley.RELEASE
I have some services registered in Eureka. The services are Spring-Boot apps, and have their actuators secured by HTTP basic auth. The service actuators are at /actuator. The services are working and I can interact with their actuators via Postman and curl. SBA connects to Eureka and discovers the services, but they are always in a down (red) state, except for the SBA application itself, which is shown just fine as green in the SBA console, and I am able to click on it and see it's properties.
When I click on one of the service instances, I am prompted for credentials. I'm not sure what credentials to use, so I use the credentials for the service actuator. I already have these credentials in the metadata-map as shown in the docs, but I am still prompted for credentials anyway. This always results in showing the Whitelabel Error Page, with an error message like this:
Mon Jun 25 12:40:57 CDT 2018 There was an unexpected error
(type=Method Not Allowed, status=405). Request method 'POST' not
supported
Though I note the url for that error is apparently on the SBA instance intself, not the remote service. The url decodes to this: http://localhost:8080/#/instances/9207aa5fc06b/
But I see this in the log for the service, so apparently an unauthenticated request is making it to the remove service:
[2018-06-25 12:16:54.242] - DEBUG - [http-nio-8380-exec-7]
[AUTHENTICATION_SERVICE_DEV,8dc8165d4f77be7c,8dc8165d4f77be7c,false]
--- [nio-8380-exec-7] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Written [{timestamp=Mon Jun 25 12:16:54 CDT 2018, status=401,
error=Unauthorized, message=Unauthorized, path=/actuator/health}] as
"application/vnd.spring-boot.actuator.v2+json" using
[org.springframework.http.converter.json.MappingJackson2HttpMessageConverter#30c8681]
And this in the SBA log:
2018-06-25 12:39:40.884 ERROR [SERVICES_ADMIN_CONSOLE_LOCAL,,,] 20728
--- [nio-8080-exec-8] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path
[] threw exception
java.io.IOException: An established connection was aborted by the
software in your host machine
This is the root of my confusion, I'm not sure what credentials I need or even what I am authenticating to. I have provided the credentials to remote service in properties as well as in the login form, and it doesn't work.
When I click on the SBA application in the SBA console, it works as expected. So this seems to be related to authenticating to a remote actuator, but I can't figure out what the problem is.
Server:
#Configuration
#EnableAutoConfiguration
#EnableEurekaClient
#EnableAdminServer
public class ServiceAdmin {
public static void main(String[] args) {
SpringApplication.run(ServiceAdmin.class, args);
}
#Configuration
public static class SecurityPermitAllConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().permitAll()
.and().csrf().disable();
}
}
}
SBA Config:
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
management.info.git.mode=full
management.endpoint.shutdown.enabled=true
spring.security.user.name=actuator
spring.security.user.password=password
spring.security.user.roles=ACTUATOR
eureka.instance.leaseRenewalIntervalInSeconds=10
eureka.instance.health-check-url-path=/actuator/health
eureka.instance.metadata-map.user.name=actuator
eureka.instance.metadata-map.user.password=password
eureka.client.registryFetchIntervalSeconds=5
eureka.client.serviceUrl.defaultZone=http://svcregistry1.mycompany.com/eureka/,http://svcregistry2.mycompany.com

For anyone coming to this question, being as puzzled as I, to clear up this answer.
I'm having Eureka and Springboot admin server/ui in the same application
All the services that will register into eureka AND springboot admin, will need their own /actuator credentials present as metadata :
eureka.instance.metadata-map.user.name = ${endpoints.user.name}
eureka.instance.metadata-map.user.password = ${endpoints.user.password}
This post cleared up a few things.
https://zoltanaltfatter.com/2018/05/15/spring-cloud-discovery-with-spring-boot-admin/

The problem here was I failed to understand the docs. The eureka credentials in the metadataMap have to be provided by the monitored application at registration time. Not provided in the SBA config.

Related

Newly added SecurityFilterChain not included in filter chain

Spring Security: 5.6.2
Wildfly 24 Application Server with container managed authentication setup
So far we were using WebSecurityConfigurerAdapter for security configuration to apply our own set of rule for authorization with Spring Security, but now WebSecurityConfigurerAdapter is going to be deprecated from 5.7 (this blog post) we are moving to SecurityFilterChain mechanism.
This is the code snippet for SecurityFilterChain setup.
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
String role = "ADMINUSER";
http.jee().mappableAuthorities(role);
http.csrf().disable()
http.authorizeRequests()
.antMatchers("/assets/**").permitAll()
.antMatchers("/login/**").permitAll()
.antMatchers("/j_security_check").permitAll()
// OWASP Pen Test: X-Frame-Options header
http.headers().frameOptions().deny();
// Remainder of app must have ADMINUSER role
http.authorizeRequests().antMatchers("/**").hasRole(role)
return http.build();
}
On enabling TRACE log level for Spring security, found that this filter is recognized and printed permission rules on log, see below:
o.s.s.w.a.e.ExpressionBasedFilterInvocationSecurityMetadataSource [ExpressionBasedFilterInvocationSecurityMetadataSource.java:72] Adding web access control expression [permitAll] for Ant [pattern='/assets/**']
o.s.s.w.a.e.ExpressionBasedFilterInvocationSecurityMetadataSource [ExpressionBasedFilterInvocationSecurityMetadataSource.java:72] Adding web access control expression [permitAll] for Ant [pattern='/login/**']
o.s.s.w.a.e.ExpressionBasedFilterInvocationSecurityMetadataSource [ExpressionBasedFilterInvocationSecurityMetadataSource.java:72] Adding web access control expression [permitAll] for Ant [pattern='/j_security_check']
o.s.s.w.a.e.ExpressionBasedFilterInvocationSecurityMetadataSource [ExpressionBasedFilterInvocationSecurityMetadataSource.java:72] Adding web access control expression [hasRole('ROLE_ADMINUSER')] for Ant [pattern='/**']
But eventually it has put these request patterns to secured resources list, from the log:
o.s.s.w.FilterChainProxy [FilterChainProxy.java:208] Securing GET /assets/login/Prod-Logo-55b1334f6df931972f65a053d027da82.png
o.s.s.w.FilterChainProxy [FilterChainProxy.java:208] Securing GET /assets/login/login-4af79e08f88a8922f7b81b96f782eb39.css
It does not include these unsecured resources to login page and so the login page looks unpleasant because static resources are not available. And moreover, on providing correct user credentials, it redirects to Spring's default login page, instead of welcome page specified in web.xml.
Two questions:
Why does it redirect to Spring Security's default login page on providing correct user credentials
As the permissions for static resources are confirmed and verified in the log, then why do they put in secured resources list?
Please help by pointing out where I am missing on setup.

Spring Boot Security and Keycloak - receive 403 forbidden /sso/login after successfull login when using HTTPS

I have a Spring Boot App using Spring Security and Keycloak as IDP.
Keycloak is available under https://auth.example.com, having a realm backo with a client backo-core and a testuser configured with the required roles.
If I configure my local app, using
keycloak.enabled=true
keycloak.auth-server-url=https://auth.example.com/auth
keycloak.realm=backo
keycloak.public-client=true
keycloak.resource=backo-core
keycloak.ssl-required=external
keycloak.confidential-port=443
Everything works fine.
If I deploy it to my DEV environment under https://backo.example.com/backo with https://backo.example.com/sso/login, when accessing the app I get redirect to the Keycloak login. After successful login I get redirected to the redirect URL with the state, session-state and code parameters but receive 403.
https://backo.example.com/sso/login?state=...&session_state=...&code=...
with request initiator chain coming from https://auth.example.com/auth/realms/backo/login-action/authenticate?...
If I set locally keycloak.ssl-required=all, the redirect_url parameter when accessing the login page is https://localhost/sso/login, so I can change it manually to http://localhost:8080/sso/login. After a successful login I have the exact same problem with a 403 Forbidden response for
http://localhost:8080/sso/login?state=...&session_state=...&code=...
with request initiator chain coming from https://auth.example.com/auth/realms/backo/login-action/authenticate?...
This is how my security config looks like
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
.authorizeRequests()
.antMatchers("/backo").hasAnyRole(ROLE_ADMIN, ROLE_BACKOFFICE)
.anyRequest().permitAll();
http.csrf().disable();
http.headers().frameOptions().disable(); // otherwise Vaadin doesn't work properly
http
.logout()
.addLogoutHandler(keycloakLogoutHandler())
.logoutUrl("/sso/logout").permitAll()
.logoutSuccessUrl("/");
}
You can ignore this Vaadin workaround, as it fails in /sso/login already.
http.csrf().disable(); is required to prevent other 403 Forbidden errors on post request while authorization.
One thing that could be worth mentioning:
The Spring Boot App has no HTTPS enabled, in our dev environment it sits behind an AWS Application loadbalancer ALB. HTTPS is terminated in the ALB.
We have faced the similar problem three days ago with spring boot thymeleaf application. We have used keycloak adapter (13.0.1) for spring boot.
After successful login it was redirecting to /sso/login page with 403 error.
After lots of effort we finally got the configuration required to fix this issue. you need to use the below application properties :
server.use-forward-headers=true
keycloak.public-client=true
keycloak.ssl-required=all
keycloak.confidential-port=443

Jhipster Health Endpoint fails when mailserver not connected

JHipster / Spring boot provides a nice endpoint /management/health, where it aggregates health information for subsystems like db, disk, and mail.
Unfortunately, when the connection to the mail server fails, the whole endpoint fails. So you do not get information what has failed.
I get a strack trace like this:
o.s.b.a.health.MailHealthIndicator : Health check failed
com.sun.mail.util.MailConnectException: Couldn't connect to host, port: XXXX, NNNN25025; timeout -1
...
at org.springframework.boot.actuate.health.MailHealthIndicator.doHealthCheck(MailHealthIndicator.java:40)
at org.springframework.boot.actuate.health.AbstractHealthIndicator.health(AbstractHealthIndicator.java:43)
at org.springframework.boot.actuate.health.CompositeHealthIndicator.health(CompositeHealthIndicator.java:68)
at org.springframework.boot.actuate.endpoint.HealthEndpoint.invoke(HealthEndpoint.java:85)
at org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.getCurrentHealth(HealthMvcEndpoint.java:177)
at org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.getHealth(HealthMvcEndpoint.java:166)
at org.springframework.boot.actuate.endpoint.mvc.HealthMvcEndpoint.invoke(HealthMvcEndpoint.java:143)
This is spring boot 1.5.9
Where should I fix this, so that the exception is catched and instead a an error status is returned?
You have to turn on your SMTP server or disable checks to it.
To disable checks to SMTP server:
management.health.mail.enabled=false
To disable checks to all server:
management.health.defaults.enabled=false
for more information, see http://www.briansjavablog.com/2017/09/health-checks-metric-s-more-with-spring.html
I believe you can handle this error with the ExceptionHandler for 1.5.9 version of Spring Boot since the newer version there is no such problem:
#ControllerAdvice
public class ExceptionController {
#ExceptionHandler(MailConnectException.class)
public ResponseEntity<?> mailExceptionHandler(MailConnectException e) {
// Do your treatment ...
} ...
}

Connect secured Client with Spring Boot Admin Security

Can someone guide me how can I connect my secured client with the spring boot admin application?
Scenario: I have a spring boot application (client) with spring security and spring-actuator enabled. The actuator endpoints are secured and for this I have the following (working) configuration in my web security config:
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth, UserDetailsService userDetailsService) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
auth.inMemoryAuthentication().withUser("Test-Actuator").password("Test-Baby").roles("ADMIN", "ACTUATOR");
}
Now I want to integrate the Spring Boot Admin Application in our environment. I set up a simple application with spring-boot-admin-server and spring-boot-admin-server-ui enabled. In the application.properties file I provide the following properties:
spring.boot.admin.username=test
spring.boot.admin.password=test
these are for the server admin, right?
spring.boot.admin.client.metadata.user.name=Test-Actuator
spring.boot.admin.client.metadata.user.password=Test-Baby
these are for the client, right?
Now when I run the applications I get the following error from the client: Failed to register application as Application [...] at spring-boot-admin ([...]) 401 null
I call the spring boot admin page and get a HttpBasic Authentication Pop Up. No credentials from above work for this Pop Up.
Note: If I disable the security in the client application.properties file it works but (like expected) the client doesn't work anymore.

Spring Security Oauth2 SSO with Zuul Proxy

I'm modifying the oauth2-vanilla sample from Springs excellent security tutorials. The oauth2-vanilla combines the Zuul Proxy and the UI into a single application. I would like to seperate the Zuul Proxy and the UI. (The Zuul Proxy should act as an API gateway and as a reverse proxy for several UIs).
When accessing the UI via the zuul proxy, it should be able to do SSO based on Oauth2 between the UI and the resource backend.
The oauth2-vanilla looks like this
Where I want to move to something like this :
I've removed the UI part from the gateway, and added a zuul route for the ui
zuul:
routes:
resource:
url: http://localhost:9000
user:
url: http://localhost:9999/uaa/user
ui:
url: http://localhost:8080
I created a new UI webapp containing the UI (Angular stuff) with an #EnableOAuth2Sso annotation.
So I'm accessing the UI via http://localhost:8888 (through the zuul proxy).
After authenticating and doing through the UI flow, I can access the /user endpoint that returns me the user. (During debugging, I see that when I access the /user endpoint that I have an HTTP Session with an OAuth2Authentication.
When I access the /resource endpoint however, the HttpSessionSecurityContextRepository cannot find a session and is unable to build a context with the OAuth2Authentication.
I've created a git repository with the modified sample.
I'm guessing there is something wrong with the gateway configuration.
I've tried changing cookie paths, changing HttpSecurity rules in the proxy but I cannot get it to work.
What I don't understand is why the UI, when accessed through the proxy is able to resolve the /user endpoint fine (with an HTTP session and a OAuth2Authentication), but it is unable to access the /resource endpoint.
Also, as the UI is now running in the /ui context, it seems that I need to have the following code in the gateway for it to load up the angular css / js files.
.antMatchers("/ui/index.html", "/ui/home.html", "ui/css/**", "/ui/js/**").permitAll().anyRequest().authenticated();
It also doesn't seem right that I need to prefix it with the zuul ui route.
Any help would be appreciated.
I was never able to get the #EnableOauthSso to work. Instead, I annotated as an #EnableResourceServer and created a security config for Zuul.
#Configuration
#EnableResourceServer
public class JwtSecurityConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/oauth/**").permitAll()
.antMatchers("/**").hasAuthority("ROLE_API")
.and()
.csrf().disable();
}
}

Resources