spring-projects / spring-boot

Spring Boot
https://spring.io/projects/spring-boot
Apache License 2.0
74.8k stars 40.6k forks source link

EndpointRequest.toLinks() does not match when management.endpoints.web.base-path is '/' #34834

Open nightswimmings opened 1 year ago

nightswimmings commented 1 year ago

I am using a different management port with management.server.base-path: '/management' and management.endpoints.web.base-path: '/'.

When setting up security as .requestMatchers(EndpointRequest.toLinks()).permitAll(), then performing a request over '/management/', returns 403

Root cause: WebEndpointProperties.setBasePath cleans '/' as ''.

Later on, upon first '/' call, LinksRequestMatcher sees the empty basepath and returns EndpointRequest.EMPTY_MATCHER, which always evaluates to false

somayaj commented 1 year ago

Can this be worked? or is a triage still planned? WebEndpointProperties ln 70 needs fixing.

https://github.com/spring-projects/spring-boot/blob/main/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/WebEndpointProperties.java#L

philwebb commented 1 year ago

@somayaj You're welcome to work on the issue, I'll assign it to you. Ideally we'll be looking to add a test as well.

wilkinsona commented 1 year ago

This is deceptively complicated as EndpointRequest.toLinks() needs to return different matchers depending on whether or not actuator is running on a separate port.

somayaj commented 1 year ago

@wilkinsona not sure if this would make sense or would be in the right direction? public static final class LinksRequestMatcher extends AbstractRequestMatcher {

    @Override
    protected RequestMatcher createDelegate(WebApplicationContext context,
            RequestMatcherFactory requestMatcherFactory) {
        WebEndpointProperties properties = context.getBean(WebEndpointProperties.class);
        String basePath = properties.getBasePath();
        ManagementPortType port = ManagementPortType.get(context.getEnvironment());
        if (StringUtils.hasText(basePath) && !(port == ManagementPortType.DIFFERENT )) {
            return new OrRequestMatcher(
                    getLinksMatchers(requestMatcherFactory, getRequestMatcherProvider(context), basePath));
        }
        else if(port == ManagementPortType.DIFFERENT) {
            return new OrRequestMatcher(
                    getLinksMatchers(requestMatcherFactory, getRequestMatcherProvider(context), properties.getBasePath())); // not sure what to put here yet? 
        }

        return EMPTY_MATCHER;
    }

}