WebMvcTagsProvider to ServerRequestObservationConvention

432 Views Asked by At

I try to remove WebMvcTagsProvider, because is deprecated in the new Spring versions, and replace it with ServerRequestObservationConvention but it seems that something is not working the same. In the previous implementation, when i use WebMvcTagsProvider i expose a custom metric that indicate the user name that is behind the requests. Now if i try the same thing a get a null user name. Is something that i do wrong?

Before


@Configuration
@EnableWebSecurity
@EnableConfigurationProperties
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private UserSecurityConfig userSecurityConfig;

    @Autowired
    public SecurityConfig(UserSecurityConfig userSecurityConfig) {
        this.userSecurityConfig = userSecurityConfig;
    }

    @Bean
    @Override
    public UserDetailsService userDetailsService() {

        PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();

        userSecurityConfig.getUsers()
                .stream()
                .map(user -> User.withUsername(user.getName())
                        .password(encoder.encode(user.getPass()))
                        .roles(user.getRoles()).build()
                )
                .forEach(manager::createUser);

        return manager;

    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().fullyAuthenticated();
        http.httpBasic();
        http.csrf().disable();
    }

}

@Component
public class PrometheusWebTagsProvider implements WebMvcTagsProvider {

    private static final String SPRING_SECURITY_CONTEXT_ATTRIBUTE = "SPRING_SECURITY_CONTEXT";

    @Override
    public Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response, Object handler, Throwable ex) {

        HttpSession session = request.getSession(true);

        return Arrays.asList(
                WebMvcTags.method(request),
                WebMvcTags.uri(request, response),
                WebMvcTags.exception(ex),
                WebMvcTags.status(response),
                WebMvcTags.outcome(response),
                Tag.of("username", extractUsername(session))
        );

    }

    @Override
    public Iterable<Tag> getLongRequestTags(HttpServletRequest request, Object handler) {
        return Arrays.asList(WebMvcTags.method(request), WebMvcTags.uri(request, null));
    }

    private String extractUsername(HttpSession session) {

        SecurityContext springSecurityContext = (SecurityContext) session.getAttribute(SPRING_SECURITY_CONTEXT_ATTRIBUTE);
        if(springSecurityContext == null) {
            return "";
        }

        Authentication authentication = springSecurityContext.getAuthentication();
        if(authentication == null) {
            return "";
        }

        return authentication.getName();

    }

}


After


@Configuration
@EnableWebSecurity
@EnableConfigurationProperties
public class SecurityConfig {

    private final UserSecurityConfig userSecurityConfig;

    @Autowired
    public SecurityConfig(UserSecurityConfig userSecurityConfig) {
        this.userSecurityConfig = userSecurityConfig;
    }

    @Bean
    public UserDetailsService userDetailsService() {

        PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();

        userSecurityConfig.getUsers()
                .stream()
                .map(user -> User.withUsername(user.getName())
                        .password(encoder.encode(user.getPass()))
                        .roles(user.getRoles()).build()
                )
                .forEach(manager::createUser);

        return manager;

    }

    @Bean
    public SecurityFilterChain configure(HttpSecurity http) throws Exception  {

        http.authorizeHttpRequests(auth -> auth.anyRequest().fullyAuthenticated())
            .httpBasic(withDefaults())
            .csrf(AbstractHttpConfigurer::disable);

        return http.build();
    }

}

@Component
@Slf4j
public class PrometheusWebTagsProvider implements ServerRequestObservationConvention {

    private static final String SPRING_SECURITY_CONTEXT_ATTRIBUTE = "SPRING_SECURITY_CONTEXT";

    @Override
    public String getName() {
        return "http.server.requests";
    }

    @Override
    public String getContextualName(ServerRequestObservationContext context) {
        return "http " + context.getCarrier().getMethod().toLowerCase();
    }

    @Override
    @NonNull
    public KeyValues getLowCardinalityKeyValues(@NonNull ServerRequestObservationContext context) {
        return KeyValues.of(method(context), status(context), exception(context)).and(additionalTags(context));
    }

    private KeyValues additionalTags(ServerRequestObservationContext context) {

        KeyValues keyValues = KeyValues.empty();
        keyValues = keyValues.and(method(context));
        keyValues = keyValues.and(status(context));
        keyValues = keyValues.and(exception(context));
        keyValues = keyValues.and(KeyValue.of("uri", context.getCarrier().getRequestURI()));
        keyValues = keyValues.and(KeyValue.of("username", extractUsername(context.getCarrier().getSession())));
        keyValues = keyValues.and(KeyValue.of("outcome", outcome(context.getResponse()).getValue()));

        return keyValues;

    }

    private KeyValue method(ServerRequestObservationContext context) {
        return KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.METHOD, context.getCarrier().getMethod());
    }

    private KeyValue status(ServerRequestObservationContext context) {
        return KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.STATUS, Integer.toString(context.getResponse().getStatus()));
    }


    private KeyValue exception(ServerRequestObservationContext context) {

        Throwable error = context.getError();

        if (error == null) {
            return KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.EXCEPTION, "none");
        }

        return KeyValue.of(ServerHttpObservationDocumentation.LowCardinalityKeyNames.EXCEPTION, error.getClass().getName());
    }

    private String extractUsername(HttpSession session) {

        SecurityContext springSecurityContext = (SecurityContext) session.getAttribute(SPRING_SECURITY_CONTEXT_ATTRIBUTE);

        if (springSecurityContext == null) {
            return "";
        }

        Authentication authentication = springSecurityContext.getAuthentication();
        if (authentication == null) {
            return "";
        }

        return authentication.getName();

    }

    private static Tag outcome(HttpServletResponse response) {
        Outcome outcome = response != null ? Outcome.forStatus(response.getStatus()) : Outcome.UNKNOWN;
        return outcome.asTag();
    }

}

0

There are 0 best solutions below