Skip to content

Commit

Permalink
Added support for authentication processor
Browse files Browse the repository at this point in the history
Includes an initial support for OIDC authenticator.

Closes open-telemetry#1424

Signed-off-by: Juraci Paixão Kröhling <[email protected]>
  • Loading branch information
jpkrohling committed Sep 3, 2020
1 parent 95389af commit 94c5345
Show file tree
Hide file tree
Showing 18 changed files with 1,594 additions and 3 deletions.
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/cenkalti/backoff v2.2.1+incompatible
github.com/census-instrumentation/opencensus-proto v0.3.0
github.com/client9/misspell v0.3.4
github.com/coreos/go-oidc v2.2.1+incompatible
github.com/davecgh/go-spew v1.1.1
github.com/evanphx/json-patch v4.5.0+incompatible // indirect
github.com/go-kit/kit v0.10.0
Expand All @@ -34,6 +35,7 @@ require (
github.com/orijtech/prometheus-go-metrics-exporter v0.0.5
github.com/ory/go-acc v0.2.6
github.com/pavius/impi v0.0.3
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
github.com/prometheus/client_golang v1.7.1
github.com/prometheus/common v0.11.1
github.com/prometheus/prometheus v1.8.2-0.20200626085723-c448ada63d83
Expand All @@ -60,6 +62,7 @@ require (
google.golang.org/grpc v1.31.0
google.golang.org/grpc/examples v0.0.0-20200728065043-dfc0c05b2da9 // indirect
google.golang.org/protobuf v1.25.0
gopkg.in/square/go-jose.v2 v2.5.1 // indirect
gopkg.in/yaml.v2 v2.3.0
honnef.co/go/tools v0.0.1-2020.1.5
)
121 changes: 118 additions & 3 deletions go.sum

Large diffs are not rendered by default.

23 changes: 23 additions & 0 deletions processor/authenticationprocessor/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Authentication Processor

* Supported pipeline types: traces
* Status: in development

This processor authenticates the incoming traces by extracting the authentication data from the context
and verifying the bearer token with the specified provider.

Currently, only bearer token authentication is supported, added as part of `PerRPC` gRPC authentication.
It requires the gRPC client to send a header named `authorization` in line with the equivalent HTTP/2 header.

Examples:
```yaml
processors:
authentication:
oidc:
issuer_url: https://auth.example.com/
issuer_ca_path: /etc/pki/tls/cert.pem
client_id: my-oidc-client
username_claim: email
```
Refer to [config.yaml](./testdata/config.yaml) for detailed examples on using the processor.
27 changes: 27 additions & 0 deletions processor/authenticationprocessor/authenticator.go
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 authenticationprocessor

import (
"context"

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

type authenticator interface {
authenticate(context.Context) (bool, error)
start(context.Context, component.Host) error
shutdown(context.Context) error
}
52 changes: 52 additions & 0 deletions processor/authenticationprocessor/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// 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 authenticationprocessor

import (
"go.opentelemetry.io/collector/config/configmodels"
)

// Config is the configuration for the processor.
type Config struct {
configmodels.ProcessorSettings `mapstructure:",squash"`

// OIDC configures this processor to use the given OIDC provider as the backend for the authentication mechanism.
// Required.
OIDC *OIDC `mapstructure:"oidc"`
}

// OIDC defines the OpenID Connect properties for this processor
type OIDC struct {
// IssuerURL is the base URL for the OIDC provider.
// Required.
IssuerURL string `mapstructure:"issuer_url"`

// Audience of the token, used during the verification.
// For example: "https://accounts.google.com" or "https://login.salesforce.com".
// Required.
Audience string `mapstructure:"audience"`

// The local path for the issuer CA's TLS server cert.
// Optional.
IssuerCAPath string `mapstructure:"issuer_ca_path"`

// The claim to use as the username, in case the token's 'sub' isn't the suitable source.
// Optional.
UsernameClaim string `mapstructure:"username_claim"`

// The claim that holds the subject's group membership information.
// Optional.
GroupsClaim string `mapstructure:"groups_claim"`
}
15 changes: 15 additions & 0 deletions processor/authenticationprocessor/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// 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 authenticationprocessor
87 changes: 87 additions & 0 deletions processor/authenticationprocessor/factory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// 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 authenticationprocessor

import (
"context"
"errors"

"go.opentelemetry.io/collector/component"
"go.opentelemetry.io/collector/config/configerror"
"go.opentelemetry.io/collector/config/configmodels"
"go.opentelemetry.io/collector/consumer"
)

const (
// typeStr is the value of "type" for this processor in the configuration.
typeStr configmodels.Type = "authentication"
)

var (
errNoOIDCProvided = errors.New("no OIDC information provided")
errNoClientIDProvided = errors.New("no ClientID provided for the OIDC configuration")
errNoIssuerURL = errors.New("no IssuerURL provided for the OIDC configuration")
)

// Factory is the factory for the processor.
type Factory struct {
}

var _ component.ProcessorFactory = (*Factory)(nil)

// Type gets the type of the config created by this factory.
func (f *Factory) Type() configmodels.Type {
return typeStr
}

// CreateDefaultConfig creates the default configuration for the processor.
func (f *Factory) CreateDefaultConfig() configmodels.Processor {
return &Config{
ProcessorSettings: configmodels.ProcessorSettings{
TypeVal: typeStr,
NameVal: string(typeStr),
},
}
}

// CreateTraceProcessor creates a trace processor based on this config.
func (f *Factory) CreateTraceProcessor(
_ context.Context,
params component.ProcessorCreateParams,
nextConsumer consumer.TraceConsumer,
cfg configmodels.Processor) (component.TraceProcessor, error) {

oCfg := cfg.(*Config)
if oCfg.OIDC == nil {
return nil, errNoOIDCProvided
}
if oCfg.OIDC.Audience == "" {
return nil, errNoClientIDProvided
}
if oCfg.OIDC.IssuerURL == "" {
return nil, errNoIssuerURL
}

return newAuthenticationProcessor(params.Logger, nextConsumer, *oCfg)
}

// CreateMetricsProcessor creates a metric processor based on this config.
func (f *Factory) CreateMetricsProcessor(
context.Context,
component.ProcessorCreateParams,
consumer.MetricsConsumer,
configmodels.Processor) (component.MetricsProcessor, error) {
return nil, configerror.ErrDataTypeIsNotSupported
}
126 changes: 126 additions & 0 deletions processor/authenticationprocessor/factory_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// 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 authenticationprocessor

import (
"context"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap"

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

func TestDefaultConfiguration(t *testing.T) {
// prepare
f := &Factory{}

// test
_ = f.CreateDefaultConfig().(*Config)
}

func TestCreateTestProcessor(t *testing.T) {
// prepare
logger, err := zap.NewDevelopment()
require.NoError(t, err)

f := &Factory{}
c := f.CreateDefaultConfig().(*Config)

c.OIDC = &OIDC{
Audience: "unit-tests",
IssuerURL: "http://example.com/",
}
params := component.ProcessorCreateParams{Logger: logger}

// test
p, err := f.CreateTraceProcessor(context.Background(), params, &mockProcessor{}, c)

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

func TestMissingOIDCParameters(t *testing.T) {
for _, tt := range []struct {
casename string
config *Config
expectedErr error
}{
{
"no-oidc",
(&Factory{}).CreateDefaultConfig().(*Config),
errNoOIDCProvided,
},
{
"no-client-id",
&Config{
OIDC: &OIDC{
IssuerURL: "http://example.com/",
},
},
errNoClientIDProvided,
},
{
"no-issuer-url",
&Config{
OIDC: &OIDC{
Audience: "unit-tests",
},
},
errNoIssuerURL,
},
} {
t.Run(tt.casename, func(t *testing.T) {
// prepare
f := &Factory{}
params := component.ProcessorCreateParams{}

// test
p, err := f.CreateTraceProcessor(context.Background(), params, nil, tt.config)

// verify
assert.Equal(t, err, tt.expectedErr)
assert.Nil(t, p)
})
}
}

func TestType(t *testing.T) {
// prepare
f := &Factory{}

// test
typ := f.Type()

// verify
assert.Equal(t, typeStr, typ)
}

func TestNoMetricsProcessor(t *testing.T) {
// prepare
f := &Factory{}
params := component.ProcessorCreateParams{}

// test
p, err := f.CreateMetricsProcessor(context.Background(), params, nil, nil)

// verify
assert.Equal(t, err, configerror.ErrDataTypeIsNotSupported)
assert.Nil(t, p)
}
Loading

0 comments on commit 94c5345

Please sign in to comment.