• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

zalando / logbook / 5242

09 Jan 2026 05:56PM UTC coverage: 98.199% (-1.8%) from 100.0%
5242

push

github

web-flow
Fix coveral on main builds (#2201)

* Switch to com.github.hazendaz.maven:coveralls-maven-plugin as org.eluder.coveralls is deprecated

* tmp allow coveral on PRs

* revert the tmp allow coveral on PRs

* use ${project.artifactId} instaed of ${artifactId} in pom.xml

754 of 768 branches covered (98.18%)

3871 of 3942 relevant lines covered (98.2%)

0.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/logbook-core/src/main/java/org/zalando/logbook/core/attributes/JwtFirstMatchingClaimExtractor.java
1
package org.zalando.logbook.core.attributes;
2

3
import java.util.ArrayList;
4
import java.util.Collections;
5
import java.util.List;
6
import java.util.Objects;
7
import java.util.Optional;
8
import jakarta.annotation.Nonnull;
9
import jakarta.annotation.Nullable;
10
import lombok.EqualsAndHashCode;
11
import lombok.extern.slf4j.Slf4j;
12
import org.apiguardian.api.API;
13
import org.zalando.logbook.HttpRequest;
14
import org.zalando.logbook.attributes.AttributeExtractor;
15
import org.zalando.logbook.attributes.HttpAttributes;
16
import tools.jackson.databind.json.JsonMapper;
17

18
import static org.apiguardian.api.API.Status.EXPERIMENTAL;
19

20
/**
21
 * Extracts a single claim from the JWT bearer token in the request Authorization header.
22
 * Jackson 3.x (tools.jackson namespace) version.
23
 * By default, the subject claim "sub" is extracted, but you can pass an (ordered) list of <code>claimNames</code>
24
 * to be scanned. The first claim in <code>claimNames</code> is then returned, or an empty attribute if no matching
25
 * claim is found.
26
 */
27
@API(status = EXPERIMENTAL)
28
@Slf4j
×
29
@EqualsAndHashCode
30
public final class JwtFirstMatchingClaimExtractor implements AttributeExtractor {
31

32
    // RFC 7519 section-4.1.2: The "sub" (subject) claim identifies the principal that is the subject of the JWT.
33
    private static final String DEFAULT_SUBJECT_CLAIM = "sub";
34
    private static final String DEFAULT_CLAIM_KEY = "subject";
35

36
    private final List<String> claimNames;
37
    private final JwtClaimsExtractor jwtClaimsExtractor;
38

39
    @Nonnull
40
    private final String claimKey;
41

42
    public JwtFirstMatchingClaimExtractor(
43
            @Nonnull final JsonMapper jsonMapper,
44
            @Nonnull final List<String> claimNames,
45
            @Nonnull final String claimKey
46
    ) {
×
47
        this.claimNames = claimNames;
×
48
        this.claimKey = claimKey;
×
49
        jwtClaimsExtractor = new JwtClaimsExtractor(jsonMapper, new ArrayList<>(claimNames));
×
50
    }
×
51

52
    @API(status = EXPERIMENTAL)
53
    public static final class Builder {
54

55
    }
56

57
    @SuppressWarnings("unused")
58
    @lombok.Builder(builderClassName = "Builder")
59
    @Nonnull
60
    private static JwtFirstMatchingClaimExtractor create(
61
            @Nullable final JsonMapper jsonMapper,
62
            @Nullable final List<String> claimNames,
63
            @Nullable final String claimKey
64
    ) {
65
        return new JwtFirstMatchingClaimExtractor(
×
66
                Optional.ofNullable(jsonMapper).orElse(new JsonMapper()),
×
67
                Optional.ofNullable(claimNames).orElse(Collections.singletonList(DEFAULT_SUBJECT_CLAIM)),
×
68
                Optional.ofNullable(claimKey).orElse(DEFAULT_CLAIM_KEY)
×
69
        );
70
    }
71

72
    @Nonnull
73
    @Override
74
    public HttpAttributes extract(final HttpRequest request) {
75
        try {
76
            return claimNames.stream()
×
77
                    .map(jwtClaimsExtractor.extractClaims(request)::get)
×
78
                    .filter(Objects::nonNull)
×
79
                    .findFirst()
×
80
                    .map(value -> HttpAttributes.of(claimKey, jwtClaimsExtractor.toStringValue(value)))
×
81
                    .orElse(HttpAttributes.EMPTY);
×
82
        } catch (Exception e) {
×
83
            log.trace(
×
84
                    "Encountered error while extracting attributes: `{}`",
85
                    (Optional.ofNullable(e.getCause()).orElse(e)).getMessage()
×
86
            );
87
            return HttpAttributes.EMPTY;
×
88
        }
89
    }
90

91
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc