mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-24 10:19:03 +00:00
Add nullability annotations to module/spring-boot-cloudfoundry
See gh-46587
This commit is contained in:
+4
-2
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
/**
|
||||
@@ -28,11 +30,11 @@ public class CloudFoundryAuthorizationException extends RuntimeException {
|
||||
|
||||
private final Reason reason;
|
||||
|
||||
public CloudFoundryAuthorizationException(Reason reason, String message) {
|
||||
public CloudFoundryAuthorizationException(Reason reason, @Nullable String message) {
|
||||
this(reason, message, null);
|
||||
}
|
||||
|
||||
public CloudFoundryAuthorizationException(Reason reason, String message, Throwable cause) {
|
||||
public CloudFoundryAuthorizationException(Reason reason, @Nullable String message, @Nullable Throwable cause) {
|
||||
super(message, cause);
|
||||
this.reason = reason;
|
||||
}
|
||||
|
||||
+4
-2
@@ -18,6 +18,8 @@ package org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.EndpointExposureOutcomeContributor;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.expose.IncludeExcludeEndpointFilter;
|
||||
@@ -38,7 +40,7 @@ class CloudFoundryEndpointExposureOutcomeContributor implements EndpointExposure
|
||||
|
||||
private static final String PROPERTY = "management.endpoints.cloud-foundry.exposure";
|
||||
|
||||
private final IncludeExcludeEndpointFilter<?> filter;
|
||||
private final @Nullable IncludeExcludeEndpointFilter<?> filter;
|
||||
|
||||
CloudFoundryEndpointExposureOutcomeContributor(Environment environment) {
|
||||
this.filter = (!CloudPlatform.CLOUD_FOUNDRY.isActive(environment)) ? null
|
||||
@@ -46,7 +48,7 @@ class CloudFoundryEndpointExposureOutcomeContributor implements EndpointExposure
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getExposureOutcome(EndpointId endpointId, Set<EndpointExposure> exposures,
|
||||
public @Nullable ConditionOutcome getExposureOutcome(EndpointId endpointId, Set<EndpointExposure> exposures,
|
||||
Builder message) {
|
||||
if (exposures.contains(EndpointExposure.WEB) && this.filter != null && this.filter.match(endpointId)) {
|
||||
return ConditionOutcome.match(message.because("marked as exposed by a '" + PROPERTY + "' property"));
|
||||
|
||||
+4
-2
@@ -19,6 +19,8 @@ package org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.aot.hint.MemberCategory;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||
@@ -60,7 +62,7 @@ public class CloudFoundryWebEndpointDiscoverer extends WebEndpointDiscoverer {
|
||||
*/
|
||||
public CloudFoundryWebEndpointDiscoverer(ApplicationContext applicationContext,
|
||||
ParameterValueMapper parameterValueMapper, EndpointMediaTypes endpointMediaTypes,
|
||||
List<PathMapper> endpointPathMappers, Collection<OperationInvokerAdvisor> invokerAdvisors,
|
||||
@Nullable List<PathMapper> endpointPathMappers, Collection<OperationInvokerAdvisor> invokerAdvisors,
|
||||
Collection<EndpointFilter<ExposableWebEndpoint>> endpointFilters,
|
||||
Collection<OperationFilter<WebOperation>> operationFilters) {
|
||||
super(applicationContext, parameterValueMapper, endpointMediaTypes, endpointPathMappers, null, invokerAdvisors,
|
||||
@@ -89,7 +91,7 @@ public class CloudFoundryWebEndpointDiscoverer extends WebEndpointDiscoverer {
|
||||
static class CloudFoundryWebEndpointDiscovererRuntimeHints implements RuntimeHintsRegistrar {
|
||||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
|
||||
hints.reflection()
|
||||
.registerType(CloudFoundryEndpointFilter.class, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
|
||||
}
|
||||
|
||||
+5
-3
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
/**
|
||||
@@ -28,13 +30,13 @@ public class SecurityResponse {
|
||||
|
||||
private final HttpStatus status;
|
||||
|
||||
private final String message;
|
||||
private final @Nullable String message;
|
||||
|
||||
public SecurityResponse(HttpStatus status) {
|
||||
this(status, null);
|
||||
}
|
||||
|
||||
public SecurityResponse(HttpStatus status, String message) {
|
||||
public SecurityResponse(HttpStatus status, @Nullable String message) {
|
||||
this.status = status;
|
||||
this.message = message;
|
||||
}
|
||||
@@ -43,7 +45,7 @@ public class SecurityResponse {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
public @Nullable String getMessage() {
|
||||
return this.message;
|
||||
}
|
||||
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Auto-configuration for Cloud Foundry endpoints.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+5
-2
@@ -23,6 +23,8 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
@@ -128,12 +130,13 @@ public final class CloudFoundryReactiveActuatorAutoConfiguration {
|
||||
|
||||
private SecurityInterceptor getSecurityInterceptor(WebClient.Builder webClientBuilder, Environment environment) {
|
||||
SecurityService cloudfoundrySecurityService = getCloudFoundrySecurityService(webClientBuilder, environment);
|
||||
TokenValidator tokenValidator = new TokenValidator(cloudfoundrySecurityService);
|
||||
TokenValidator tokenValidator = (cloudfoundrySecurityService != null)
|
||||
? new TokenValidator(cloudfoundrySecurityService) : null;
|
||||
return new SecurityInterceptor(tokenValidator, cloudfoundrySecurityService,
|
||||
environment.getProperty("vcap.application.application_id"));
|
||||
}
|
||||
|
||||
private SecurityService getCloudFoundrySecurityService(WebClient.Builder webClientBuilder,
|
||||
private @Nullable SecurityService getCloudFoundrySecurityService(WebClient.Builder webClientBuilder,
|
||||
Environment environment) {
|
||||
String cloudControllerUrl = environment.getProperty("vcap.application.cf_api");
|
||||
boolean skipSslValidation = environment.getProperty("management.cloudfoundry.skip-ssl-validation",
|
||||
|
||||
+3
-2
@@ -22,6 +22,7 @@ import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@@ -111,7 +112,7 @@ class CloudFoundryWebFluxEndpointHandlerMapping extends AbstractWebFluxEndpointH
|
||||
});
|
||||
}
|
||||
|
||||
private Map<String, Link> getAccessibleLinks(AccessLevel accessLevel, Map<String, Link> links) {
|
||||
private Map<String, Link> getAccessibleLinks(@Nullable AccessLevel accessLevel, Map<String, Link> links) {
|
||||
if (accessLevel == null) {
|
||||
return new LinkedHashMap<>();
|
||||
}
|
||||
@@ -169,7 +170,7 @@ class CloudFoundryWebFluxEndpointHandlerMapping extends AbstractWebFluxEndpointH
|
||||
private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
|
||||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
|
||||
this.reflectiveRegistrar.registerRuntimeHints(hints, CloudFoundryLinksHandler.class);
|
||||
this.bindingRegistrar.registerReflectionHints(hints.reflection(), Link.class);
|
||||
}
|
||||
|
||||
+11
-6
@@ -20,6 +20,7 @@ import java.util.Locale;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint.CloudFoundryAuthorizationException;
|
||||
@@ -28,6 +29,7 @@ import org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint.Secu
|
||||
import org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint.Token;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.cors.reactive.CorsUtils;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
@@ -41,16 +43,16 @@ class SecurityInterceptor {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(SecurityInterceptor.class);
|
||||
|
||||
private final TokenValidator tokenValidator;
|
||||
private final @Nullable TokenValidator tokenValidator;
|
||||
|
||||
private final SecurityService cloudFoundrySecurityService;
|
||||
private final @Nullable SecurityService cloudFoundrySecurityService;
|
||||
|
||||
private final String applicationId;
|
||||
private final @Nullable String applicationId;
|
||||
|
||||
private static final Mono<SecurityResponse> SUCCESS = Mono.just(SecurityResponse.success());
|
||||
|
||||
SecurityInterceptor(TokenValidator tokenValidator, SecurityService cloudFoundrySecurityService,
|
||||
String applicationId) {
|
||||
SecurityInterceptor(@Nullable TokenValidator tokenValidator, @Nullable SecurityService cloudFoundrySecurityService,
|
||||
@Nullable String applicationId) {
|
||||
this.tokenValidator = tokenValidator;
|
||||
this.cloudFoundrySecurityService = cloudFoundrySecurityService;
|
||||
this.applicationId = applicationId;
|
||||
@@ -65,7 +67,7 @@ class SecurityInterceptor {
|
||||
return Mono.error(new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE,
|
||||
"Application id is not available"));
|
||||
}
|
||||
if (this.cloudFoundrySecurityService == null) {
|
||||
if (this.cloudFoundrySecurityService == null || this.tokenValidator == null) {
|
||||
return Mono.error(new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE,
|
||||
"Cloud controller URL is not available"));
|
||||
}
|
||||
@@ -77,6 +79,9 @@ class SecurityInterceptor {
|
||||
}
|
||||
|
||||
private Mono<Void> check(ServerWebExchange exchange, String id) {
|
||||
Assert.state(this.tokenValidator != null, "'tokenValidator' must not be null");
|
||||
Assert.state(this.cloudFoundrySecurityService != null, "'cloudFoundrySecurityService' must not be null");
|
||||
Assert.state(this.applicationId != null, "'applicationId' must not be null");
|
||||
try {
|
||||
Token token = getToken(exchange.getRequest());
|
||||
return this.tokenValidator.validate(token)
|
||||
|
||||
+3
-1
@@ -135,7 +135,9 @@ class SecurityService {
|
||||
|
||||
private Map<String, String> extractTokenKeys(Map<String, Object> response) {
|
||||
Map<String, String> tokenKeys = new HashMap<>();
|
||||
for (Object key : (List<?>) response.get("keys")) {
|
||||
List<?> keys = (List<?>) response.get("keys");
|
||||
Assert.state(keys != null, "'keys' must not be null");
|
||||
for (Object key : keys) {
|
||||
Map<?, ?> tokenKey = (Map<?, ?>) key;
|
||||
tokenKeys.put((String) tokenKey.get("kid"), (String) tokenKey.get("value"));
|
||||
}
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Auto-configuration for Cloud Foundry WebFlux endpoints.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint.reactive;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
+5
-2
@@ -22,6 +22,8 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
|
||||
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration;
|
||||
@@ -134,12 +136,13 @@ public final class CloudFoundryActuatorAutoConfiguration {
|
||||
private SecurityInterceptor getSecurityInterceptor(RestTemplateBuilder restTemplateBuilder,
|
||||
Environment environment) {
|
||||
SecurityService cloudfoundrySecurityService = getCloudFoundrySecurityService(restTemplateBuilder, environment);
|
||||
TokenValidator tokenValidator = new TokenValidator(cloudfoundrySecurityService);
|
||||
TokenValidator tokenValidator = (cloudfoundrySecurityService != null)
|
||||
? new TokenValidator(cloudfoundrySecurityService) : null;
|
||||
return new SecurityInterceptor(tokenValidator, cloudfoundrySecurityService,
|
||||
environment.getProperty("vcap.application.application_id"));
|
||||
}
|
||||
|
||||
private SecurityService getCloudFoundrySecurityService(RestTemplateBuilder restTemplateBuilder,
|
||||
private @Nullable SecurityService getCloudFoundrySecurityService(RestTemplateBuilder restTemplateBuilder,
|
||||
Environment environment) {
|
||||
String cloudControllerUrl = environment.getProperty("vcap.application.cf_api");
|
||||
boolean skipSslValidation = environment.getProperty("management.cloudfoundry.skip-ssl-validation",
|
||||
|
||||
+2
-1
@@ -26,6 +26,7 @@ import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.aot.hint.BindingReflectionHintsRegistrar;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
@@ -172,7 +173,7 @@ class CloudFoundryWebEndpointServletHandlerMapping extends AbstractWebMvcEndpoin
|
||||
private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
|
||||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
||||
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
|
||||
this.reflectiveRegistrar.registerRuntimeHints(hints, CloudFoundryLinksHandler.class);
|
||||
this.bindingRegistrar.registerReflectionHints(hints.reflection(), Link.class);
|
||||
}
|
||||
|
||||
+13
-8
@@ -21,6 +21,7 @@ import java.util.Locale;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.EndpointId;
|
||||
import org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint.AccessLevel;
|
||||
@@ -30,6 +31,7 @@ import org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint.Secu
|
||||
import org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint.Token;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.cors.CorsUtils;
|
||||
|
||||
@@ -42,22 +44,22 @@ class SecurityInterceptor {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(SecurityInterceptor.class);
|
||||
|
||||
private final TokenValidator tokenValidator;
|
||||
private final @Nullable TokenValidator tokenValidator;
|
||||
|
||||
private final SecurityService cloudFoundrySecurityService;
|
||||
private final @Nullable SecurityService cloudFoundrySecurityService;
|
||||
|
||||
private final String applicationId;
|
||||
private final @Nullable String applicationId;
|
||||
|
||||
private static final SecurityResponse SUCCESS = SecurityResponse.success();
|
||||
|
||||
SecurityInterceptor(TokenValidator tokenValidator, SecurityService cloudFoundrySecurityService,
|
||||
String applicationId) {
|
||||
SecurityInterceptor(@Nullable TokenValidator tokenValidator, @Nullable SecurityService cloudFoundrySecurityService,
|
||||
@Nullable String applicationId) {
|
||||
this.tokenValidator = tokenValidator;
|
||||
this.cloudFoundrySecurityService = cloudFoundrySecurityService;
|
||||
this.applicationId = applicationId;
|
||||
}
|
||||
|
||||
SecurityResponse preHandle(HttpServletRequest request, EndpointId endpointId) {
|
||||
SecurityResponse preHandle(HttpServletRequest request, @Nullable EndpointId endpointId) {
|
||||
if (CorsUtils.isPreFlightRequest(request)) {
|
||||
return SecurityResponse.success();
|
||||
}
|
||||
@@ -66,7 +68,7 @@ class SecurityInterceptor {
|
||||
throw new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE,
|
||||
"Application id is not available");
|
||||
}
|
||||
if (this.cloudFoundrySecurityService == null) {
|
||||
if (this.cloudFoundrySecurityService == null || this.tokenValidator == null) {
|
||||
throw new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE,
|
||||
"Cloud controller URL is not available");
|
||||
}
|
||||
@@ -86,7 +88,10 @@ class SecurityInterceptor {
|
||||
return SecurityResponse.success();
|
||||
}
|
||||
|
||||
private void check(HttpServletRequest request, EndpointId endpointId) {
|
||||
private void check(HttpServletRequest request, @Nullable EndpointId endpointId) {
|
||||
Assert.state(this.cloudFoundrySecurityService != null, "'cloudFoundrySecurityService' must not be null");
|
||||
Assert.state(this.applicationId != null, "'applicationId' must not be null");
|
||||
Assert.state(this.tokenValidator != null, "'tokenValidator' must not be null");
|
||||
Token token = getToken(request);
|
||||
this.tokenValidator.validate(token);
|
||||
AccessLevel accessLevel = this.cloudFoundrySecurityService.getAccessLevel(token.toString(), this.applicationId);
|
||||
|
||||
+14
-5
@@ -22,6 +22,8 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint.AccessLevel;
|
||||
import org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint.CloudFoundryAuthorizationException;
|
||||
import org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint.CloudFoundryAuthorizationException.Reason;
|
||||
@@ -45,7 +47,7 @@ class SecurityService {
|
||||
|
||||
private final String cloudControllerUrl;
|
||||
|
||||
private String uaaUrl;
|
||||
private @Nullable String uaaUrl;
|
||||
|
||||
SecurityService(RestTemplateBuilder restTemplateBuilder, String cloudControllerUrl, boolean skipSslValidation) {
|
||||
Assert.notNull(restTemplateBuilder, "'restTemplateBuilder' must not be null");
|
||||
@@ -69,7 +71,7 @@ class SecurityService {
|
||||
URI uri = getPermissionsUri(applicationId);
|
||||
RequestEntity<?> request = RequestEntity.get(uri).header("Authorization", "bearer " + token).build();
|
||||
Map<?, ?> body = this.restTemplate.exchange(request, Map.class).getBody();
|
||||
if (Boolean.TRUE.equals(body.get("read_sensitive_data"))) {
|
||||
if (body != null && Boolean.TRUE.equals(body.get("read_sensitive_data"))) {
|
||||
return AccessLevel.FULL;
|
||||
}
|
||||
return AccessLevel.RESTRICTED;
|
||||
@@ -100,7 +102,9 @@ class SecurityService {
|
||||
*/
|
||||
Map<String, String> fetchTokenKeys() {
|
||||
try {
|
||||
return extractTokenKeys(this.restTemplate.getForObject(getUaaUrl() + "/token_keys", Map.class));
|
||||
Map<?, ?> response = this.restTemplate.getForObject(getUaaUrl() + "/token_keys", Map.class);
|
||||
Assert.state(response != null, "'response' must not be null");
|
||||
return extractTokenKeys(response);
|
||||
}
|
||||
catch (HttpStatusCodeException ex) {
|
||||
throw new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE, "UAA not reachable");
|
||||
@@ -109,7 +113,9 @@ class SecurityService {
|
||||
|
||||
private Map<String, String> extractTokenKeys(Map<?, ?> response) {
|
||||
Map<String, String> tokenKeys = new HashMap<>();
|
||||
for (Object key : (List<?>) response.get("keys")) {
|
||||
List<?> keys = (List<?>) response.get("keys");
|
||||
Assert.state(keys != null, "'keys' must not be null");
|
||||
for (Object key : keys) {
|
||||
Map<?, ?> tokenKey = (Map<?, ?>) key;
|
||||
tokenKeys.put((String) tokenKey.get("kid"), (String) tokenKey.get("value"));
|
||||
}
|
||||
@@ -124,7 +130,10 @@ class SecurityService {
|
||||
if (this.uaaUrl == null) {
|
||||
try {
|
||||
Map<?, ?> response = this.restTemplate.getForObject(this.cloudControllerUrl + "/info", Map.class);
|
||||
this.uaaUrl = (String) response.get("token_endpoint");
|
||||
Assert.state(response != null, "'response' must not be null");
|
||||
String tokenEndpoint = (String) response.get("token_endpoint");
|
||||
Assert.state(tokenEndpoint != null, "'tokenEndpoint' must not be null");
|
||||
this.uaaUrl = tokenEndpoint;
|
||||
}
|
||||
catch (HttpStatusCodeException ex) {
|
||||
throw new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE,
|
||||
|
||||
+11
-7
@@ -27,9 +27,12 @@ import java.util.Base64;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint.CloudFoundryAuthorizationException;
|
||||
import org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint.CloudFoundryAuthorizationException.Reason;
|
||||
import org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint.Token;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Validator used to ensure that a signed {@link Token} has not been tampered with.
|
||||
@@ -40,7 +43,7 @@ class TokenValidator {
|
||||
|
||||
private final SecurityService securityService;
|
||||
|
||||
private Map<String, String> tokenKeys;
|
||||
private @Nullable Map<String, String> tokenKeys;
|
||||
|
||||
TokenValidator(SecurityService cloudFoundrySecurityService) {
|
||||
this.securityService = cloudFoundrySecurityService;
|
||||
@@ -67,22 +70,23 @@ class TokenValidator {
|
||||
|
||||
private void validateKeyIdAndSignature(Token token) {
|
||||
String keyId = token.getKeyId();
|
||||
if (this.tokenKeys == null || !hasValidKeyId(keyId)) {
|
||||
if (this.tokenKeys == null || !hasValidKeyId(this.tokenKeys, keyId)) {
|
||||
this.tokenKeys = this.securityService.fetchTokenKeys();
|
||||
if (!hasValidKeyId(keyId)) {
|
||||
if (!hasValidKeyId(this.tokenKeys, keyId)) {
|
||||
throw new CloudFoundryAuthorizationException(Reason.INVALID_KEY_ID,
|
||||
"Key Id present in token header does not match");
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasValidSignature(token, this.tokenKeys.get(keyId))) {
|
||||
String key = this.tokenKeys.get(keyId);
|
||||
Assert.state(key != null, "'key' must not be null");
|
||||
if (!hasValidSignature(token, key)) {
|
||||
throw new CloudFoundryAuthorizationException(Reason.INVALID_SIGNATURE,
|
||||
"RSA Signature did not match content");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasValidKeyId(String tokenKey) {
|
||||
return this.tokenKeys.containsKey(tokenKey);
|
||||
private boolean hasValidKeyId(Map<String, String> tokenKeys, String tokenKey) {
|
||||
return tokenKeys.containsKey(tokenKey);
|
||||
}
|
||||
|
||||
private boolean hasValidSignature(Token token, String key) {
|
||||
|
||||
+3
@@ -17,4 +17,7 @@
|
||||
/**
|
||||
* Auto-configuration for Cloud Foundry Servlet endpoints.
|
||||
*/
|
||||
@NullMarked
|
||||
package org.springframework.boot.cloudfoundry.actuate.autoconfigure.endpoint.servlet;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
Reference in New Issue
Block a user