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

Support for Custom Exporter Authenticators as Extensions #3128

Merged
merged 65 commits into from
May 20, 2021
Merged
Show file tree
Hide file tree
Changes from 60 commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
3a541b5
Added support for client auth via extensions
pavankrish123 May 7, 2021
604f0e8
clean up
pavankrish123 May 7, 2021
77dbf97
used proper name for authentication
pavankrish123 May 7, 2021
0eacfd4
added proper example
pavankrish123 May 7, 2021
e38a6bc
added search for grpc auth
pavankrish123 May 7, 2021
2d31e3e
clean up
pavankrish123 May 8, 2021
457cdfc
added tests
pavankrish123 May 9, 2021
e878999
fixed typo in doc string
pavankrish123 May 10, 2021
c9ec98d
fixed readme.md
pavankrish123 May 10, 2021
0baa79c
updated PR per comments + added test cases
pavankrish123 May 12, 2021
cc179ca
fixed tests
pavankrish123 May 12, 2021
cf87bbc
fixed go.mod
pavankrish123 May 12, 2021
54a67fe
Merge branch 'master' into client_auth_ext
pavankrish123 May 12, 2021
eff20d5
fixed imports order
pavankrish123 May 12, 2021
9f761cd
modified per latest changes to component apis
pavankrish123 May 12, 2021
930bcf0
clean up
pavankrish123 May 12, 2021
5392bb0
clean up
pavankrish123 May 12, 2021
4a4e580
clean up
pavankrish123 May 12, 2021
343eca9
clean up
pavankrish123 May 12, 2021
8bb7cfc
clean up
pavankrish123 May 12, 2021
1a7e06d
clean up
pavankrish123 May 12, 2021
7654e1c
clean up
pavankrish123 May 12, 2021
731bd19
clean up
pavankrish123 May 12, 2021
972c131
clean up
pavankrish123 May 12, 2021
54db711
1) Removed OAuth client Authenticator to make PR more manageble 2) Ad…
pavankrish123 May 12, 2021
d872d98
fixed import orders
pavankrish123 May 13, 2021
94fa96c
added more verbose description in README
pavankrish123 May 13, 2021
e86d364
Merge branch 'master' into client_auth_ext
pavankrish123 May 13, 2021
8cf8db0
Merge branch 'master' into client_auth_ext
pavankrish123 May 13, 2021
abcc69d
Fixed merge conflicts per latest commit
pavankrish123 May 13, 2021
1356d06
Made following changes per review comments 1) Renamed the Server Auth…
pavankrish123 May 14, 2021
112a3ac
Merge branch 'master' into client_auth_ext
pavankrish123 May 14, 2021
07292d6
fixed per new main changes
pavankrish123 May 14, 2021
3d129dd
fixed errors from goimpi
pavankrish123 May 14, 2021
344d529
fixed comments per suggestions
pavankrish123 May 14, 2021
6315ae8
fixed test case
pavankrish123 May 14, 2021
e1651df
fixed linting
pavankrish123 May 14, 2021
46cb4db
refactored zipkin
pavankrish123 May 14, 2021
73fdba1
refactored prometheusremotewriteexporter
pavankrish123 May 14, 2021
eea54aa
cleanup
pavankrish123 May 14, 2021
01bf264
refactored opencensus exporter
pavankrish123 May 14, 2021
02eb834
moved clients creations to start of exporters
pavankrish123 May 15, 2021
fbbc1a9
cleanup jaeger exporter
pavankrish123 May 15, 2021
72fec3a
cleanup jaeger exporter
pavankrish123 May 15, 2021
d07af8e
cleanup README
pavankrish123 May 15, 2021
2c8a74b
added complete example for bearertoken auth
pavankrish123 May 17, 2021
48efcbf
Merge branch 'master' into client_auth_ext
pavankrish123 May 17, 2021
6d2f927
removed needless refactorings
pavankrish123 May 17, 2021
94c42de
fixed trace receiver
pavankrish123 May 17, 2021
b4a0c1d
Merge branch 'master' into client_auth_ext
pavankrish123 May 17, 2021
d01dacb
Merge branch 'master' into client_auth_ext
pavankrish123 May 18, 2021
7e65d43
use prper NumConsumers
pavankrish123 May 18, 2021
cc79a97
Fixed liniting
pavankrish123 May 18, 2021
ce39a35
Fixed comments
pavankrish123 May 18, 2021
33c181d
fixed readme
pavankrish123 May 18, 2021
4bd909d
fixed per review comments
pavankrish123 May 18, 2021
23c9b26
removed needless condition
pavankrish123 May 18, 2021
98c258e
fxied tests
pavankrish123 May 18, 2021
7ff009c
fixed lint issues
pavankrish123 May 18, 2021
9ff5660
Fixed module name bearertokenauth -> bearertokenauthextension
pavankrish123 May 19, 2021
b6dff65
fixed import
pavankrish123 May 19, 2021
c24b316
Merge branch 'master' into client_auth_ext
pavankrish123 May 19, 2021
fcc50f3
Fixed tests
pavankrish123 May 19, 2021
40079fd
fixed tests
pavankrish123 May 19, 2021
d8cb3eb
Merge branch 'master' into client_auth_ext
pavankrish123 May 20, 2021
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
78 changes: 78 additions & 0 deletions config/configauth/clientauth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// 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 (
"fmt"
"net/http"

