1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.bremersee.actuator.security.authentication;
18
19 import java.util.ArrayList;
20 import java.util.List;
21 import java.util.Set;
22 import java.util.TreeSet;
23 import java.util.stream.Collectors;
24 import javax.validation.constraints.NotEmpty;
25 import javax.validation.constraints.NotNull;
26 import lombok.EqualsAndHashCode;
27 import lombok.Getter;
28 import lombok.Setter;
29 import lombok.ToString;
30 import org.bremersee.security.authentication.AccessExpressionUtils;
31 import org.bremersee.security.authentication.AutoSecurityMode;
32 import org.bremersee.security.authentication.ClientCredentialsFlowProperties;
33 import org.bremersee.security.core.AuthorityConstants;
34 import org.springframework.boot.context.properties.ConfigurationProperties;
35 import org.springframework.util.StringUtils;
36 import org.springframework.validation.annotation.Validated;
37
38
39
40
41
42
43 @ConfigurationProperties(prefix = "bremersee.actuator.auth")
44 @Getter
45 @Setter
46 @ToString
47 @EqualsAndHashCode
48 @Validated
49 public class ActuatorAuthProperties {
50
51
52
53
54 @NotNull
55 private AutoSecurityMode enable = AutoSecurityMode.OTHER;
56
57
58
59
60 private int order = 61;
61
62
63
64
65 private boolean enableCors = true;
66
67
68
69
70 @NotNull
71 private List<Class<?>> unauthenticatedEndpoints = new ArrayList<>();
72
73
74
75
76 @NotNull
77 private List<String> adminRoles = new ArrayList<>();
78
79
80
81
82 @NotNull
83 private List<String> roles = new ArrayList<>();
84
85
86
87
88 @NotNull
89 private List<String> ipAddresses = new ArrayList<>();
90
91
92
93
94 private String jwkSetUri;
95
96
97
98
99 @NotEmpty
100 private String jwsAlgorithm = "RS256";
101
102
103
104
105 private String issuerUri;
106
107
108
109
110 @NotEmpty
111 private String rolesJsonPath = "$.realm_access.roles";
112
113
114
115
116 private boolean rolesValueList = true;
117
118
119
120
121 @NotNull
122 private String rolesValueSeparator = " ";
123
124
125
126
127 @NotNull
128 private String rolePrefix = "ROLE_";
129
130
131
132
133 @NotEmpty
134 private String nameJsonPath = "$.preferred_username";
135
136
137
138
139 @NotNull
140 private ActuatorPasswordFlow passwordFlow = new ActuatorPasswordFlow();
141
142
143
144
145
146
147 @NotNull
148 public List<Class<?>> unauthenticatedEndpointsOrDefaults() {
149 if (unauthenticatedEndpoints.isEmpty()) {
150 unauthenticatedEndpoints.add(
151 org.springframework.boot.actuate.health.HealthEndpoint.class);
152 unauthenticatedEndpoints.add(
153 org.springframework.boot.actuate.info.InfoEndpoint.class);
154 }
155 return unauthenticatedEndpoints;
156 }
157
158
159
160
161
162
163 @NotNull
164 public Set<String> rolesOrDefaults() {
165 final TreeSet<String> roleSet = new TreeSet<>(roles);
166 if (roleSet.isEmpty()) {
167 roleSet.add(AuthorityConstants.ACTUATOR_ROLE_NAME);
168 roleSet.add(AuthorityConstants.ACTUATOR_ADMIN_ROLE_NAME);
169 roleSet.add(AuthorityConstants.ADMIN_ROLE_NAME);
170 }
171 return roleSet.stream()
172 .map(this::ensureRolePrefix)
173 .collect(Collectors.toSet());
174 }
175
176
177
178
179
180
181 @NotNull
182 public Set<String> adminRolesOrDefaults() {
183 final TreeSet<String> roleSet = new TreeSet<>(adminRoles);
184 if (roleSet.isEmpty()) {
185 roleSet.add(AuthorityConstants.ACTUATOR_ADMIN_ROLE_NAME);
186 roleSet.add(AuthorityConstants.ADMIN_ROLE_NAME);
187 }
188 return roleSet.stream()
189 .map(this::ensureRolePrefix)
190 .collect(Collectors.toSet());
191 }
192
193
194
195
196
197
198 @NotNull
199 public String buildAccessExpression() {
200 return AccessExpressionUtils.hasAuthorityOrIpAddressExpr(
201 rolesOrDefaults(), null, ipAddresses);
202 }
203
204
205
206
207
208
209 @NotNull
210 public String buildAdminAccessExpression() {
211 return AccessExpressionUtils.hasAuthorityOrIpAddressExpr(adminRolesOrDefaults(), null, null);
212 }
213
214
215
216
217
218
219
220 @NotNull
221 public String ensureRolePrefix(@NotNull String role) {
222 final String prefix = rolePrefix.trim();
223 return StringUtils.hasText(prefix) && role.startsWith(prefix) ? role : prefix + role;
224 }
225
226
227
228
229 @Getter
230 @Setter
231 @ToString(exclude = {"clientSecret"})
232 @EqualsAndHashCode(exclude = {"clientSecret"})
233 public static class ActuatorPasswordFlow implements ClientCredentialsFlowProperties {
234
235 private String tokenEndpoint;
236
237 private String clientId;
238
239 private String clientSecret;
240 }
241 }