Skip to content

Actuator HTTP trace data not reported for OAuth endpoints #760

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
mikesaurus opened this issue Jun 2, 2022 · 11 comments
Closed

Actuator HTTP trace data not reported for OAuth endpoints #760

mikesaurus opened this issue Jun 2, 2022 · 11 comments
Assignees
Labels
status: duplicate A duplicate of another issue

Comments

@mikesaurus
Copy link

Describe the bug
When implementing Spring Authorization Server and Spring Boot Actuator with the HTTP Trace endpoint enabled, Spring Boot Actuator does not report any trace data for requests to OAuth endpoints (/authorize, /token, etc.). Non-OAuth requests, such as the requests to the Actuator endpoints are reported as expected.

This was first discovered with our authorization server that implements a custom authorization consent page and integrates with Spring Boot Admin. Spring Boot Admin reports (via the authorization server Actuator endpoints) requests for Actuator endpoints and the custom authorization consent page (mapped in a custom controller). However, HTTP Trace data does not include the OAuth endpoint requests. This behavior was reproduced using the samples in the spring-authorization-server project.

To Reproduce

  1. Clone the spring-authorization-server
  2. Update the "default-authorizationserver" sample with these 3 changes:
  • Add the Spring Boot Actuator dependency to the modules .gradle file
    implementation "org.springframework.boot:spring-boot-starter-actuator"
  • Expose the Actuator endpoints in the application.yaml file
management:
  endpoints:
    web:
      exposure:
        include: '*'
  • Add an HttpTraceRepository bean to the server config
    @Bean
    public HttpTraceRepository httpTraceRepository() {
        return new InMemoryHttpTraceRepository();
    }
  1. Run the default-authorizationserver, messages-resource, and messages-client samples according to the README
  2. Go to http://127.0.0.1:8080 and run through the sample workflow
  3. Go to http://127.0.0.1:9000/actuator/httptrace and view the HTTP Trace data

Expected behavior
Requests/responses for all OAuth endpoints are reported via the /actuator/httptrace endpoint.

Sample

https://github.com/spring-projects/spring-authorization-server/tree/main/samples

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jun 2, 2022
@pxzxj
Copy link

pxzxj commented Jun 2, 2022

@mikesaurus the HttpTraceFilter default order is Ordered.LOWEST_PRECEDENCE - 10,so it's after spring security FilterChain.
The spring security FilterChain will not continue the subsequent filter after processing the oauth2 request.

httptrace

The solution is to create a HttpTrace bean and specify its order lower than spring security FilterChain order.

@Configuration
public class WebConfig {

	@Bean
	HttpTraceFilter httpTraceFilter(HttpTraceRepository repository, HttpExchangeTracer tracer, SecurityProperties securityProperties) {
		HttpTraceFilter httpTraceFilter = new HttpTraceFilter(repository, tracer);
		httpTraceFilter.setOrder(securityProperties.getFilter().getOrder() - 1);
		return httpTraceFilter;
	}

}

@mikesaurus
Copy link
Author

@pxzxj Thank you! Tested this solution out with the sample project and it works as you said. We'll look to incorporate this into our authorization server implementation.

While this is a simple fix for an application to make, it feels like an application should expect to get this behavior by default. It doesn't seem right to have to customize base Spring filter configurations for what should be plain vanilla usage of Spring Auth Server and Spring Boot Actuator. I can understand why Spring's default ordering is configured the way it is, but the OAuth2 endpoint filters are functional endpoints and not layered application security. It feels like this solution should be incorporated into the Spring Auth Server lib to ensure that provided functional behavior can be traced appropriately with standard Spring tooling.

@pxzxj
Copy link

pxzxj commented Jun 3, 2022

let me make some additions.
While specifing the filter order cant fix the problem, the source of the problem is not the filter order,but the sping security filter convention.
I read a lot of spring security filter source code and found that filterChain.doFilter(request, response) is no longer called if someting has been writen to the response. for example the DefaultLogoutPageGeneratingFilter

public class DefaultLogoutPageGeneratingFilter extends OncePerRequestFilter {
	private RequestMatcher matcher = new AntPathRequestMatcher("/logout", "GET");

	@Override
	protected void doFilterInternal(HttpServletRequest request,
			HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		if (this.matcher.matches(request)) {
			renderLogout(request, response);
		} else {
			filterChain.doFilter(request, response);
		}
	}

	private void renderLogout(HttpServletRequest request, HttpServletResponse response)
			throws IOException {
		String page =  "<!DOCTYPE html>\n"
				+ "<html lang=\"en\">\n"
                              // logout page content
				+ "</html>";

		response.setContentType("text/html;charset=UTF-8");
		response.getWriter().write(page);
	}
}

The same goes for oauth2 filters used to process oauth2 requests. So subsequent filters will not be called after processing the oauth2 request.
Actually, I cannot understand why filterChain.doFilter(request, response) is no longer called after the response is written, do you have any ideas?

@jgrandja
Copy link
Collaborator

@pxzxj Thank you for providing the configuration that resolves this issue!

@mikesaurus

It feels like this solution should be incorporated into the Spring Auth Server lib

Since HttpTraceFilter lives in Spring Boot, the correct filter order should be specified in the Spring Boot auto-configuration classes.

I added an item in gh-673 to track this issue. Closing this as a duplicate.

@jgrandja jgrandja self-assigned this Jun 14, 2022
@jgrandja jgrandja added status: duplicate A duplicate of another issue and removed status: waiting-for-triage An issue we've not yet triaged labels Jun 14, 2022
@pxzxj
Copy link

pxzxj commented Jun 15, 2022

hi, @jgrandja , as my comment above said,i don't think changing the filter order is the right solution for this problem. HttpTraceFilter is generally on ApplicationFilterChain but OAuth2Filter is on SecurityFilterChain. changing their order is not simple.
in addition, can you help me with the question: why filterChain.doFilter(request, response) is no longer called after the response is written, i can't find an answer in stackoverflow

@jgrandja
Copy link
Collaborator

@pxzxj

why filterChain.doFilter(request, response) is no longer called after the response is written

Which Filter are you referring to?

@pxzxj
Copy link

pxzxj commented Jun 15, 2022

Almost any Spring Security filter that writes content to the response.
for example the OAuth2TokenEndpointFilterOAuth2AuthorizationServerMetadataEndpointFilterDefaultLogoutPageGeneratingFilter

public final class OAuth2TokenEndpointFilter extends OncePerRequestFilter {
    	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {

		if (!this.tokenEndpointMatcher.matches(request)) {
			filterChain.doFilter(request, response);
			return;
		}

		// these code generate token and write it to response,but filterChain never been called to execute follow-up filters
	}
}

@jgrandja
Copy link
Collaborator

@pxzxj If the incoming request is an OAuth2 access token request then OAuth2TokenEndpointFilter will handle it and return the access token response. There is no need to pass the request to the next filter in chain since the current request is meant for OAuth2TokenEndpointFilter to handle.

@saldanaj27
Copy link

Any update on this with the newer versions of spring and /httptrace became deprecated? I have the same issue and would want to see information on /token and /authorize

@saldanaj27
Copy link

saldanaj27 commented Jan 26, 2023

@jgrandja

@jgrandja
Copy link
Collaborator

jgrandja commented Jan 26, 2023

@saldanaj27 See comment. Also, logging was added in gh-159. You can enable TRACE logging for more info.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: duplicate A duplicate of another issue
Projects
None yet
Development

No branches or pull requests

5 participants