"google.golang.org/grpc/credentials"

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

// ClientAuthenticator is an Extension that can be used as an authenticator for the configauth.Authentication option.
// Authenticators are then included as part of OpenTelemetry Collector builds and can be referenced by their
// 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(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() (credentials.PerRPCCredentials, error)
}

// GetHTTPClientAuthenticator attempts to select the appropriate HTTPClientAuthenticator 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 GetHTTPClientAuthenticator(extensions map[config.ComponentID]component.Extension,
componentID config.ComponentID) (HTTPClientAuthenticator, error) {
for name, ext := range extensions {
if name == componentID {
if auth, ok := ext.(HTTPClientAuthenticator); ok {
return auth, nil
}
return nil, fmt.Errorf("requested authenticator is not for HTTP clients")
}
}
return nil, fmt.Errorf("failed to resolve authenticator %q: %w", componentID.String(), 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 GetGRPCClientAuthenticator(extensions map[config.ComponentID]component.Extension,
componentID config.ComponentID) (GRPCClientAuthenticator, error) {
for name, ext := range extensions {
if name == componentID {
if auth, ok := ext.(GRPCClientAuthenticator); ok {
return auth, nil
}
return nil, fmt.Errorf("requested authenticator is not for gRPC clients")
}
}
return nil, fmt.Errorf("failed to resolve authenticator %q: %w", componentID.String(), errAuthenticatorNotFound)
}
24 changes: 7 additions & 17 deletions config/configauth/configauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,35 +23,25 @@ import (
)

var (
errAuthenticatorNotFound = errors.New("authenticator not found")
errAuthenticatorNotProvided = errors.New("authenticator not provided")
errAuthenticatorNotFound = errors.New("authenticator not found")
)

// Authentication defines the auth settings for the receiver
type Authentication struct {
// Authenticator specifies the name of the extension to use in order to authenticate the incoming data point.
// AuthenticatorName specifies the name of the extension to use in order to authenticate the incoming data point.
AuthenticatorName string `mapstructure:"authenticator"`
}

// GetAuthenticator attempts to select the appropriate from the list of extensions, based on the requested extension name.
// GetServerAuthenticator attempts to select the appropriate from the list of extensions, based on the requested extension name.
// If an authenticator is not found, an error is returned.
func GetAuthenticator(extensions map[config.ComponentID]component.Extension, requested string) (Authenticator, error) {
if requested == "" {
return nil, errAuthenticatorNotProvided
}

reqID, err := config.NewIDFromString(requested)
if err != nil {
return nil, err
}

func GetServerAuthenticator(extensions map[config.ComponentID]component.Extension, componentID config.ComponentID) (ServerAuthenticator, error) {
for name, ext := range extensions {
if auth, ok := ext.(Authenticator); ok {
if name == reqID {
if auth, ok := ext.(ServerAuthenticator); ok {
if name == componentID {
return auth, nil
}
}
}

return nil, fmt.Errorf("failed to resolve authenticator %q: %w", requested, errAuthenticatorNotFound)
return nil, fmt.Errorf("failed to resolve authenticator %q: %w", componentID.String(), errAuthenticatorNotFound)
}
17 changes: 8 additions & 9 deletions config/configauth/configauth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ func TestGetAuthenticator(t *testing.T) {
}

// test
authenticator, err := GetAuthenticator(ext, cfg.AuthenticatorName)
componentID, err := config.NewIDFromString(cfg.AuthenticatorName)
assert.NoError(t, err)

authenticator, err := GetServerAuthenticator(ext, componentID)

// verify
assert.NoError(t, err)
Expand All @@ -48,13 +51,7 @@ func TestGetAuthenticatorFails(t *testing.T) {
expected error
}{
{
desc: "Authenticator not provided",
cfg: &Authentication{},
ext: map[config.ComponentID]component.Extension{},
expected: errAuthenticatorNotProvided,
},
{
desc: "Authenticator not found",
desc: "ServerAuthenticator not found",
cfg: &Authentication{
AuthenticatorName: "does-not-exist",
},
Expand All @@ -64,7 +61,9 @@ func TestGetAuthenticatorFails(t *testing.T) {
}
for _, tC := range testCases {
t.Run(tC.desc, func(t *testing.T) {
authenticator, err := GetAuthenticator(tC.ext, tC.cfg.AuthenticatorName)
componentID, err := config.NewIDFromString(tC.cfg.AuthenticatorName)
assert.NoError(t, err)
authenticator, err := GetServerAuthenticator(tC.ext, componentID)
assert.ErrorIs(t, err, tC.expected)
assert.Nil(t, authenticator)
})
Expand Down
66 changes: 66 additions & 0 deletions config/configauth/mock_clientauth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// 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"
"errors"
"net/http"

"google.golang.org/grpc/credentials"

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

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

// MockClientAuthenticator provides a mock implementation of GRPCClientAuthenticator and HTTPClientAuthenticator interfaces
type MockClientAuthenticator struct {
ResultRoundTripper http.RoundTripper
ResultPerRPCCredentials credentials.PerRPCCredentials
MustError bool
}

// Start for the MockClientAuthenticator does nothing
func (m *MockClientAuthenticator) Start(ctx context.Context, host component.Host) error {
return nil
}

// Shutdown for the MockClientAuthenticator does nothing
func (m *MockClientAuthenticator) Shutdown(ctx context.Context) error {
return nil
}

// RoundTripper for the MockClientAuthenticator either returns error if the mock authenticator is forced to or
// returns the supplied resultRoundTripper.
func (m *MockClientAuthenticator) RoundTripper(base http.RoundTripper) (http.RoundTripper, error) {
if m.MustError {
return nil, errMockError
}
return m.ResultRoundTripper, nil
}

// PerRPCCredentials for the MockClientAuthenticator either returns error if the mock authenticator is forced to or
// returns the supplied resultPerRPCCredentials.
func (m *MockClientAuthenticator) PerRPCCredentials() (credentials.PerRPCCredentials, error) {
if m.MustError {
return nil, errMockError
}
return m.ResultPerRPCCredentials, nil
}
139 changes: 139 additions & 0 deletions config/configauth/mock_clientauth_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// 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"
)

func TestNilStartAndShutdown(t *testing.T) {
// prepare
m := &MockClientAuthenticator{}

// test and verify
origCtx := context.Background()

err := m.Start(origCtx, nil)
assert.NoError(t, err)

err = m.Shutdown(origCtx)
assert.NoError(t, err)
}

type customRoundTripper struct{}

func (c *customRoundTripper) RoundTrip(request *http.Request) (*http.Response, error) {
return nil, nil
}

func TestMockRoundTripper(t *testing.T) {
testcases := []struct {
name string
expectedErr bool
clientAuth MockClientAuthenticator
}{
{
name: "no_error",
expectedErr: false,
clientAuth: MockClientAuthenticator{
ResultRoundTripper: &customRoundTripper{},
MustError: false,
},
},
{
name: "error",
expectedErr: true,
clientAuth: MockClientAuthenticator{
ResultRoundTripper: &customRoundTripper{},
MustError: true,
},
},
}

for _, testcase := range testcases {
t.Run(testcase.name, func(t *testing.T) {
tripper, err := testcase.clientAuth.RoundTripper(nil)
if testcase.expectedErr {
assert.Error(t, err)
return
}
assert.NotNil(t, tripper)
assert.NoError(t, err)
// check if the resultant tripper is indeed the one provided
_, ok := tripper.(*customRoundTripper)
assert.True(t, ok)
})
}
}

type customPerRPCCredentials struct{}

var _ credentials.PerRPCCredentials = (*customPerRPCCredentials)(nil)

func (c *customPerRPCCredentials) GetRequestMetadata(context.Context, ...string) (map[string]string, error) {
return nil, nil
}

func (c *customPerRPCCredentials) RequireTransportSecurity() bool {
return true
}

func TestMockPerRPCCredential(t *testing.T) {
testcases := []struct {
name string
expectedErr bool
clientAuth MockClientAuthenticator
}{
{
name: "no_error",
expectedErr: false,
clientAuth: MockClientAuthenticator{
ResultPerRPCCredentials: &customPerRPCCredentials{},
MustError: false,
},
},
{
name: "error",
expectedErr: true,
clientAuth: MockClientAuthenticator{
ResultPerRPCCredentials: &customPerRPCCredentials{},
MustError: true,
},
},
}

for _, testcase := range testcases {
t.Run(testcase.name, func(t *testing.T) {
credential, err := testcase.clientAuth.PerRPCCredentials()
if err != nil {
return
}
if testcase.expectedErr {
assert.Error(t, err)
return
}
assert.NotNil(t, credential)
assert.NoError(t, err)
// check if the resultant tripper is indeed the one provided
_, ok := credential.(*customPerRPCCredentials)
assert.True(t, ok)
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
)

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

Expand Down
Loading