Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion credentials/verifier_default.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func (v *VerifierDefault) Verify(
}

if len(r.Issuers) > 0 {
if !slices.Contains(r.Issuers, parsedClaims.Issuer) {
if !matchesTrustedIssuer(r.Issuers, parsedClaims.Issuer) {
return nil, herodot.ErrUnauthorized().WithReasonf("Token issuer does not match any trusted issuer %s.", parsedClaims.Issuer).
WithDetail("received issuers", strings.Join(r.Issuers, ", "))
}
Expand Down Expand Up @@ -166,3 +166,20 @@ func scope(claims map[string]interface{}) ([]string, string) {
return []string{}, key
}
}

// matchesTrustedIssuer reports whether the token issuer matches any of the
// trusted issuers, treating issuers that differ only by a trailing slash as
// equal. This avoids rejecting otherwise-valid tokens when the trusted_issuers
// configuration and the token's "iss" claim disagree on a trailing "/" (for
// example "https://issuer" versus "https://issuer/").
//
// See https://github.com/ory/oathkeeper/issues/527.
func matchesTrustedIssuer(trusted []string, issuer string) bool {
issuer = strings.TrimSuffix(issuer, "/")
for _, t := range trusted {
if strings.TrimSuffix(t, "/") == issuer {
return true
}
}
return false
}
40 changes: 40 additions & 0 deletions credentials/verifier_default_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,46 @@ func TestVerifierDefault(t *testing.T) {
}, "file://../test/stub/jwks-hs.json"),
expectErr: true,
},
{
d: "should pass when the trusted issuer has a trailing slash but the token issuer does not (issue #527)",
c: &ValidationContext{
Algorithms: []string{"HS256"},
Issuers: []string{"https://my-issuer/"},
KeyURLs: []url.URL{*x.ParseURLOrPanic("file://../test/stub/jwks-hs.json")},
},
token: sign(jwt.MapClaims{
"sub": "sub",
"exp": now.Add(time.Hour).Unix(),
"iss": "https://my-issuer",
}, "file://../test/stub/jwks-hs.json"),
},
{
d: "should pass when the token issuer has a trailing slash but the trusted issuer does not (issue #527)",
c: &ValidationContext{
Algorithms: []string{"HS256"},
Issuers: []string{"https://my-issuer"},
KeyURLs: []url.URL{*x.ParseURLOrPanic("file://../test/stub/jwks-hs.json")},
},
token: sign(jwt.MapClaims{
"sub": "sub",
"exp": now.Add(time.Hour).Unix(),
"iss": "https://my-issuer/",
}, "file://../test/stub/jwks-hs.json"),
},
{
d: "should still fail when the issuer genuinely differs despite trailing-slash normalization (issue #527)",
c: &ValidationContext{
Algorithms: []string{"HS256"},
Issuers: []string{"https://my-issuer/"},
KeyURLs: []url.URL{*x.ParseURLOrPanic("file://../test/stub/jwks-hs.json")},
},
token: sign(jwt.MapClaims{
"sub": "sub",
"exp": now.Add(time.Hour).Unix(),
"iss": "https://evil-issuer",
}, "file://../test/stub/jwks-hs.json"),
expectErr: true,
},
} {
t.Run(fmt.Sprintf("case=%d/description=%s", k, tc.d), func(t *testing.T) {
claims, err := verifier.Verify(context.Background(), tc.token, tc.c)
Expand Down
2 changes: 1 addition & 1 deletion oryx/openapix/jsonpatch.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type JSONPatchDocument []JSONPatch
//
// swagger:model jsonPatch
type JSONPatch struct {
// The operation to be performed. One of "add", "remove", "replace", "move", "copy", or "test".
// The operation to be performed. One of "add", "remove", or "replace".
//
// required: true
// example: replace
Expand Down
Loading