forked from open-telemetry/opentelemetry-collector-contrib
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce an extension called `lumigoauth` that ensures that HTTP requests processed by the associated receivers come in with a `Authentication: LumigoToken <token>` header, and make the value of the token available in the `auth` context for later processing.
- Loading branch information
Michele Mancioppi
committed
Sep 18, 2022
1 parent
e6ec2dc
commit 530b7af
Showing
16 changed files
with
766 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
include ../../Makefile.Common |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
# Lumigo Authenticator | ||
|
||
| Status | | | ||
| ------------------------ |----------------------| | ||
| Stability | [alpha] | | ||
| Supported pipeline types | trace | | ||
| Distributions | [lumigo] | | ||
|
||
This extension implements the `configauth.ServerAuthenticator` interface to require clients to send a Lumigo token with a header with the following structure: | ||
|
||
``` | ||
Authentication: LumigoToken <token> | ||
``` | ||
|
||
If the `Authentication` header is not provided, ot its structure does not match the expected pattern, a `401` is returned. | ||
|
||
The extension does not yet perform validation of the token itself. | ||
|
||
The token is available in the `auth` context with the `auth.lumigo-token` key. | ||
The raw value of the `Authentication` header is available as `auth.raw`. | ||
|
||
## Configuration | ||
|
||
The following configuration includes the setting of the token as an additional resource attribute called `lumigoToken` via the [`resourceprocessor`](../../processor/resourceprocessor/) processor: | ||
|
||
```yaml | ||
extensions: | ||
lumigoauth: {} | ||
|
||
receivers: | ||
otlp: | ||
protocols: | ||
http: | ||
auth: | ||
authenticator: lumigoauth | ||
|
||
processors: | ||
resource/lumigo_token_from_auth: | ||
attributes: | ||
- key: lumigoToken | ||
action: upsert | ||
from_context: auth.lumigo-token | ||
|
||
exporters: | ||
otlp: | ||
|
||
service: | ||
extensions: [lumigoauth] | ||
pipelines: | ||
traces: | ||
receivers: [otlp] | ||
processors: [resource/lumigo_token_from_auth] | ||
exporters: [otlp] | ||
``` | ||
[alpha]:https://github.com/open-telemetry/opentelemetry-collector#alpha | ||
[lumigo]:https://github.com/lumigo-io/opentelemetry-collector-contrib |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// 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 lumigoauthextension // import "github.com/lumigo-io/opentelemetry-collector-contrib/extension/lumigoauthextension" | ||
|
||
import ( | ||
"go.opentelemetry.io/collector/config" | ||
) | ||
|
||
type Config struct { | ||
config.ExtensionSettings `mapstructure:",squash"` | ||
} | ||
|
||
func (cfg *Config) Validate() error { | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// 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 lumigoauthextension | ||
|
||
import ( | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
"go.opentelemetry.io/collector/component/componenttest" | ||
"go.opentelemetry.io/collector/service/servicetest" | ||
) | ||
|
||
func TestLoadConfig(t *testing.T) { | ||
factories, err := componenttest.NopFactories() | ||
require.NoError(t, err) | ||
|
||
factory := NewFactory() | ||
factories.Extensions[typeStr] = factory | ||
_, err = servicetest.LoadConfigAndValidate(filepath.Join("testdata", "valid_config.yml"), factories) | ||
require.NoError(t, err) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
// 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 lumigoauthextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/lumigoauthextension" | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"strings" | ||
|
||
"go.opentelemetry.io/collector/client" | ||
"go.opentelemetry.io/collector/component" | ||
"go.opentelemetry.io/collector/config/configauth" | ||
"go.uber.org/zap" | ||
) | ||
|
||
var ( | ||
errNoAuth = errors.New("the Authorization header is missing") | ||
errInvalidSchemePrefix = errors.New("the Authorization header does not have the 'LumigoToken <token>' structure") | ||
) | ||
|
||
type lumigoAuth struct { | ||
logger *zap.Logger | ||
} | ||
|
||
func newServerAuthExtension(cfg *Config, logger *zap.Logger) (configauth.ServerAuthenticator, error) { | ||
la := lumigoAuth{ | ||
logger: logger, | ||
} | ||
return configauth.NewServerAuthenticator( | ||
configauth.WithStart(la.serverStart), | ||
configauth.WithAuthenticate(la.authenticate), | ||
), nil | ||
} | ||
|
||
func (la *lumigoAuth) serverStart(ctx context.Context, host component.Host) error { | ||
return nil | ||
} | ||
|
||
func (la *lumigoAuth) authenticate(ctx context.Context, headers map[string][]string) (context.Context, error) { | ||
auth := la.getAuthHeader(headers) | ||
if auth == "" { | ||
return ctx, errNoAuth | ||
} | ||
|
||
authData, err := la.parseLumigoToken(auth) | ||
if err != nil { | ||
return ctx, err | ||
} | ||
|
||
cl := client.FromContext(ctx) | ||
cl.Auth = authData | ||
return client.NewContext(ctx, cl), nil | ||
} | ||
|
||
func (la *lumigoAuth) getAuthHeader(h map[string][]string) string { | ||
const ( | ||
canonicalHeaderKey = "Authorization" | ||
metadataKey = "authorization" | ||
) | ||
|
||
authHeaders, ok := h[canonicalHeaderKey] | ||
|
||
if !ok { | ||
authHeaders, ok = h[metadataKey] | ||
} | ||
|
||
if !ok { | ||
for k, v := range h { | ||
if strings.EqualFold(k, metadataKey) { | ||
authHeaders = v | ||
break | ||
} | ||
} | ||
} | ||
|
||
if len(authHeaders) == 0 { | ||
return "" | ||
} | ||
|
||
return authHeaders[0] | ||
} | ||
|
||
func (la *lumigoAuth) parseLumigoToken(auth string) (*authData, error) { | ||
const prefix = "LumigoToken " | ||
if len(auth) < len(prefix) || !strings.EqualFold(auth[:len(prefix)], prefix) { | ||
return nil, errInvalidSchemePrefix | ||
} | ||
|
||
token := auth[len(prefix):] | ||
|
||
return &authData{ | ||
raw: auth, | ||
token: token, | ||
}, nil | ||
} | ||
|
||
var _ client.AuthData = (*authData)(nil) | ||
|
||
type authData struct { | ||
raw string | ||
token string | ||
} | ||
|
||
func (a *authData) GetAttribute(name string) interface{} { | ||
switch name { | ||
case "lumigo-token": | ||
return a.token | ||
case "raw": | ||
return a.raw | ||
default: | ||
return nil | ||
} | ||
} | ||
|
||
func (*authData) GetAttributeNames() []string { | ||
return []string{"raw", "lumigo-token"} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// 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. | ||
|
||
// nolint:errcheck | ||
package lumigoauthextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/basicauthextension" | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
"go.opentelemetry.io/collector/component/componenttest" | ||
) | ||
|
||
func TestLumigoAuth_NoHeader(t *testing.T) { | ||
ext, err := newServerAuthExtension(&Config{}) | ||
require.NoError(t, err) | ||
_, err = ext.Authenticate(context.Background(), map[string][]string{}) | ||
assert.Equal(t, errNoAuth, err) | ||
} | ||
|
||
func TestLumigoAuth_InvalidPrefix(t *testing.T) { | ||
ext, err := newServerAuthExtension(&Config{}) | ||
require.NoError(t, err) | ||
_, err = ext.Authenticate(context.Background(), map[string][]string{"authorization": {"Bearer token"}}) | ||
assert.Equal(t, errInvalidSchemePrefix, err) | ||
} | ||
|
||
func TestLumigoAuth_SupportedHeaders(t *testing.T) { | ||
ext, err := newServerAuthExtension(&Config{}) | ||
require.NoError(t, err) | ||
require.NoError(t, ext.Start(context.Background(), componenttest.NewNopHost())) | ||
|
||
for _, k := range []string{ | ||
"Authorization", | ||
"authorization", | ||
"aUtHoRiZaTiOn", | ||
} { | ||
_, err = ext.Authenticate(context.Background(), map[string][]string{k: {"LumigoToken 1234567"}}) | ||
assert.NoError(t, err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// 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 lumigoauthextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/lumigoauthextension" | ||
|
||
import ( | ||
"context" | ||
|
||
"go.opentelemetry.io/collector/component" | ||
"go.opentelemetry.io/collector/config" | ||
) | ||
|
||
const ( | ||
typeStr = "lumigoauth" | ||
) | ||
|
||
// NewFactory creates a factory for the static bearer token Authenticator extension. | ||
func NewFactory() component.ExtensionFactory { | ||
return component.NewExtensionFactory( | ||
typeStr, | ||
createDefaultConfig, | ||
createExtension) | ||
} | ||
|
||
func createDefaultConfig() config.Extension { | ||
return &Config{ | ||
ExtensionSettings: config.NewExtensionSettings(config.NewComponentID(typeStr)), | ||
} | ||
} | ||
|
||
func createExtension(_ context.Context, set component.ExtensionCreateSettings, cfg config.Extension) (component.Extension, error) { | ||
// check if config is a server auth(Htpasswd should be set) | ||
return newServerAuthExtension(cfg.(*Config), set.Logger) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// 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 lumigoauthextension // import "github.com/open-telemetry/opentelemetry-collector-contrib/extension/basicauthextension" | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"go.opentelemetry.io/collector/config" | ||
"go.opentelemetry.io/collector/config/configtest" | ||
) | ||
|
||
func TestCreateDefaultConfig(t *testing.T) { | ||
expected := &Config{ | ||
ExtensionSettings: config.NewExtensionSettings(config.NewComponentID(typeStr)), | ||
} | ||
actual := createDefaultConfig() | ||
assert.Equal(t, expected, createDefaultConfig()) | ||
assert.NoError(t, configtest.CheckConfigStruct(actual)) | ||
} |
Oops, something went wrong.