Skip to content

Commit 06c80c4

Browse files
committed
Enable CSRF-Protection possible and update samples
closes codecentric#805
1 parent 2de9393 commit 06c80c4

File tree

9 files changed

+101
-24
lines changed

9 files changed

+101
-24
lines changed

spring-boot-admin-docs/src/main/asciidoc/security.adoc

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ A Spring Security configuration could look like this:
1111
----
1212
include::{samples-dir}/spring-boot-admin-sample-servlet/src/main/java/de/codecentric/boot/admin/SpringBootAdminApplication.java[tags=configuration-spring-security]
1313
----
14+
<1> Grants public access to all static assets and the login page.
15+
<2> Every other request must be authenticated.
16+
<3> Configures login and logout.
17+
<4> Enables HTTP-Basic support. This is needed for the Spring Boot Admin Client to register.
18+
<5> Enables CSRF-Protection using Cookies
19+
<6> Disables CRSF-Protection the endpoint the Spring Boot Admin Client uses to register.
20+
<7> Disables CRSF-Protection for the actuator endpoints.
1421

1522
For a complete sample look at https://github.com/codecentric/spring-boot-admin/tree/master/spring-boot-admin-samples/spring-boot-admin-sample-servlet/[spring-boot-admin-sample-servlet.
1623

@@ -50,3 +57,16 @@ WARNING: You should configure HTTPS for your SBA Server or (service registry) wh
5057
WARNING: When using Spring Cloud Discovery, you must be aware that anybody who can query your service registry can obtain the credentials.
5158

5259
TIP: When using this approach the SBA Server decides whether or not the user can access the registered applications. There are more complex solutions possible (using OAuth2) to let the clients decide if the user can access the endpoints. For that please have a look at the samples in https://github.com/joshiste/spring-boot-admin-samples[joshiste/spring-boot-admin-samples^].
60+
61+
==== CSRF on Actuator Endpoints ====
62+
63+
Some of the actuator endpoints (e.g. `/loggers`) support POST requests. When using Spring Security you need to ignore the actuator endpoints for CSRF-Protection as the Spring Boot Admin Server currently lacks support.
64+
65+
[source,java]
66+
----
67+
@Override
68+
protected void configure(HttpSecurity http) throws Exception {
69+
http.csrf()
70+
.ignoringAntMatchers("/actuator/**");
71+
}
72+
----

spring-boot-admin-samples/spring-boot-admin-sample-consul/src/main/java/de/codecentric/boot/admin/SpringBootAdminApplication.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
2828
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
2929
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
30+
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
3031

3132
@Configuration
3233
@EnableAutoConfiguration
@@ -39,8 +40,13 @@ public class SpringBootAdminApplication {
3940
public static class SecurityPermitAllConfig extends WebSecurityConfigurerAdapter {
4041
@Override
4142
protected void configure(HttpSecurity http) throws Exception {
42-
http.authorizeRequests().anyRequest().permitAll()//
43-
.and().csrf().disable();
43+
http.authorizeRequests()
44+
.anyRequest()
45+
.permitAll()
46+
.and()
47+
.csrf()
48+
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
49+
.ignoringAntMatchers("/instances", "/actuator/**");
4450
}
4551
}
4652

@@ -67,7 +73,9 @@ protected void configure(HttpSecurity http) throws Exception {
6773
.formLogin().loginPage(adminContextPath + "/login").successHandler(successHandler).and()
6874
.logout().logoutUrl(adminContextPath + "/logout").and()
6975
.httpBasic().and()
70-
.csrf().disable();
76+
.csrf()
77+
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
78+
.ignoringAntMatchers("/instances", "/actuator/**");
7179
// @formatter:on
7280
}
7381
}

spring-boot-admin-samples/spring-boot-admin-sample-eureka/src/main/java/de/codecentric/boot/admin/SpringBootAdminApplication.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
2828
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
2929
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
30+
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
3031

