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

Implement default client authenticators #4837

Merged
merged 5 commits into from
Mar 11, 2022
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
### 💡 Enhancements 💡

- Add validation to check at least one endpoint is specified in otlphttpexporter's configuration (#4860)
- Implement default client authenticators (#4837)

## 🧰 Bug fixes 🧰

Expand Down
104 changes: 104 additions & 0 deletions config/configauth/default_clientauthenticator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package configauth // import "go.opentelemetry.io/collector/config/configauth"

import (
"context"
"net/http"

"google.golang.org/grpc/credentials"

"go.opentelemetry.io/collector/component"
)

var _ ClientAuthenticator = (*defaultClientAuthenticator)(nil)

// Option represents the possible options for NewServerAuthenticator.
type ClientOption func(*defaultClientAuthenticator)

type defaultClientAuthenticator struct {
component.StartFunc
component.ShutdownFunc
roundTripperFunc func(base http.RoundTripper) (http.RoundTripper, error)
perRPCCredentialsFunc func() (credentials.PerRPCCredentials, error)
}

// WithClientStart overrides the default `Start` function for a component.Component.
// The default always returns nil.
func WithClientStart(startFunc component.StartFunc) ClientOption {
return func(o *defaultClientAuthenticator) {
o.StartFunc = startFunc
}
}

// WithClientShutdown overrides the default `Shutdown` function for a component.Component.
// The default always returns nil.
func WithClientShutdown(shutdownFunc component.ShutdownFunc) ClientOption {
return func(o *defaultClientAuthenticator) {
o.ShutdownFunc = shutdownFunc
}
}

// WithClientRoundTripper provides a `RoundTripper` function for this client authenticator.
// The default round tripper is no-op.
func WithClientRoundTripper(roundTripperFunc func(base http.RoundTripper) (http.RoundTripper, error)) ClientOption {
return func(o *defaultClientAuthenticator) {
o.roundTripperFunc = roundTripperFunc
}
}

// WithPerRPCCredentials provides a `PerRPCCredentials` function for this client authenticator.
// There's no default.
func WithPerRPCCredentials(perRPCCredentialsFunc func() (credentials.PerRPCCredentials, error)) ClientOption {
return func(o *defaultClientAuthenticator) {
o.perRPCCredentialsFunc = perRPCCredentialsFunc
}
}

// NewClientAuthenticator returns a ClientAuthenticator configured with the provided options.
func NewClientAuthenticator(options ...ClientOption) ClientAuthenticator {
bc := &defaultClientAuthenticator{
StartFunc: func(ctx context.Context, host component.Host) error { return nil },
ShutdownFunc: func(ctx context.Context) error { return nil },
roundTripperFunc: func(base http.RoundTripper) (http.RoundTripper, error) { return base, nil },
perRPCCredentialsFunc: func() (credentials.PerRPCCredentials, error) { return nil, nil },
}

for _, op := range options {
op(bc)
}

return bc
}

// Start the component.
func (a *defaultClientAuthenticator) Start(ctx context.Context, host component.Host) error {
return a.StartFunc(ctx, host)
}

// Shutdown stops the component.
func (a *defaultClientAuthenticator) Shutdown(ctx context.Context) error {
return a.ShutdownFunc(ctx)
}

// RoundTripper adds the base HTTP RoundTripper in this authenticator's round tripper.
func (a *defaultClientAuthenticator) RoundTripper(base http.RoundTripper) (http.RoundTripper, error) {
return a.roundTripperFunc(base)
}

// PerRPCCredentials returns this authenticator's credentials.PerRPCCredentials implementation.
func (a *defaultClientAuthenticator) PerRPCCredentials() (credentials.PerRPCCredentials, error) {
return a.perRPCCredentialsFunc()
}
118 changes: 118 additions & 0 deletions config/configauth/default_clientauthenticator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package configauth

import (
"context"
"net/http"
"testing"

"github.com/stretchr/testify/assert"
"google.golang.org/grpc/credentials"

"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/component/componenttest"
)

func TestClientDefaultValues(t *testing.T) {
// prepare
e := NewClientAuthenticator()

// test
t.Run("start", func(t *testing.T) {
err := e.Start(context.Background(), componenttest.NewNopHost())
assert.NoError(t, err)
})

t.Run("roundtripper", func(t *testing.T) {
ctx, err := e.RoundTripper(http.DefaultTransport)
assert.NotNil(t, ctx)
assert.NoError(t, err)
})

t.Run("per-rpc-credentials", func(t *testing.T) {
p, err := e.PerRPCCredentials()
assert.Nil(t, p)
assert.NoError(t, err)
})

t.Run("shutdown", func(t *testing.T) {
err := e.Shutdown(context.Background())
assert.NoError(t, err)
})
}

func TestWithClientStart(t *testing.T) {
called := false
e := NewClientAuthenticator(WithClientStart(func(c context.Context, h component.Host) error {
called = true
return nil
}))

// test
err := e.Start(context.Background(), componenttest.NewNopHost())

// verify
assert.True(t, called)
assert.NoError(t, err)
}

func TestWithClientShutdown(t *testing.T) {
called := false
e := NewClientAuthenticator(WithClientShutdown(func(c context.Context) error {
called = true
return nil
}))

// test
err := e.Shutdown(context.Background())

// verify
assert.True(t, called)
assert.NoError(t, err)
}

func TestWithClientRoundTripper(t *testing.T) {
called := false
e := NewClientAuthenticator(WithClientRoundTripper(func(base http.RoundTripper) (http.RoundTripper, error) {
called = true
return base, nil
}))

// test
rt, err := e.RoundTripper(http.DefaultTransport)

// verify
assert.True(t, called)
assert.NotNil(t, rt)
assert.NoError(t, err)
}

func TestWithPerRPCCredentials(t *testing.T) {
called := false
e := NewClientAuthenticator(WithPerRPCCredentials(func() (credentials.PerRPCCredentials, error) {
called = true
return &customPerRPCCredentials{}, nil
}))

// test
p, err := e.PerRPCCredentials()

// verify
assert.True(t, called)
assert.NotNil(t, p)
assert.NoError(t, err)

}