17
17
package org .springframework .boot .actuate .autoconfigure .health ;
18
18
19
19
import java .security .Principal ;
20
- import java .util .Map ;
21
20
22
21
import org .junit .Test ;
23
22
import reactor .core .publisher .Mono ;
24
23
24
+ import org .springframework .boot .actuate .endpoint .SecurityContext ;
25
25
import org .springframework .boot .actuate .health .Health ;
26
26
import org .springframework .boot .actuate .health .HealthEndpoint ;
27
27
import org .springframework .boot .actuate .health .HealthIndicator ;
28
- import org .springframework .boot .actuate .health .HealthStatusHttpMapper ;
28
+ import org .springframework .boot .actuate .health .HealthWebEndpointResponseMapper ;
29
29
import org .springframework .boot .actuate .health .ReactiveHealthEndpointWebExtension ;
30
30
import org .springframework .boot .actuate .health .ReactiveHealthIndicator ;
31
31
import org .springframework .boot .test .context .runner .ReactiveWebApplicationContextRunner ;
34
34
import org .springframework .test .util .ReflectionTestUtils ;
35
35
36
36
import static org .assertj .core .api .Assertions .assertThat ;
37
+ import static org .mockito .BDDMockito .given ;
37
38
import static org .mockito .Mockito .mock ;
38
39
39
40
/**
@@ -69,12 +70,17 @@ public void runWithCustomHealthMappingShouldMapStatusCode() {
69
70
.run ((context ) -> {
70
71
Object extension = context
71
72
.getBean (ReactiveHealthEndpointWebExtension .class );
72
- HealthStatusHttpMapper mapper = (HealthStatusHttpMapper ) ReflectionTestUtils
73
- .getField (extension , "statusHttpMapper" );
74
- Map <String , Integer > statusMappings = mapper .getStatusMapping ();
75
- assertThat (statusMappings ).containsEntry ("DOWN" , 503 );
76
- assertThat (statusMappings ).containsEntry ("OUT_OF_SERVICE" , 503 );
77
- assertThat (statusMappings ).containsEntry ("CUSTOM" , 500 );
73
+ HealthWebEndpointResponseMapper responseMapper = (HealthWebEndpointResponseMapper ) ReflectionTestUtils
74
+ .getField (extension , "responseMapper" );
75
+ Class <SecurityContext > securityContext = SecurityContext .class ;
76
+ assertThat (responseMapper
77
+ .map (Health .down ().build (), mock (securityContext ))
78
+ .getStatus ()).isEqualTo (503 );
79
+ assertThat (responseMapper .map (Health .status ("OUT_OF_SERVICE" ).build (),
80
+ mock (securityContext )).getStatus ()).isEqualTo (503 );
81
+ assertThat (responseMapper
82
+ .map (Health .status ("CUSTOM" ).build (), mock (securityContext ))
83
+ .getStatus ()).isEqualTo (500 );
78
84
});
79
85
}
80
86
@@ -86,8 +92,11 @@ public void regularAndReactiveHealthIndicatorsMatch() {
86
92
ReactiveHealthEndpointWebExtension extension = context
87
93
.getBean (ReactiveHealthEndpointWebExtension .class );
88
94
Health endpointHealth = endpoint .health ();
89
- Health extensionHealth = extension .health (mock (Principal .class ))
90
- .block ().getBody ();
95
+ SecurityContext securityContext = mock (SecurityContext .class );
96
+ given (securityContext .getPrincipal ())
97
+ .willReturn (mock (Principal .class ));
98
+ Health extensionHealth = extension .health (securityContext ).block ()
99
+ .getBody ();
91
100
assertThat (endpointHealth .getDetails ())
92
101
.containsOnlyKeys ("application" , "first" , "second" );
93
102
assertThat (extensionHealth .getDetails ())
@@ -100,7 +109,8 @@ public void unauthenticatedUsersAreNotShownDetailsByDefault() {
100
109
this .contextRunner .run ((context ) -> {
101
110
ReactiveHealthEndpointWebExtension extension = context
102
111
.getBean (ReactiveHealthEndpointWebExtension .class );
103
- assertThat (extension .health (null ).block ().getBody ().getDetails ()).isEmpty ();
112
+ assertThat (extension .health (mock (SecurityContext .class )).block ().getBody ()
113
+ .getDetails ()).isEmpty ();
104
114
});
105
115
}
106
116
@@ -109,8 +119,10 @@ public void authenticatedUsersAreShownDetailsByDefault() {
109
119
this .contextRunner .run ((context ) -> {
110
120
ReactiveHealthEndpointWebExtension extension = context
111
121
.getBean (ReactiveHealthEndpointWebExtension .class );
112
- assertThat (extension .health (mock (Principal .class )).block ().getBody ()
113
- .getDetails ()).isNotEmpty ();
122
+ SecurityContext securityContext = mock (SecurityContext .class );
123
+ given (securityContext .getPrincipal ()).willReturn (mock (Principal .class ));
124
+ assertThat (extension .health (securityContext ).block ().getBody ().getDetails ())
125
+ .isNotEmpty ();
114
126
});
115
127
}
116
128
@@ -133,11 +145,60 @@ public void detailsCanBeHiddenFromAuthenticatedUsers() {
133
145
.run ((context ) -> {
134
146
ReactiveHealthEndpointWebExtension extension = context
135
147
.getBean (ReactiveHealthEndpointWebExtension .class );
136
- assertThat (extension .health (mock (Principal .class )).block ().getBody ()
148
+ SecurityContext securityContext = mock (SecurityContext .class );
149
+ assertThat (extension .health (securityContext ).block ().getBody ()
137
150
.getDetails ()).isEmpty ();
138
151
});
139
152
}
140
153
154
+ @ Test
155
+ public void detailsCanBeHiddenFromUnauthorizedUsers () {
156
+ this .contextRunner .withPropertyValues (
157
+ "management.endpoint.health.show-details=when-authorized" ,
158
+ "management.endpoint.health.roles=ACTUATOR" ).run ((context ) -> {
159
+ ReactiveHealthEndpointWebExtension extension = context
160
+ .getBean (ReactiveHealthEndpointWebExtension .class );
161
+ SecurityContext securityContext = mock (SecurityContext .class );
162
+ given (securityContext .getPrincipal ())
163
+ .willReturn (mock (Principal .class ));
164
+ given (securityContext .isUserInRole ("ACTUATOR" )).willReturn (false );
165
+ assertThat (extension .health (securityContext ).block ().getBody ()
166
+ .getDetails ()).isEmpty ();
167
+ });
168
+ }
169
+
170
+ @ Test
171
+ public void detailsCanBeShownToAuthorizedUsers () {
172
+ this .contextRunner .withPropertyValues (
173
+ "management.endpoint.health.show-details=when-authorized" ,
174
+ "management.endpoint.health.roles=ACTUATOR" ).run ((context ) -> {
175
+ ReactiveHealthEndpointWebExtension extension = context
176
+ .getBean (ReactiveHealthEndpointWebExtension .class );
177
+ SecurityContext securityContext = mock (SecurityContext .class );
178
+ given (securityContext .getPrincipal ())
179
+ .willReturn (mock (Principal .class ));
180
+ given (securityContext .isUserInRole ("ACTUATOR" )).willReturn (true );
181
+ assertThat (extension .health (securityContext ).block ().getBody ()
182
+ .getDetails ()).isNotEmpty ();
183
+ });
184
+ }
185
+
186
+ @ Test
187
+ public void roleCanBeCustomized () {
188
+ this .contextRunner .withPropertyValues (
189
+ "management.endpoint.health.show-details=when-authorized" ,
190
+ "management.endpoint.health.roles=ADMIN" ).run ((context ) -> {
191
+ ReactiveHealthEndpointWebExtension extension = context
192
+ .getBean (ReactiveHealthEndpointWebExtension .class );
193
+ SecurityContext securityContext = mock (SecurityContext .class );
194
+ given (securityContext .getPrincipal ())
195
+ .willReturn (mock (Principal .class ));
196
+ given (securityContext .isUserInRole ("ADMIN" )).willReturn (true );
197
+ assertThat (extension .health (securityContext ).block ().getBody ()
198
+ .getDetails ()).isNotEmpty ();
199
+ });
200
+ }
201
+
141
202
@ Configuration
142
203
static class HealthIndicatorsConfiguration {
143
204
0 commit comments