3132
@Configuration
3233
@EnableAutoConfiguration
@@ -42,8 +43,13 @@ public static void main(String[] args) {
4243
public static class SecurityPermitAllConfig extends WebSecurityConfigurerAdapter {
4344
@Override
4445
protected void configure(HttpSecurity http) throws Exception {
45-
http.authorizeRequests().anyRequest().permitAll()//
46-
.and().csrf().disable();
46+
http.authorizeRequests()
47+
.anyRequest()
48+
.permitAll()
49+
.and()
50+
.csrf()
51+
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
52+
.ignoringAntMatchers("/instances", "/actuator/**");
4753
}
4854
}
4955

@@ -70,7 +76,9 @@ protected void configure(HttpSecurity http) throws Exception {
7076
.formLogin().loginPage(adminContextPath + "/login").successHandler(successHandler).and()
7177
.logout().logoutUrl(adminContextPath + "/logout").and()
7278
.httpBasic().and()
73-
.csrf().disable();
79+
.csrf()
80+
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
81+
.ignoringAntMatchers("/instances", "/actuator/**");
7482
// @formatter:on
7583
}
7684
}

spring-boot-admin-samples/spring-boot-admin-sample-hazelcast/src/main/java/de/codecentric/boot/admin/SpringBootAdminApplication.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
2828
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
2929
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
30+
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
3031
import com.hazelcast.config.Config;
3132
import com.hazelcast.config.EvictionPolicy;
3233
import com.hazelcast.config.InMemoryFormat;
@@ -50,8 +51,13 @@ public Config hazelcastConfig() {
5051
public static class SecurityPermitAllConfig extends WebSecurityConfigurerAdapter {
5152
@Override
5253
protected void configure(HttpSecurity http) throws Exception {
53-
http.authorizeRequests().anyRequest().permitAll()//
54-
.and().csrf().disable();
54+
http.authorizeRequests()
55+
.anyRequest()
56+
.permitAll()
57+
.and()
58+
.csrf()
59+
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
60+
.ignoringAntMatchers("/instances", "/actuator/**");
5561
}
5662
}
5763

@@ -78,7 +84,9 @@ protected void configure(HttpSecurity http) throws Exception {
7884
.formLogin().loginPage(adminContextPath + "/login").successHandler(successHandler).and()
7985
.logout().logoutUrl(adminContextPath + "/logout").and()
8086
.httpBasic().and()
81-
.csrf().disable();
87+
.csrf()
88+
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
89+
.ignoringAntMatchers("/instances", "/actuator/**");
8290
// @formatter:on
8391
}
8492
}

spring-boot-admin-samples/spring-boot-admin-sample-servlet/src/main/java/de/codecentric/boot/admin/SpringBootAdminApplication.java

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
4343
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
4444
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
45+
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
4546

4647
@Configuration
4748
@EnableAutoConfiguration
@@ -59,8 +60,13 @@ public static void main(String[] args) {
5960
public static class SecurityPermitAllConfig extends WebSecurityConfigurerAdapter {
6061
@Override
6162
protected void configure(HttpSecurity http) throws Exception {
62-
http.authorizeRequests().anyRequest().permitAll()//
63-
.and().csrf().disable();
63+
http.authorizeRequests()
64+
.anyRequest()
65+
.permitAll()
66+
.and()
67+
.csrf()
68+
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
69+
.ignoringAntMatchers("/instances", "/actuator/**");
6470
}
6571
}
6672

@@ -81,14 +87,19 @@ protected void configure(HttpSecurity http) throws Exception {
8187
successHandler.setTargetUrlParameter("redirectTo");
8288

8389
http.authorizeRequests()
84-
.antMatchers(adminContextPath + "/assets/**").permitAll()
90+
.antMatchers(adminContextPath + "/assets/**").permitAll() // <1>
8591
.antMatchers(adminContextPath + "/login").permitAll()
86-
.anyRequest().authenticated()
92+
.anyRequest().authenticated() // <2>
8793
.and()
88-
.formLogin().loginPage(adminContextPath + "/login").successHandler(successHandler).and()
94+
.formLogin().loginPage(adminContextPath + "/login").successHandler(successHandler).and() // <3>
8995
.logout().logoutUrl(adminContextPath + "/logout").and()
90-
.httpBasic().and()
91-
.csrf().disable();
96+
.httpBasic().and() // <4>
97+
.csrf()
98+
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) // <5>
99+
.ignoringAntMatchers(
100+
"/instances", // <6>
101+
"/actuator/**" // <7>
102+
);
92103
// @formatter:on
93104
}
94105
}

