mirror of
https://github.com/oauth2-proxy/oauth2-proxy.git
synced 2025-06-06 23:46:28 +02:00
Add header Injector
This commit is contained in:
parent
d9ed1e7d45
commit
ca5fd3c39f
26
pkg/apis/options/util/util.go
Normal file
26
pkg/apis/options/util/util.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetSecretValue returns the value of the Secret from its source
|
||||||
|
func GetSecretValue(source *options.SecretSource) ([]byte, error) {
|
||||||
|
switch {
|
||||||
|
case len(source.Value) > 0 && source.FromEnv == "" && source.FromFile == "":
|
||||||
|
value := make([]byte, base64.StdEncoding.DecodedLen(len(source.Value)))
|
||||||
|
decoded, err := base64.StdEncoding.Decode(value, source.Value)
|
||||||
|
return value[:decoded], err
|
||||||
|
case len(source.Value) == 0 && source.FromEnv != "" && source.FromFile == "":
|
||||||
|
return []byte(os.Getenv(source.FromEnv)), nil
|
||||||
|
case len(source.Value) == 0 && source.FromEnv == "" && source.FromFile != "":
|
||||||
|
return ioutil.ReadFile(source.FromFile)
|
||||||
|
default:
|
||||||
|
return nil, errors.New("secret source is invalid: exactly one entry required, specify either value, fromEnv or fromFile")
|
||||||
|
}
|
||||||
|
}
|
16
pkg/apis/options/util/util_suite_test.go
Normal file
16
pkg/apis/options/util/util_suite_test.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUtilSuite(t *testing.T) {
|
||||||
|
logger.SetOutput(GinkgoWriter)
|
||||||
|
|
||||||
|
RegisterFailHandler(Fail)
|
||||||
|
RunSpecs(t, "Options Util Suite")
|
||||||
|
}
|
88
pkg/apis/options/util/util_test.go
Normal file
88
pkg/apis/options/util/util_test.go
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
|
||||||
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("GetSecretValue", func() {
|
||||||
|
var fileDir string
|
||||||
|
const secretEnvKey = "SECRET_ENV_KEY"
|
||||||
|
const secretEnvValue = "secret-env-value"
|
||||||
|
var secretFileValue = []byte("secret-file-value")
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
os.Setenv(secretEnvKey, secretEnvValue)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
fileDir, err = ioutil.TempDir("", "oauth2-proxy-util-get-secret-value")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(ioutil.WriteFile(path.Join(fileDir, "secret-file"), secretFileValue, 0600)).To(Succeed())
|
||||||
|
})
|
||||||
|
|
||||||
|
AfterEach(func() {
|
||||||
|
os.Unsetenv(secretEnvKey)
|
||||||
|
os.RemoveAll(fileDir)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns the correct value from base64", func() {
|
||||||
|
originalValue := []byte("secret-value-1")
|
||||||
|
b64Value := base64.StdEncoding.EncodeToString((originalValue))
|
||||||
|
|
||||||
|
// Once encoded, the originalValue could have a decoded length longer than
|
||||||
|
// its actual length, ensure we trim this.
|
||||||
|
// This assertion ensures we are testing the triming
|
||||||
|
Expect(len(originalValue)).To(BeNumerically("<", base64.StdEncoding.DecodedLen(len(b64Value))))
|
||||||
|
|
||||||
|
value, err := GetSecretValue(&options.SecretSource{
|
||||||
|
Value: []byte(b64Value),
|
||||||
|
})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(value).To(Equal(originalValue))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns the correct value from the environment", func() {
|
||||||
|
value, err := GetSecretValue(&options.SecretSource{
|
||||||
|
FromEnv: secretEnvKey,
|
||||||
|
})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(value).To(BeEquivalentTo(secretEnvValue))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("returns the correct value from a file", func() {
|
||||||
|
value, err := GetSecretValue(&options.SecretSource{
|
||||||
|
FromFile: path.Join(fileDir, "secret-file"),
|
||||||
|
})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(value).To(Equal(secretFileValue))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("when the file does not exist", func() {
|
||||||
|
value, err := GetSecretValue(&options.SecretSource{
|
||||||
|
FromFile: path.Join(fileDir, "not-exist"),
|
||||||
|
})
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(value).To(BeEmpty())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("with no source set", func() {
|
||||||
|
value, err := GetSecretValue(&options.SecretSource{})
|
||||||
|
Expect(err).To(MatchError("secret source is invalid: exactly one entry required, specify either value, fromEnv or fromFile"))
|
||||||
|
Expect(value).To(BeEmpty())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("with multiple sources set", func() {
|
||||||
|
value, err := GetSecretValue(&options.SecretSource{
|
||||||
|
FromEnv: secretEnvKey,
|
||||||
|
FromFile: path.Join(fileDir, "secret-file"),
|
||||||
|
})
|
||||||
|
Expect(err).To(MatchError("secret source is invalid: exactly one entry required, specify either value, fromEnv or fromFile"))
|
||||||
|
Expect(value).To(BeEmpty())
|
||||||
|
})
|
||||||
|
})
|
@ -8,6 +8,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
@ -69,6 +70,34 @@ func (s *SessionState) String() string {
|
|||||||
return o + "}"
|
return o + "}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SessionState) GetClaim(claim string) string {
|
||||||
|
if s == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
switch claim {
|
||||||
|
case "access_token":
|
||||||
|
return s.AccessToken
|
||||||
|
case "id_token":
|
||||||
|
return s.IDToken
|
||||||
|
case "created_at":
|
||||||
|
return s.CreatedAt.String()
|
||||||
|
case "expires_on":
|
||||||
|
return s.ExpiresOn.String()
|
||||||
|
case "refresh_token":
|
||||||
|
return s.RefreshToken
|
||||||
|
case "email":
|
||||||
|
return s.Email
|
||||||
|
case "user":
|
||||||
|
return s.User
|
||||||
|
case "groups":
|
||||||
|
return strings.Join(s.Groups, ",")
|
||||||
|
case "preferred_username":
|
||||||
|
return s.PreferredUsername
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// EncodeSessionState returns an encrypted, lz4 compressed, MessagePack encoded session
|
// EncodeSessionState returns an encrypted, lz4 compressed, MessagePack encoded session
|
||||||
func (s *SessionState) EncodeSessionState(c encryption.Cipher, compress bool) ([]byte, error) {
|
func (s *SessionState) EncodeSessionState(c encryption.Cipher, compress bool) ([]byte, error) {
|
||||||
packed, err := msgpack.Marshal(s)
|
packed, err := msgpack.Marshal(s)
|
||||||
|
37
pkg/header/header_suite_test.go
Normal file
37
pkg/header/header_suite_test.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package header
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
filesDir string
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHeaderSuite(t *testing.T) {
|
||||||
|
logger.SetOutput(GinkgoWriter)
|
||||||
|
|
||||||
|
RegisterFailHandler(Fail)
|
||||||
|
RunSpecs(t, "Header")
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = BeforeSuite(func() {
|
||||||
|
os.Setenv("SECRET_ENV", "super-secret-env")
|
||||||
|
|
||||||
|
dir, err := ioutil.TempDir("", "oauth2-proxy-header-suite")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(ioutil.WriteFile(path.Join(dir, "secret-file"), []byte("super-secret-file"), 0644)).To(Succeed())
|
||||||
|
filesDir = dir
|
||||||
|
})
|
||||||
|
|
||||||
|
var _ = AfterSuite(func() {
|
||||||
|
os.Unsetenv("SECRET_ENV")
|
||||||
|
Expect(os.RemoveAll(filesDir)).To(Succeed())
|
||||||
|
})
|
112
pkg/header/injector.go
Normal file
112
pkg/header/injector.go
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
package header
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options/util"
|
||||||
|
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Injector interface {
|
||||||
|
Inject(http.Header, *sessionsapi.SessionState)
|
||||||
|
}
|
||||||
|
|
||||||
|
type injector struct {
|
||||||
|
valueInjectors []valueInjector
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i injector) Inject(header http.Header, session *sessionsapi.SessionState) {
|
||||||
|
for _, injector := range i.valueInjectors {
|
||||||
|
injector.inject(header, session)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInjector(headers []options.Header) (Injector, error) {
|
||||||
|
injectors := []valueInjector{}
|
||||||
|
for _, header := range headers {
|
||||||
|
for _, value := range header.Values {
|
||||||
|
injector, err := newValueinjector(header.Name, value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error building injector for header %q: %v", header.Name, err)
|
||||||
|
}
|
||||||
|
injectors = append(injectors, injector)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &injector{valueInjectors: injectors}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type valueInjector interface {
|
||||||
|
inject(http.Header, *sessionsapi.SessionState)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newValueinjector(name string, value options.HeaderValue) (valueInjector, error) {
|
||||||
|
switch {
|
||||||
|
case value.SecretSource != nil && value.ClaimSource == nil:
|
||||||
|
return newSecretInjector(name, value.SecretSource)
|
||||||
|
case value.SecretSource == nil && value.ClaimSource != nil:
|
||||||
|
return newClaimInjector(name, value.ClaimSource)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("header %q value has multiple entries: only one entry per value is allowed", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type injectorFunc struct {
|
||||||
|
injectFunc func(http.Header, *sessionsapi.SessionState)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *injectorFunc) inject(header http.Header, session *sessionsapi.SessionState) {
|
||||||
|
i.injectFunc(header, session)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newInjectorFunc(injectFunc func(header http.Header, session *sessionsapi.SessionState)) valueInjector {
|
||||||
|
return &injectorFunc{injectFunc: injectFunc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSecretInjector(name string, source *options.SecretSource) (valueInjector, error) {
|
||||||
|
value, err := util.GetSecretValue(source)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error getting secret value: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return newInjectorFunc(func(header http.Header, session *sessionsapi.SessionState) {
|
||||||
|
header.Add(name, string(value))
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newClaimInjector(name string, source *options.ClaimSource) (valueInjector, error) {
|
||||||
|
switch {
|
||||||
|
case source.BasicAuthPassword != nil:
|
||||||
|
password, err := util.GetSecretValue(source.BasicAuthPassword)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error loading basicAuthPassword: %v", err)
|
||||||
|
}
|
||||||
|
return newInjectorFunc(func(header http.Header, session *sessionsapi.SessionState) {
|
||||||
|
claim := session.GetClaim(source.Claim)
|
||||||
|
if claim == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
auth := claim + ":" + string(password)
|
||||||
|
header.Add(name, "Basic "+base64.StdEncoding.EncodeToString([]byte(auth)))
|
||||||
|
}), nil
|
||||||
|
case source.Prefix != "":
|
||||||
|
return newInjectorFunc(func(header http.Header, session *sessionsapi.SessionState) {
|
||||||
|
claim := session.GetClaim(source.Claim)
|
||||||
|
if claim == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
header.Add(name, source.Prefix+claim)
|
||||||
|
}), nil
|
||||||
|
default:
|
||||||
|
return newInjectorFunc(func(header http.Header, session *sessionsapi.SessionState) {
|
||||||
|
claim := session.GetClaim(source.Claim)
|
||||||
|
if claim == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
header.Add(name, claim)
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
}
|
417
pkg/header/injector_test.go
Normal file
417
pkg/header/injector_test.go
Normal file
@ -0,0 +1,417 @@
|
|||||||
|
package header
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
||||||
|
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/ginkgo/extensions/table"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Injector Suite", func() {
|
||||||
|
Context("NewInjector", func() {
|
||||||
|
type newInjectorTableInput struct {
|
||||||
|
headers []options.Header
|
||||||
|
initialHeaders http.Header
|
||||||
|
session *sessionsapi.SessionState
|
||||||
|
expectedHeaders http.Header
|
||||||
|
expectedErr error
|
||||||
|
}
|
||||||
|
|
||||||
|
DescribeTable("creates an injector",
|
||||||
|
func(in newInjectorTableInput) {
|
||||||
|
injector, err := NewInjector(in.headers)
|
||||||
|
if in.expectedErr != nil {
|
||||||
|
Expect(err).To(MatchError(in.expectedErr))
|
||||||
|
Expect(injector).To(BeNil())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(injector).ToNot(BeNil())
|
||||||
|
|
||||||
|
headers := in.initialHeaders.Clone()
|
||||||
|
injector.Inject(headers, in.session)
|
||||||
|
Expect(headers).To(Equal(in.expectedHeaders))
|
||||||
|
},
|
||||||
|
Entry("with no configured headers", newInjectorTableInput{
|
||||||
|
headers: []options.Header{},
|
||||||
|
initialHeaders: http.Header{
|
||||||
|
"foo": []string{"bar", "baz"},
|
||||||
|
},
|
||||||
|
session: &sessionsapi.SessionState{},
|
||||||
|
expectedHeaders: http.Header{
|
||||||
|
"foo": []string{"bar", "baz"},
|
||||||
|
},
|
||||||
|
expectedErr: nil,
|
||||||
|
}),
|
||||||
|
Entry("with a static valued header from base64", newInjectorTableInput{
|
||||||
|
headers: []options.Header{
|
||||||
|
{
|
||||||
|
Name: "Secret",
|
||||||
|
Values: []options.HeaderValue{
|
||||||
|
{
|
||||||
|
SecretSource: &options.SecretSource{
|
||||||
|
Value: []byte(base64.StdEncoding.EncodeToString([]byte("super-secret"))),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
initialHeaders: http.Header{
|
||||||
|
"foo": []string{"bar", "baz"},
|
||||||
|
},
|
||||||
|
session: &sessionsapi.SessionState{},
|
||||||
|
expectedHeaders: http.Header{
|
||||||
|
"foo": []string{"bar", "baz"},
|
||||||
|
"Secret": []string{"super-secret"},
|
||||||
|
},
|
||||||
|
expectedErr: nil,
|
||||||
|
}),
|
||||||
|
Entry("with a static valued header from env", newInjectorTableInput{
|
||||||
|
headers: []options.Header{
|
||||||
|
{
|
||||||
|
Name: "Secret",
|
||||||
|
Values: []options.HeaderValue{
|
||||||
|
{
|
||||||
|
SecretSource: &options.SecretSource{
|
||||||
|
FromEnv: "SECRET_ENV",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
initialHeaders: http.Header{
|
||||||
|
"foo": []string{"bar", "baz"},
|
||||||
|
},
|
||||||
|
session: &sessionsapi.SessionState{},
|
||||||
|
expectedHeaders: http.Header{
|
||||||
|
"foo": []string{"bar", "baz"},
|
||||||
|
"Secret": []string{"super-secret-env"},
|
||||||
|
},
|
||||||
|
expectedErr: nil,
|
||||||
|
}),
|
||||||
|
Entry("with a claim valued header", newInjectorTableInput{
|
||||||
|
headers: []options.Header{
|
||||||
|
{
|
||||||
|
Name: "Claim",
|
||||||
|
Values: []options.HeaderValue{
|
||||||
|
{
|
||||||
|
ClaimSource: &options.ClaimSource{
|
||||||
|
Claim: "id_token",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
initialHeaders: http.Header{
|
||||||
|
"foo": []string{"bar", "baz"},
|
||||||
|
},
|
||||||
|
session: &sessionsapi.SessionState{
|
||||||
|
IDToken: "IDToken-1234",
|
||||||
|
},
|
||||||
|
expectedHeaders: http.Header{
|
||||||
|
"foo": []string{"bar", "baz"},
|
||||||
|
"Claim": []string{"IDToken-1234"},
|
||||||
|
},
|
||||||
|
expectedErr: nil,
|
||||||
|
}),
|
||||||
|
Entry("with a claim valued header and a nil session", newInjectorTableInput{
|
||||||
|
headers: []options.Header{
|
||||||
|
{
|
||||||
|
Name: "Claim",
|
||||||
|
Values: []options.HeaderValue{
|
||||||
|
{
|
||||||
|
ClaimSource: &options.ClaimSource{
|
||||||
|
Claim: "id_token",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
initialHeaders: http.Header{
|
||||||
|
"foo": []string{"bar", "baz"},
|
||||||
|
},
|
||||||
|
session: nil,
|
||||||
|
expectedHeaders: http.Header{
|
||||||
|
"foo": []string{"bar", "baz"},
|
||||||
|
},
|
||||||
|
expectedErr: nil,
|
||||||
|
}),
|
||||||
|
Entry("with a prefixed claim valued header", newInjectorTableInput{
|
||||||
|
headers: []options.Header{
|
||||||
|
{
|
||||||
|
Name: "Claim",
|
||||||
|
Values: []options.HeaderValue{
|
||||||
|
{
|
||||||
|
ClaimSource: &options.ClaimSource{
|
||||||
|
Claim: "id_token",
|
||||||
|
Prefix: "Bearer ",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
initialHeaders: http.Header{
|
||||||
|
"foo": []string{"bar", "baz"},
|
||||||
|
},
|
||||||
|
session: &sessionsapi.SessionState{
|
||||||
|
IDToken: "IDToken-1234",
|
||||||
|
},
|
||||||
|
expectedHeaders: http.Header{
|
||||||
|
"foo": []string{"bar", "baz"},
|
||||||
|
"Claim": []string{"Bearer IDToken-1234"},
|
||||||
|
},
|
||||||
|
expectedErr: nil,
|
||||||
|
}),
|
||||||
|
Entry("with a prefixed claim valued header missing the claim", newInjectorTableInput{
|
||||||
|
headers: []options.Header{
|
||||||
|
{
|
||||||
|
Name: "Claim",
|
||||||
|
Values: []options.HeaderValue{
|
||||||
|
{
|
||||||
|
ClaimSource: &options.ClaimSource{
|
||||||
|
Claim: "idToken",
|
||||||
|
Prefix: "Bearer ",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
initialHeaders: http.Header{
|
||||||
|
"foo": []string{"bar", "baz"},
|
||||||
|
},
|
||||||
|
session: &sessionsapi.SessionState{},
|
||||||
|
expectedHeaders: http.Header{
|
||||||
|
"foo": []string{"bar", "baz"},
|
||||||
|
},
|
||||||
|
expectedErr: nil,
|
||||||
|
}),
|
||||||
|
Entry("with a basicAuthPassword and claim valued header", newInjectorTableInput{
|
||||||
|
headers: []options.Header{
|
||||||
|
{
|
||||||
|
Name: "X-Auth-Request-Authorization",
|
||||||
|
Values: []options.HeaderValue{
|
||||||
|
{
|
||||||
|
ClaimSource: &options.ClaimSource{
|
||||||
|
Claim: "user",
|
||||||
|
BasicAuthPassword: &options.SecretSource{
|
||||||
|
Value: []byte(base64.StdEncoding.EncodeToString([]byte("basic-password"))),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
initialHeaders: http.Header{
|
||||||
|
"foo": []string{"bar", "baz"},
|
||||||
|
},
|
||||||
|
session: &sessionsapi.SessionState{
|
||||||
|
User: "user-123",
|
||||||
|
},
|
||||||
|
expectedHeaders: http.Header{
|
||||||
|
"foo": []string{"bar", "baz"},
|
||||||
|
"X-Auth-Request-Authorization": []string{"Basic " + base64.StdEncoding.EncodeToString([]byte("user-123:basic-password"))},
|
||||||
|
},
|
||||||
|
expectedErr: nil,
|
||||||
|
}),
|
||||||
|
Entry("with a basicAuthPassword and claim valued header missing the claim", newInjectorTableInput{
|
||||||
|
headers: []options.Header{
|
||||||
|
{
|
||||||
|
Name: "X-Auth-Request-Authorization",
|
||||||
|
Values: []options.HeaderValue{
|
||||||
|
{
|
||||||
|
ClaimSource: &options.ClaimSource{
|
||||||
|
Claim: "user",
|
||||||
|
BasicAuthPassword: &options.SecretSource{
|
||||||
|
Value: []byte(base64.StdEncoding.EncodeToString([]byte("basic-password"))),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
initialHeaders: http.Header{
|
||||||
|
"foo": []string{"bar", "baz"},
|
||||||
|
},
|
||||||
|
session: &sessionsapi.SessionState{},
|
||||||
|
expectedHeaders: http.Header{
|
||||||
|
"foo": []string{"bar", "baz"},
|
||||||
|
},
|
||||||
|
expectedErr: nil,
|
||||||
|
}),
|
||||||
|
Entry("with a header that already exists", newInjectorTableInput{
|
||||||
|
headers: []options.Header{
|
||||||
|
{
|
||||||
|
Name: "X-Auth-Request-User",
|
||||||
|
Values: []options.HeaderValue{
|
||||||
|
{
|
||||||
|
ClaimSource: &options.ClaimSource{
|
||||||
|
Claim: "user",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
initialHeaders: http.Header{
|
||||||
|
"X-Auth-Request-User": []string{"user"},
|
||||||
|
},
|
||||||
|
session: &sessionsapi.SessionState{
|
||||||
|
User: "user-123",
|
||||||
|
},
|
||||||
|
expectedHeaders: http.Header{
|
||||||
|
"X-Auth-Request-User": []string{"user", "user-123"},
|
||||||
|
},
|
||||||
|
expectedErr: nil,
|
||||||
|
}),
|
||||||
|
Entry("with a claim and secret valued header value", newInjectorTableInput{
|
||||||
|
headers: []options.Header{
|
||||||
|
{
|
||||||
|
Name: "Claim",
|
||||||
|
Values: []options.HeaderValue{
|
||||||
|
{
|
||||||
|
ClaimSource: &options.ClaimSource{
|
||||||
|
Claim: "id_token",
|
||||||
|
},
|
||||||
|
SecretSource: &options.SecretSource{
|
||||||
|
FromEnv: "SECRET_ENV",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
initialHeaders: http.Header{
|
||||||
|
"foo": []string{"bar", "baz"},
|
||||||
|
},
|
||||||
|
session: &sessionsapi.SessionState{
|
||||||
|
IDToken: "IDToken-1234",
|
||||||
|
},
|
||||||
|
expectedHeaders: nil,
|
||||||
|
expectedErr: errors.New("error building injector for header \"Claim\": header \"Claim\" value has multiple entries: only one entry per value is allowed"),
|
||||||
|
}),
|
||||||
|
Entry("with an invalid static valued header", newInjectorTableInput{
|
||||||
|
headers: []options.Header{
|
||||||
|
{
|
||||||
|
Name: "Secret",
|
||||||
|
Values: []options.HeaderValue{
|
||||||
|
{
|
||||||
|
SecretSource: &options.SecretSource{
|
||||||
|
FromEnv: "SECRET_ENV",
|
||||||
|
FromFile: "secret-file",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
initialHeaders: http.Header{
|
||||||
|
"foo": []string{"bar", "baz"},
|
||||||
|
},
|
||||||
|
session: &sessionsapi.SessionState{},
|
||||||
|
expectedHeaders: nil,
|
||||||
|
expectedErr: errors.New("error building injector for header \"Secret\": error getting secret value: secret source is invalid: exactly one entry required, specify either value, fromEnv or fromFile"),
|
||||||
|
}),
|
||||||
|
Entry("with an invalid basicAuthPassword claim valued header", newInjectorTableInput{
|
||||||
|
headers: []options.Header{
|
||||||
|
{
|
||||||
|
Name: "X-Auth-Request-Authorization",
|
||||||
|
Values: []options.HeaderValue{
|
||||||
|
{
|
||||||
|
ClaimSource: &options.ClaimSource{
|
||||||
|
Claim: "user",
|
||||||
|
BasicAuthPassword: &options.SecretSource{
|
||||||
|
Value: []byte(base64.StdEncoding.EncodeToString([]byte("basic-password"))),
|
||||||
|
FromEnv: "SECRET_ENV",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
initialHeaders: http.Header{
|
||||||
|
"foo": []string{"bar", "baz"},
|
||||||
|
},
|
||||||
|
session: &sessionsapi.SessionState{
|
||||||
|
User: "user-123",
|
||||||
|
},
|
||||||
|
expectedHeaders: nil,
|
||||||
|
expectedErr: errors.New("error building injector for header \"X-Auth-Request-Authorization\": error loading basicAuthPassword: secret source is invalid: exactly one entry required, specify either value, fromEnv or fromFile"),
|
||||||
|
}),
|
||||||
|
Entry("with a mix of configured headers", newInjectorTableInput{
|
||||||
|
headers: []options.Header{
|
||||||
|
{
|
||||||
|
Name: "X-Auth-Request-Authorization",
|
||||||
|
Values: []options.HeaderValue{
|
||||||
|
{
|
||||||
|
ClaimSource: &options.ClaimSource{
|
||||||
|
Claim: "user",
|
||||||
|
BasicAuthPassword: &options.SecretSource{
|
||||||
|
Value: []byte(base64.StdEncoding.EncodeToString([]byte("basic-password"))),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "X-Auth-Request-User",
|
||||||
|
Values: []options.HeaderValue{
|
||||||
|
{
|
||||||
|
ClaimSource: &options.ClaimSource{
|
||||||
|
Claim: "user",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "X-Auth-Request-Email",
|
||||||
|
Values: []options.HeaderValue{
|
||||||
|
{
|
||||||
|
ClaimSource: &options.ClaimSource{
|
||||||
|
Claim: "email",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "X-Auth-Request-Version-Info",
|
||||||
|
Values: []options.HeaderValue{
|
||||||
|
{
|
||||||
|
SecretSource: &options.SecretSource{
|
||||||
|
Value: []byte(base64.StdEncoding.EncodeToString([]byte("major=1"))),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
SecretSource: &options.SecretSource{
|
||||||
|
Value: []byte(base64.StdEncoding.EncodeToString([]byte("minor=2"))),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
SecretSource: &options.SecretSource{
|
||||||
|
Value: []byte(base64.StdEncoding.EncodeToString([]byte("patch=3"))),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
initialHeaders: http.Header{
|
||||||
|
"foo": []string{"bar", "baz"},
|
||||||
|
},
|
||||||
|
session: &sessionsapi.SessionState{
|
||||||
|
User: "user-123",
|
||||||
|
Email: "user@example.com",
|
||||||
|
},
|
||||||
|
expectedHeaders: http.Header{
|
||||||
|
"foo": []string{"bar", "baz"},
|
||||||
|
"X-Auth-Request-Authorization": []string{"Basic " + base64.StdEncoding.EncodeToString([]byte("user-123:basic-password"))},
|
||||||
|
"X-Auth-Request-User": []string{"user-123"},
|
||||||
|
"X-Auth-Request-Email": []string{"user@example.com"},
|
||||||
|
"X-Auth-Request-Version-Info": []string{"major=1", "minor=2", "patch=3"},
|
||||||
|
},
|
||||||
|
expectedErr: nil,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
Loading…
x
Reference in New Issue
Block a user