Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
14 changes: 9 additions & 5 deletions client/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,11 +259,12 @@ func (m *MTLSEndpoints) ApplyForSenderConstrain(endpoints *Endpoints) bool {
// ApplyForClientAuth is ApplyForSenderConstrain's own counterpart for
// RFC 8705 §2 client authentication
// (Config.ClientAuthMethod == ClientAuthMethodSelfSignedTLSClientAuth
// or ClientAuthMethodTLSClientAuth): overrides endpoints' Token and
// PushedAuthorizationRequest fields, since a certificate-authenticated
// client must present its certificate at PAR too, not just at the
// token endpoint — the same asymmetry a server's own client
// authentication enforces. m may be nil, in which case
// or ClientAuthMethodTLSClientAuth): overrides endpoints' Token,
// PushedAuthorizationRequest and Revocation fields, since a
// certificate-authenticated client must present its certificate at PAR
// and token revocation (RevokeToken) too, not just at the token
// endpoint — the same asymmetry a server's own client authentication
// enforces. m may be nil, in which case
// ApplyForClientAuth leaves endpoints untouched and reports false, for
// the same reason ApplyForSenderConstrain does.
func (m *MTLSEndpoints) ApplyForClientAuth(endpoints *Endpoints) bool {
Expand All @@ -276,6 +277,9 @@ func (m *MTLSEndpoints) ApplyForClientAuth(endpoints *Endpoints) bool {
if !m.PushedAuthorizationRequest.IsZero() {
endpoints.PushedAuthorizationRequest = m.PushedAuthorizationRequest
}
if !m.Revocation.IsZero() {
endpoints.Revocation = m.Revocation
}
return true
}

Expand Down
9 changes: 7 additions & 2 deletions client/mtls_endpoints_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,21 @@ func TestMTLSEndpointsApplyForSenderConstrainOverridesTokenAndBackchannel(t *tes
}

// TestMTLSEndpointsApplyForClientAuthOverridesTokenAndPAR covers
// ApplyForClientAuth's own field selection: Token and
// PushedAuthorizationRequest move to their mTLS alias;
// ApplyForClientAuth's own field selection: Token,
// PushedAuthorizationRequest and Revocation move to their mTLS alias;
// BackchannelAuthentication is untouched (only ApplyForSenderConstrain
// ever moves it).
func TestMTLSEndpointsApplyForClientAuthOverridesTokenAndPAR(t *testing.T) {
aliases := &client.MTLSEndpoints{
Token: mustEndpointURL(t, "https://mtls.example.com/token"),
PushedAuthorizationRequest: mustEndpointURL(t, "https://mtls.example.com/par"),
Revocation: mustEndpointURL(t, "https://mtls.example.com/revoke"),
}
endpoints := client.Endpoints{
Token: mustEndpointURL(t, "https://as.example.com/token"),
PushedAuthorizationRequest: mustEndpointURL(t, "https://as.example.com/par"),
BackchannelAuthentication: mustEndpointURL(t, "https://as.example.com/backchannel"),
Revocation: mustEndpointURL(t, "https://as.example.com/revoke"),
}

if !aliases.ApplyForClientAuth(&endpoints) {
Expand All @@ -74,6 +76,9 @@ func TestMTLSEndpointsApplyForClientAuthOverridesTokenAndPAR(t *testing.T) {
if got, want := endpoints.PushedAuthorizationRequest.String(), aliases.PushedAuthorizationRequest.String(); got != want {
t.Errorf("PushedAuthorizationRequest = %s, want alias %s", got, want)
}
if got, want := endpoints.Revocation.String(), aliases.Revocation.String(); got != want {
t.Errorf("Revocation = %s, want alias %s", got, want)
}
if got, want := endpoints.BackchannelAuthentication.String(), "https://as.example.com/backchannel"; got != want {
t.Errorf("BackchannelAuthentication = %s, want untouched %s", got, want)
}
Expand Down
10 changes: 6 additions & 4 deletions federation/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,10 +300,12 @@ func newChainWalkState(subjectID string, leafStmt intfed.Statement, leafToken st
// Resolve resolves subjectID's Trust Chain against one of
// Config.TrustAnchors and returns its Resolved Metadata, enforcing
// every Subordinate Statement's own max_path_length, naming_constraints
// and allowed_entity_types constraints along the way. See doc.go for
// this release's scope (leaf-entity resolution only, automatic
// registration's own trust model — no server-side federation endpoints
// of this Resolver's own, no trust marks).
// and allowed_entity_types constraints along the way. It resolves a
// leaf entity for automatic registration's trust model. The Trust Marks
// the entity declares come back unverified in ResolvedEntity.TrustMarks,
// for VerifyTrustMark; issuing statements and serving federation
// endpoints is SelfIssuer's and SubordinateIssuer's job, not a
// Resolver's. See doc.go for the package's scope.
func (r *Resolver) Resolve(ctx context.Context, subjectID string) (ResolvedEntity, error) {
if subjectID == "" {
return ResolvedEntity{}, fmt.Errorf("federation: subject entity ID is empty")
Expand Down
Loading