spring-boot-admin-samples/spring-boot-admin-sample-war/src/main/java/de/codecentric/boot/admin/SpringBootAdminApplication.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
2929
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
3030
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
31+
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
3132

3233
@Configuration
3334
@EnableAutoConfiguration
@@ -44,8 +45,13 @@ protected SpringApplicationBuilder configure(SpringApplicationBuilder applicatio
4445
public static class SecurityPermitAllConfig extends WebSecurityConfigurerAdapter {
4546
@Override
4647
protected void configure(HttpSecurity http) throws Exception {
47-
http.authorizeRequests().anyRequest().permitAll()//
48-
.and().csrf().disable();
48+
http.authorizeRequests()
49+
.anyRequest()
50+
.permitAll()
51+
.and()
52+
.csrf()
53+
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
54+
.ignoringAntMatchers("/instances", "/actuator/**");
4955
}
5056
}
5157

@@ -72,7 +78,9 @@ protected void configure(HttpSecurity http) throws Exception {
7278
.formLogin().loginPage(adminContextPath + "/login").successHandler(successHandler).and()
7379
.logout().logoutUrl(adminContextPath + "/logout").and()
7480
.httpBasic().and()
75-
.csrf().disable();
81+
.csrf()
82+
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
83+
.ignoringAntMatchers("/instances", "/actuator/**");
7684
// @formatter:on
7785
}
7886
}

spring-boot-admin-samples/spring-boot-admin-sample-zookeeper/src/main/java/de/codecentric/boot/admin/SpringBootAdminApplication.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
2828
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
2929
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
30+
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
3031

3132
@Configuration
3233
@EnableAutoConfiguration
@@ -38,8 +39,13 @@ public class SpringBootAdminApplication {
3839
public static class SecurityPermitAllConfig extends WebSecurityConfigurerAdapter {
3940
@Override
4041
protected void configure(HttpSecurity http) throws Exception {
41-
http.authorizeRequests().anyRequest().permitAll()//
42-
.and().csrf().disable();
42+
http.authorizeRequests()
43+
.anyRequest()
44+
.permitAll()
45+
.and()
46+
.csrf()
47+
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
48+
.ignoringAntMatchers("/instances", "/actuator/**");
4349
}
4450
}
4551

@@ -66,7 +72,9 @@ protected void configure(HttpSecurity http) throws Exception {
6672
.formLogin().loginPage(adminContextPath + "/login").successHandler(successHandler).and()
6773
.logout().logoutUrl(adminContextPath + "/logout").and()
6874
.httpBasic().and()
69-
.csrf().disable();
75+
.csrf()
76+
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
77+
.ignoringAntMatchers("/instances", "/actuator/**");
7078
// @formatter:on
7179
}
7280
}

spring-boot-admin-server-ui/src/main/frontend/login.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@
3838
</figure>
3939
<h1 class="title has-text-primary">Spring Boot Admin</h1>
4040
<form method="post">
41+
<input type="hidden"
42+
th:if="${_csrf}"
43+
th:name="${_csrf.parameterName}"
44+
th:value="${_csrf.token}"/>
4145
<div class="field">
4246
<p class="is-medium has-text-danger" th:unless="${param.error == null}">
4347
Invalid username or password

spring-boot-admin-server-ui/src/main/frontend/services/instance.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ import {Observable} from '@/utils/rxjs'
2121
import uri from '@/utils/uri';
2222
import _ from 'lodash';
2323

24-
const actuatorMimeTypes = ['application/vnd.spring-boot.actuator.v2+json',
24+
const actuatorMimeTypes = [
25+
'application/vnd.spring-boot.actuator.v2+json',
2526
'application/vnd.spring-boot.actuator.v1+json',
26-
'application/json'];
27+
'application/json'
28+
];
2729

2830
class Instance {
2931
constructor(id) {

0 commit comments

Comments
 (0)