mirror of
https://github.com/oauth2-proxy/oauth2-proxy.git
synced 2024-11-24 08:52:25 +02:00
63727103db
You must explicitly configure oauth2-proxy (alpha config only) with which parameters are allowed to pass through, and optionally provide an allow-list of valid values and/or regular expressions for each one. Note that this mechanism subsumes the functionality of the "prompt", "approval_prompt" and "acr_values" legacy configuration options, which must be converted to the equivalent YAML when running in alpha config mode.
258 lines
7.2 KiB
Go
258 lines
7.2 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
|
|
. "github.com/onsi/ginkgo"
|
|
. "github.com/onsi/ginkgo/extensions/table"
|
|
. "github.com/onsi/gomega"
|
|
"github.com/spf13/pflag"
|
|
)
|
|
|
|
var _ = Describe("Configuration Loading Suite", func() {
|
|
const testLegacyConfig = `
|
|
http_address="127.0.0.1:4180"
|
|
upstreams="http://httpbin"
|
|
set_basic_auth="true"
|
|
basic_auth_password="super-secret-password"
|
|
client_id="oauth2-proxy"
|
|
client_secret="b2F1dGgyLXByb3h5LWNsaWVudC1zZWNyZXQK"
|
|
`
|
|
|
|
const testAlphaConfig = `
|
|
upstreamConfig:
|
|
proxyrawpath: false
|
|
upstreams:
|
|
- id: /
|
|
path: /
|
|
uri: http://httpbin
|
|
flushInterval: 1s
|
|
passHostHeader: true
|
|
proxyWebSockets: true
|
|
injectRequestHeaders:
|
|
- name: Authorization
|
|
values:
|
|
- claim: user
|
|
prefix: "Basic "
|
|
basicAuthPassword:
|
|
value: c3VwZXItc2VjcmV0LXBhc3N3b3Jk
|
|
- name: X-Forwarded-Groups
|
|
values:
|
|
- claim: groups
|
|
- name: X-Forwarded-User
|
|
values:
|
|
- claim: user
|
|
- name: X-Forwarded-Email
|
|
values:
|
|
- claim: email
|
|
- name: X-Forwarded-Preferred-Username
|
|
values:
|
|
- claim: preferred_username
|
|
injectResponseHeaders:
|
|
- name: Authorization
|
|
values:
|
|
- claim: user
|
|
prefix: "Basic "
|
|
basicAuthPassword:
|
|
value: c3VwZXItc2VjcmV0LXBhc3N3b3Jk
|
|
server:
|
|
bindAddress: "127.0.0.1:4180"
|
|
providers:
|
|
- provider: google
|
|
ID: google=oauth2-proxy
|
|
clientSecret: b2F1dGgyLXByb3h5LWNsaWVudC1zZWNyZXQK
|
|
clientID: oauth2-proxy
|
|
azureConfig:
|
|
tenant: common
|
|
oidcConfig:
|
|
groupsClaim: groups
|
|
emailClaim: email
|
|
userIDClaim: email
|
|
insecureSkipNonce: true
|
|
audienceClaims: [aud]
|
|
extraAudiences: []
|
|
loginURLParameters:
|
|
- name: approval_prompt
|
|
default:
|
|
- force
|
|
`
|
|
|
|
const testCoreConfig = `
|
|
cookie_secret="OQINaROshtE9TcZkNAm-5Zs2Pv3xaWytBmc5W7sPX7w="
|
|
email_domains="example.com"
|
|
cookie_secure="false"
|
|
|
|
redirect_url="http://localhost:4180/oauth2/callback"
|
|
`
|
|
|
|
boolPtr := func(b bool) *bool {
|
|
return &b
|
|
}
|
|
|
|
durationPtr := func(d time.Duration) *options.Duration {
|
|
du := options.Duration(d)
|
|
return &du
|
|
}
|
|
|
|
testExpectedOptions := func() *options.Options {
|
|
opts, err := options.NewLegacyOptions().ToOptions()
|
|
Expect(err).ToNot(HaveOccurred())
|
|
|
|
opts.Cookie.Secret = "OQINaROshtE9TcZkNAm-5Zs2Pv3xaWytBmc5W7sPX7w="
|
|
opts.EmailDomains = []string{"example.com"}
|
|
opts.Cookie.Secure = false
|
|
opts.RawRedirectURL = "http://localhost:4180/oauth2/callback"
|
|
|
|
opts.UpstreamServers = options.UpstreamConfig{
|
|
Upstreams: []options.Upstream{
|
|
{
|
|
ID: "/",
|
|
Path: "/",
|
|
URI: "http://httpbin",
|
|
FlushInterval: durationPtr(options.DefaultUpstreamFlushInterval),
|
|
PassHostHeader: boolPtr(true),
|
|
ProxyWebSockets: boolPtr(true),
|
|
},
|
|
},
|
|
}
|
|
|
|
authHeader := options.Header{
|
|
Name: "Authorization",
|
|
Values: []options.HeaderValue{
|
|
{
|
|
ClaimSource: &options.ClaimSource{
|
|
Claim: "user",
|
|
Prefix: "Basic ",
|
|
BasicAuthPassword: &options.SecretSource{
|
|
Value: []byte("super-secret-password"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
opts.InjectRequestHeaders = append([]options.Header{authHeader}, opts.InjectRequestHeaders...)
|
|
opts.InjectResponseHeaders = append(opts.InjectResponseHeaders, authHeader)
|
|
|
|
opts.Providers = options.Providers{
|
|
options.Provider{
|
|
ID: "google=oauth2-proxy",
|
|
Type: "google",
|
|
ClientSecret: "b2F1dGgyLXByb3h5LWNsaWVudC1zZWNyZXQK",
|
|
ClientID: "oauth2-proxy",
|
|
AzureConfig: options.AzureOptions{
|
|
Tenant: "common",
|
|
},
|
|
OIDCConfig: options.OIDCOptions{
|
|
GroupsClaim: "groups",
|
|
EmailClaim: "email",
|
|
UserIDClaim: "email",
|
|
AudienceClaims: []string{"aud"},
|
|
ExtraAudiences: []string{},
|
|
InsecureSkipNonce: true,
|
|
},
|
|
LoginURLParameters: []options.LoginURLParameter{
|
|
{Name: "approval_prompt", Default: []string{"force"}},
|
|
},
|
|
},
|
|
}
|
|
return opts
|
|
}
|
|
|
|
type loadConfigurationTableInput struct {
|
|
configContent string
|
|
alphaConfigContent string
|
|
args []string
|
|
extraFlags func() *pflag.FlagSet
|
|
expectedOptions func() *options.Options
|
|
expectedErr error
|
|
}
|
|
|
|
DescribeTable("LoadConfiguration",
|
|
func(in loadConfigurationTableInput) {
|
|
var configFileName, alphaConfigFileName string
|
|
|
|
defer func() {
|
|
if configFileName != "" {
|
|
Expect(os.Remove(configFileName)).To(Succeed())
|
|
}
|
|
if alphaConfigFileName != "" {
|
|
Expect(os.Remove(alphaConfigFileName)).To(Succeed())
|
|
}
|
|
}()
|
|
|
|
if in.configContent != "" {
|
|
By("Writing the config to a temporary file", func() {
|
|
file, err := ioutil.TempFile("", "oauth2-proxy-test-config-XXXX.cfg")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
defer file.Close()
|
|
|
|
configFileName = file.Name()
|
|
|
|
_, err = file.WriteString(in.configContent)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
})
|
|
}
|
|
|
|
if in.alphaConfigContent != "" {
|
|
By("Writing the config to a temporary file", func() {
|
|
file, err := ioutil.TempFile("", "oauth2-proxy-test-alpha-config-XXXX.yaml")
|
|
Expect(err).ToNot(HaveOccurred())
|
|
defer file.Close()
|
|
|
|
alphaConfigFileName = file.Name()
|
|
|
|
_, err = file.WriteString(in.alphaConfigContent)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
})
|
|
}
|
|
|
|
extraFlags := pflag.NewFlagSet("test-flagset", pflag.ExitOnError)
|
|
if in.extraFlags != nil {
|
|
extraFlags = in.extraFlags()
|
|
}
|
|
|
|
opts, err := loadConfiguration(configFileName, alphaConfigFileName, extraFlags, in.args)
|
|
if in.expectedErr != nil {
|
|
Expect(err).To(MatchError(in.expectedErr.Error()))
|
|
} else {
|
|
Expect(err).ToNot(HaveOccurred())
|
|
}
|
|
Expect(in.expectedOptions).ToNot(BeNil())
|
|
Expect(opts).To(Equal(in.expectedOptions()))
|
|
},
|
|
Entry("with legacy configuration", loadConfigurationTableInput{
|
|
configContent: testCoreConfig + testLegacyConfig,
|
|
expectedOptions: testExpectedOptions,
|
|
}),
|
|
Entry("with alpha configuration", loadConfigurationTableInput{
|
|
configContent: testCoreConfig,
|
|
alphaConfigContent: testAlphaConfig,
|
|
expectedOptions: testExpectedOptions,
|
|
}),
|
|
Entry("with bad legacy configuration", loadConfigurationTableInput{
|
|
configContent: testCoreConfig + "unknown_field=\"something\"",
|
|
expectedOptions: func() *options.Options { return nil },
|
|
expectedErr: errors.New("failed to load config: error unmarshalling config: 1 error(s) decoding:\n\n* '' has invalid keys: unknown_field"),
|
|
}),
|
|
Entry("with bad alpha configuration", loadConfigurationTableInput{
|
|
configContent: testCoreConfig,
|
|
alphaConfigContent: testAlphaConfig + ":",
|
|
expectedOptions: func() *options.Options { return nil },
|
|
expectedErr: fmt.Errorf("failed to load alpha options: error unmarshalling config: error converting YAML to JSON: yaml: line %d: did not find expected key", strings.Count(testAlphaConfig, "\n")),
|
|
}),
|
|
Entry("with alpha configuration and bad core configuration", loadConfigurationTableInput{
|
|
configContent: testCoreConfig + "unknown_field=\"something\"",
|
|
alphaConfigContent: testAlphaConfig,
|
|
expectedOptions: func() *options.Options { return nil },
|
|
expectedErr: errors.New("failed to load core options: failed to load config: error unmarshalling config: 1 error(s) decoding:\n\n* '' has invalid keys: unknown_field"),
|
|
}),
|
|
)
|
|
})
|