Skip to content
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

Remove protocol-specific authenticator interfaces #4255

Merged
merged 2 commits into from
Oct 26, 2021
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

## 🛑 Breaking changes 🛑
- Removed `configauth.HTTPClientAuthenticator` and `configauth.GRPCClientAuthenticator` in favor of `configauth.ClientAuthenticator` (#4255)

## 🛑 Breaking changes 🛑

- Rename `parserprovider.MapProvider` as `config.MapProvider` (#4178)
Expand Down
12 changes: 2 additions & 10 deletions config/configauth/clientauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,10 @@ import (
// names from the Authentication configuration.
type ClientAuthenticator interface {
component.Extension
}

// HTTPClientAuthenticator is a ClientAuthenticator that can be used as an authenticator
// for the configauth.Authentication option for HTTP clients.
type HTTPClientAuthenticator interface {
ClientAuthenticator
// RoundTripper returns a RoundTripper that can be used to authenticate HTTP requests.
RoundTripper(base http.RoundTripper) (http.RoundTripper, error)
}

// GRPCClientAuthenticator is a ClientAuthenticator that can be used as an authenticator for
// the configauth.Authentication option for gRPC clients.
type GRPCClientAuthenticator interface {
ClientAuthenticator
// PerRPCCredentials returns a PerRPCCredentials that can be used to authenticate gRPC requests.
PerRPCCredentials() (credentials.PerRPCCredentials, error)
}
27 changes: 8 additions & 19 deletions config/configauth/configauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ import (
)

var (
errAuthenticatorNotFound = errors.New("authenticator not found")
errAuthenticatorNotFound = errors.New("authenticator not found")
errNotClientAuthenticator = errors.New("requested authenticator is not a client authenticator")
errNotServerAuthenticator = errors.New("requested authenticator is not a server authenticator")
)

// Authentication defines the auth settings for the receiver.
Expand All @@ -39,34 +41,21 @@ func (a Authentication) GetServerAuthenticator(extensions map[config.ComponentID
if auth, ok := ext.(ServerAuthenticator); ok {
return auth, nil
}
return nil, fmt.Errorf("requested authenticator is not a server authenticator")
return nil, errNotServerAuthenticator
}

return nil, fmt.Errorf("failed to resolve authenticator %q: %w", a.AuthenticatorID, errAuthenticatorNotFound)
}

// GetHTTPClientAuthenticator attempts to select the appropriate HTTPClientAuthenticator from the list of extensions,
// GetClientAuthenticator attempts to select the appropriate ClientAuthenticator from the list of extensions,
// based on the component id of the extension. If an authenticator is not found, an error is returned.
// This should be only used by HTTP clients.
func (a Authentication) GetHTTPClientAuthenticator(extensions map[config.ComponentID]component.Extension) (HTTPClientAuthenticator, error) {
func (a Authentication) GetClientAuthenticator(extensions map[config.ComponentID]component.Extension) (ClientAuthenticator, error) {
if ext, found := extensions[a.AuthenticatorID]; found {
if auth, ok := ext.(HTTPClientAuthenticator); ok {
if auth, ok := ext.(ClientAuthenticator); ok {
return auth, nil
}
return nil, fmt.Errorf("requested authenticator is not a HTTPClientAuthenticator")
}
return nil, fmt.Errorf("failed to resolve authenticator %q: %w", a.AuthenticatorID, errAuthenticatorNotFound)
}

// GetGRPCClientAuthenticator attempts to select the appropriate GRPCClientAuthenticator from the list of extensions,
// based on the component id of the extension. If an authenticator is not found, an error is returned.
// This should only be used by gRPC clients.
func (a Authentication) GetGRPCClientAuthenticator(extensions map[config.ComponentID]component.Extension) (GRPCClientAuthenticator, error) {
if ext, found := extensions[a.AuthenticatorID]; found {
if auth, ok := ext.(GRPCClientAuthenticator); ok {
return auth, nil
}
return nil, fmt.Errorf("requested authenticator is not a GRPCClientAuthenticator")
return nil, errNotClientAuthenticator
}
return nil, fmt.Errorf("failed to resolve authenticator %q: %w", a.AuthenticatorID, errAuthenticatorNotFound)
}
108 changes: 84 additions & 24 deletions config/configauth/configauth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,43 +23,103 @@ import (
"go.opentelemetry.io/collector/config"
)

func TestGetAuthenticator(t *testing.T) {
// prepare
cfg := &Authentication{
AuthenticatorID: config.NewComponentID("mock"),
func TestGetServerAuthenticator(t *testing.T) {
testCases := []struct {
desc string
authenticator component.Extension
expected error
}{
{
desc: "obtain server authenticator",
authenticator: &MockServerAuthenticator{},
expected: nil,
},
{
desc: "not a server authenticator",
authenticator: &MockClientAuthenticator{},
expected: errNotServerAuthenticator,
},
}
ext := map[config.ComponentID]component.Extension{
config.NewComponentID("mock"): &MockAuthenticator{},
for _, tC := range testCases {
t.Run(tC.desc, func(t *testing.T) {
// prepare
cfg := &Authentication{
AuthenticatorID: config.NewComponentID("mock"),
}
ext := map[config.ComponentID]component.Extension{
config.NewComponentID("mock"): tC.authenticator,
}

authenticator, err := cfg.GetServerAuthenticator(ext)

// verify
if tC.expected != nil {
assert.ErrorIs(t, err, tC.expected)
assert.Nil(t, authenticator)
} else {
assert.NoError(t, err)
assert.NotNil(t, authenticator)
}
})
}
}

authenticator, err := cfg.GetServerAuthenticator(ext)
func TestGetServerAuthenticatorFails(t *testing.T) {
cfg := &Authentication{
AuthenticatorID: config.NewComponentID("does-not-exist"),
}

// verify
assert.NoError(t, err)
assert.NotNil(t, authenticator)
authenticator, err := cfg.GetServerAuthenticator(map[config.ComponentID]component.Extension{})
assert.ErrorIs(t, err, errAuthenticatorNotFound)
assert.Nil(t, authenticator)
}

func TestGetAuthenticatorFails(t *testing.T) {
func TestGetClientAuthenticator(t *testing.T) {
testCases := []struct {
desc string
cfg *Authentication
ext map[config.ComponentID]component.Extension
expected error
desc string
authenticator component.Extension
expected error
}{
{
desc: "ServerAuthenticator not found",
cfg: &Authentication{
AuthenticatorID: config.NewComponentID("does-not-exist"),
},
ext: map[config.ComponentID]component.Extension{},
expected: errAuthenticatorNotFound,
desc: "obtain client authenticator",
authenticator: &MockClientAuthenticator{},
expected: nil,
},
{
desc: "not a client authenticator",
authenticator: &MockServerAuthenticator{},
expected: errNotClientAuthenticator,
},
}
for _, tC := range testCases {
t.Run(tC.desc, func(t *testing.T) {
authenticator, err := tC.cfg.GetServerAuthenticator(tC.ext)
assert.ErrorIs(t, err, tC.expected)
assert.Nil(t, authenticator)
// prepare
cfg := &Authentication{
AuthenticatorID: config.NewComponentID("mock"),
}
ext := map[config.ComponentID]component.Extension{
config.NewComponentID("mock"): tC.authenticator,
}

authenticator, err := cfg.GetClientAuthenticator(ext)

// verify
if tC.expected != nil {
assert.ErrorIs(t, err, tC.expected)
assert.Nil(t, authenticator)
} else {
assert.NoError(t, err)
assert.NotNil(t, authenticator)
}
})
}
}

func TestGetClientAuthenticatorFails(t *testing.T) {
cfg := &Authentication{
AuthenticatorID: config.NewComponentID("does-not-exist"),
}
authenticator, err := cfg.GetClientAuthenticator(map[config.ComponentID]component.Extension{})
assert.ErrorIs(t, err, errAuthenticatorNotFound)
assert.Nil(t, authenticator)
}
5 changes: 2 additions & 3 deletions config/configauth/mock_clientauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,8 @@ import (
)

var (
_ HTTPClientAuthenticator = (*MockClientAuthenticator)(nil)
_ GRPCClientAuthenticator = (*MockClientAuthenticator)(nil)
errMockError = errors.New("mock Error")
_ ClientAuthenticator = (*MockClientAuthenticator)(nil)
errMockError = errors.New("mock Error")
)

// MockClientAuthenticator provides a mock implementation of GRPCClientAuthenticator and HTTPClientAuthenticator interfaces
Expand Down
18 changes: 9 additions & 9 deletions config/configauth/mock_serverauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,41 +23,41 @@ import (
)

var (
_ ServerAuthenticator = (*MockAuthenticator)(nil)
_ component.Extension = (*MockAuthenticator)(nil)
_ ServerAuthenticator = (*MockServerAuthenticator)(nil)
_ component.Extension = (*MockServerAuthenticator)(nil)
)

// MockAuthenticator provides a testing mock for code dealing with authentication.
type MockAuthenticator struct {
// MockServerAuthenticator provides a testing mock for code dealing with authentication.
type MockServerAuthenticator struct {
// AuthenticateFunc to use during the authentication phase of this mock. Optional.
AuthenticateFunc AuthenticateFunc
// TODO: implement the other funcs
}

// Authenticate executes the mock's AuthenticateFunc, if provided, or just returns the given context unchanged.
func (m *MockAuthenticator) Authenticate(ctx context.Context, headers map[string][]string) (context.Context, error) {
func (m *MockServerAuthenticator) Authenticate(ctx context.Context, headers map[string][]string) (context.Context, error) {
if m.AuthenticateFunc == nil {
return context.Background(), nil
}
return m.AuthenticateFunc(ctx, headers)
}

// GRPCUnaryServerInterceptor isn't currently implemented and always returns nil.
func (m *MockAuthenticator) GRPCUnaryServerInterceptor(context.Context, interface{}, *grpc.UnaryServerInfo, grpc.UnaryHandler) (interface{}, error) {
func (m *MockServerAuthenticator) GRPCUnaryServerInterceptor(context.Context, interface{}, *grpc.UnaryServerInfo, grpc.UnaryHandler) (interface{}, error) {
return nil, nil
}

// GRPCStreamServerInterceptor isn't currently implemented and always returns nil.
func (m *MockAuthenticator) GRPCStreamServerInterceptor(interface{}, grpc.ServerStream, *grpc.StreamServerInfo, grpc.StreamHandler) error {
func (m *MockServerAuthenticator) GRPCStreamServerInterceptor(interface{}, grpc.ServerStream, *grpc.StreamServerInfo, grpc.StreamHandler) error {
return nil
}

// Start isn't currently implemented and always returns nil.
func (m *MockAuthenticator) Start(context.Context, component.Host) error {
func (m *MockServerAuthenticator) Start(context.Context, component.Host) error {
return nil
}

// Shutdown isn't currently implemented and always returns nil.
func (m *MockAuthenticator) Shutdown(ctx context.Context) error {
func (m *MockServerAuthenticator) Shutdown(ctx context.Context) error {
return nil
}
4 changes: 2 additions & 2 deletions config/configauth/mock_serverauth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (

func TestAuthenticateFunc(t *testing.T) {
// prepare
m := &MockAuthenticator{}
m := &MockServerAuthenticator{}
called := false
m.AuthenticateFunc = func(c context.Context, m map[string][]string) (context.Context, error) {
called = true
Expand All @@ -41,7 +41,7 @@ func TestAuthenticateFunc(t *testing.T) {

func TestNilOperations(t *testing.T) {
// prepare
m := &MockAuthenticator{}
m := &MockServerAuthenticator{}

// test and verify
origCtx := context.Background()
Expand Down
2 changes: 1 addition & 1 deletion config/configgrpc/configgrpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ func (gcs *GRPCClientSettings) ToDialOptions(host component.Host) ([]grpc.DialOp
return nil, fmt.Errorf("no extensions configuration available")
}

grpcAuthenticator, cerr := gcs.Auth.GetGRPCClientAuthenticator(host.GetExtensions())
grpcAuthenticator, cerr := gcs.Auth.GetClientAuthenticator(host.GetExtensions())
if cerr != nil {
return nil, cerr
}
Expand Down
2 changes: 1 addition & 1 deletion config/configgrpc/configgrpc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ func TestGrpcServerAuthSettings(t *testing.T) {
}
host := &mockHost{
ext: map[config.ComponentID]component.Extension{
config.NewComponentID("mock"): &configauth.MockAuthenticator{},
config.NewComponentID("mock"): &configauth.MockServerAuthenticator{},
},
}
opts, err := gss.ToServerOption(host, componenttest.NewNopTelemetrySettings())
Expand Down
2 changes: 1 addition & 1 deletion config/confighttp/confighttp.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func (hcs *HTTPClientSettings) ToClient(ext map[config.ComponentID]component.Ext
return nil, fmt.Errorf("extensions configuration not found")
}

httpCustomAuthRoundTripper, aerr := hcs.Auth.GetHTTPClientAuthenticator(ext)
httpCustomAuthRoundTripper, aerr := hcs.Auth.GetClientAuthenticator(ext)
if aerr != nil {
return nil, aerr
}
Expand Down