mirror of
https://github.com/pomerium/pomerium.git
synced 2025-05-18 11:37:08 +02:00
Protect Options from being mutated by services
- Change Options URLs from pointers to values - Remove special handling for AuthenticateURL checksum - Change Options itself to a value
This commit is contained in:
parent
49bc8274f1
commit
64eb992854
12 changed files with 117 additions and 125 deletions
|
@ -18,8 +18,8 @@ import (
|
||||||
// ValidateOptions checks to see if configuration values are valid for the authenticate service.
|
// ValidateOptions checks to see if configuration values are valid for the authenticate service.
|
||||||
// The checks do not modify the internal state of the Option structure. Returns
|
// The checks do not modify the internal state of the Option structure. Returns
|
||||||
// on first error found.
|
// on first error found.
|
||||||
func ValidateOptions(o *config.Options) error {
|
func ValidateOptions(o config.Options) error {
|
||||||
if o.AuthenticateURL == nil || o.AuthenticateURL.Hostname() == "" {
|
if o.AuthenticateURL.Hostname() == "" {
|
||||||
return errors.New("authenticate: 'AUTHENTICATE_SERVICE_URL' missing")
|
return errors.New("authenticate: 'AUTHENTICATE_SERVICE_URL' missing")
|
||||||
}
|
}
|
||||||
if o.ClientID == "" {
|
if o.ClientID == "" {
|
||||||
|
@ -54,10 +54,7 @@ type Authenticate struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// New validates and creates a new authenticate service from a set of Options
|
// New validates and creates a new authenticate service from a set of Options
|
||||||
func New(opts *config.Options) (*Authenticate, error) {
|
func New(opts config.Options) (*Authenticate, error) {
|
||||||
if opts == nil {
|
|
||||||
return nil, errors.New("authenticate: options cannot be nil")
|
|
||||||
}
|
|
||||||
if err := ValidateOptions(opts); err != nil {
|
if err := ValidateOptions(opts); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -83,7 +80,7 @@ func New(opts *config.Options) (*Authenticate, error) {
|
||||||
provider, err := identity.New(
|
provider, err := identity.New(
|
||||||
opts.Provider,
|
opts.Provider,
|
||||||
&identity.Provider{
|
&identity.Provider{
|
||||||
RedirectURL: redirectURL,
|
RedirectURL: &redirectURL,
|
||||||
ProviderName: opts.Provider,
|
ProviderName: opts.Provider,
|
||||||
ProviderURL: opts.ProviderURL,
|
ProviderURL: opts.ProviderURL,
|
||||||
ClientID: opts.ClientID,
|
ClientID: opts.ClientID,
|
||||||
|
@ -97,7 +94,7 @@ func New(opts *config.Options) (*Authenticate, error) {
|
||||||
|
|
||||||
return &Authenticate{
|
return &Authenticate{
|
||||||
SharedKey: opts.SharedKey,
|
SharedKey: opts.SharedKey,
|
||||||
RedirectURL: redirectURL,
|
RedirectURL: &redirectURL,
|
||||||
templates: templates.New(),
|
templates: templates.New(),
|
||||||
csrfStore: cookieStore,
|
csrfStore: cookieStore,
|
||||||
sessionStore: cookieStore,
|
sessionStore: cookieStore,
|
||||||
|
|
|
@ -8,10 +8,10 @@ import (
|
||||||
"github.com/pomerium/pomerium/internal/config"
|
"github.com/pomerium/pomerium/internal/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testOptions() *config.Options {
|
func testOptions() config.Options {
|
||||||
redirectURL, _ := url.Parse("https://example.com/oauth2/callback")
|
redirectURL, _ := url.Parse("https://example.com/oauth2/callback")
|
||||||
return &config.Options{
|
return config.Options{
|
||||||
AuthenticateURL: redirectURL,
|
AuthenticateURL: *redirectURL,
|
||||||
SharedKey: "80ldlrU2d7w+wVpKNfevk6fmb8otEx6CqOfshj2LwhQ=",
|
SharedKey: "80ldlrU2d7w+wVpKNfevk6fmb8otEx6CqOfshj2LwhQ=",
|
||||||
ClientID: "test-client-id",
|
ClientID: "test-client-id",
|
||||||
ClientSecret: "OromP1gurwGWjQPYb1nNgSxtbVB5NnLzX6z5WOKr0Yw=",
|
ClientSecret: "OromP1gurwGWjQPYb1nNgSxtbVB5NnLzX6z5WOKr0Yw=",
|
||||||
|
@ -25,7 +25,7 @@ func testOptions() *config.Options {
|
||||||
func TestOptions_Validate(t *testing.T) {
|
func TestOptions_Validate(t *testing.T) {
|
||||||
good := testOptions()
|
good := testOptions()
|
||||||
badRedirectURL := testOptions()
|
badRedirectURL := testOptions()
|
||||||
badRedirectURL.AuthenticateURL = nil
|
badRedirectURL.AuthenticateURL = url.URL{}
|
||||||
emptyClientID := testOptions()
|
emptyClientID := testOptions()
|
||||||
emptyClientID.ClientID = ""
|
emptyClientID.ClientID = ""
|
||||||
emptyClientSecret := testOptions()
|
emptyClientSecret := testOptions()
|
||||||
|
@ -39,15 +39,15 @@ func TestOptions_Validate(t *testing.T) {
|
||||||
badSharedKey := testOptions()
|
badSharedKey := testOptions()
|
||||||
badSharedKey.SharedKey = ""
|
badSharedKey.SharedKey = ""
|
||||||
badAuthenticateURL := testOptions()
|
badAuthenticateURL := testOptions()
|
||||||
badAuthenticateURL.AuthenticateURL = new(url.URL)
|
badAuthenticateURL.AuthenticateURL = url.URL{}
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
o *config.Options
|
o config.Options
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{"minimum options", good, false},
|
{"minimum options", good, false},
|
||||||
{"nil options", &config.Options{}, true},
|
{"nil options", config.Options{}, true},
|
||||||
{"bad redirect url", badRedirectURL, true},
|
{"bad redirect url", badRedirectURL, true},
|
||||||
{"no cookie secret", emptyCookieSecret, true},
|
{"no cookie secret", emptyCookieSecret, true},
|
||||||
{"invalid cookie secret", invalidCookieSecret, true},
|
{"invalid cookie secret", invalidCookieSecret, true},
|
||||||
|
@ -72,16 +72,16 @@ func TestNew(t *testing.T) {
|
||||||
good.Provider = "google"
|
good.Provider = "google"
|
||||||
|
|
||||||
badRedirectURL := testOptions()
|
badRedirectURL := testOptions()
|
||||||
badRedirectURL.AuthenticateURL = nil
|
badRedirectURL.AuthenticateURL = url.URL{}
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
opts *config.Options
|
opts config.Options
|
||||||
// want *Authenticate
|
// want *Authenticate
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{"good", good, false},
|
{"good", good, false},
|
||||||
{"empty opts", nil, true},
|
{"empty opts", config.Options{}, true},
|
||||||
{"fails to validate", badRedirectURL, true},
|
{"fails to validate", badRedirectURL, true},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
|
|
||||||
// ValidateOptions checks to see if configuration values are valid for the
|
// ValidateOptions checks to see if configuration values are valid for the
|
||||||
// authorize service. Returns first error, if found.
|
// authorize service. Returns first error, if found.
|
||||||
func ValidateOptions(o *config.Options) error {
|
func ValidateOptions(o config.Options) error {
|
||||||
decoded, err := base64.StdEncoding.DecodeString(o.SharedKey)
|
decoded, err := base64.StdEncoding.DecodeString(o.SharedKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("authorize: `SHARED_SECRET` setting is invalid base64: %v", err)
|
return fmt.Errorf("authorize: `SHARED_SECRET` setting is invalid base64: %v", err)
|
||||||
|
@ -39,10 +39,7 @@ type Authorize struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// New validates and creates a new Authorize service from a set of Options
|
// New validates and creates a new Authorize service from a set of Options
|
||||||
func New(opts *config.Options) (*Authorize, error) {
|
func New(opts config.Options) (*Authorize, error) {
|
||||||
if opts == nil {
|
|
||||||
return nil, errors.New("authorize: options cannot be nil")
|
|
||||||
}
|
|
||||||
if err := ValidateOptions(opts); err != nil {
|
if err := ValidateOptions(opts); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -67,7 +64,7 @@ func (a *Authorize) ValidIdentity(route string, identity *Identity) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateOptions updates internal structres based on config.Options
|
// UpdateOptions updates internal structres based on config.Options
|
||||||
func (a *Authorize) UpdateOptions(o *config.Options) error {
|
func (a *Authorize) UpdateOptions(o config.Options) error {
|
||||||
log.Info().Msg("authorize: updating options")
|
log.Info().Msg("authorize: updating options")
|
||||||
a.identityAccess = NewIdentityWhitelist(o.Policies, o.Administrators)
|
a.identityAccess = NewIdentityWhitelist(o.Policies, o.Administrators)
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -22,14 +22,14 @@ func TestNew(t *testing.T) {
|
||||||
{"bad shared secret", "AZA85podM73CjLCjViDNz1EUvvejKpWp7Hysr0knXA==", policies, true},
|
{"bad shared secret", "AZA85podM73CjLCjViDNz1EUvvejKpWp7Hysr0knXA==", policies, true},
|
||||||
{"really bad shared secret", "sup", policies, true},
|
{"really bad shared secret", "sup", policies, true},
|
||||||
{"validation error, short secret", "AZA85podM73CjLCjViDNz1EUvvejKpWp7Hysr0knXA==", policies, true},
|
{"validation error, short secret", "AZA85podM73CjLCjViDNz1EUvvejKpWp7Hysr0knXA==", policies, true},
|
||||||
{"nil options", "", []policy.Policy{}, true}, // special case
|
{"empty options", "", []policy.Policy{}, true}, // special case
|
||||||
{"missing policies", "gXK6ggrlIW2HyKyUF9rUO4azrDgxhDPWqw9y+lJU7B8=", []policy.Policy{}, true}, // special case
|
{"missing policies", "gXK6ggrlIW2HyKyUF9rUO4azrDgxhDPWqw9y+lJU7B8=", []policy.Policy{}, true}, // special case
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
o := &config.Options{SharedKey: tt.SharedKey, Policies: tt.Policies}
|
o := config.Options{SharedKey: tt.SharedKey, Policies: tt.Policies}
|
||||||
if tt.name == "nil options" {
|
if tt.name == "empty options" {
|
||||||
o = nil
|
o = config.Options{}
|
||||||
}
|
}
|
||||||
_, err := New(o)
|
_, err := New(o)
|
||||||
if (err != nil) != tt.wantErr {
|
if (err != nil) != tt.wantErr {
|
||||||
|
@ -76,7 +76,7 @@ func Test_UpdateOptions(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
o := &config.Options{SharedKey: tt.SharedKey, Policies: tt.Policies}
|
o := config.Options{SharedKey: tt.SharedKey, Policies: tt.Policies}
|
||||||
authorize, _ := New(o)
|
authorize, _ := New(o)
|
||||||
o.Policies = tt.newPolices
|
o.Policies = tt.newPolices
|
||||||
authorize.UpdateOptions(o)
|
authorize.UpdateOptions(o)
|
||||||
|
|
|
@ -114,8 +114,8 @@ func startRedirectServer(addr string) (*http.Server, error) {
|
||||||
return srv, nil
|
return srv, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAuthenticateService(opt *config.Options, mux *http.ServeMux, rpc *grpc.Server) (*authenticate.Authenticate, error) {
|
func newAuthenticateService(opt config.Options, mux *http.ServeMux, rpc *grpc.Server) (*authenticate.Authenticate, error) {
|
||||||
if opt == nil || !config.IsAuthenticate(opt.Services) {
|
if !config.IsAuthenticate(opt.Services) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
service, err := authenticate.New(opt)
|
service, err := authenticate.New(opt)
|
||||||
|
@ -127,8 +127,8 @@ func newAuthenticateService(opt *config.Options, mux *http.ServeMux, rpc *grpc.S
|
||||||
return service, nil
|
return service, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAuthorizeService(opt *config.Options, rpc *grpc.Server) (*authorize.Authorize, error) {
|
func newAuthorizeService(opt config.Options, rpc *grpc.Server) (*authorize.Authorize, error) {
|
||||||
if opt == nil || !config.IsAuthorize(opt.Services) {
|
if !config.IsAuthorize(opt.Services) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
service, err := authorize.New(opt)
|
service, err := authorize.New(opt)
|
||||||
|
@ -139,8 +139,8 @@ func newAuthorizeService(opt *config.Options, rpc *grpc.Server) (*authorize.Auth
|
||||||
return service, nil
|
return service, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newProxyService(opt *config.Options, mux *http.ServeMux) (*proxy.Proxy, error) {
|
func newProxyService(opt config.Options, mux *http.ServeMux) (*proxy.Proxy, error) {
|
||||||
if opt == nil || !config.IsProxy(opt.Services) {
|
if !config.IsProxy(opt.Services) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
service, err := proxy.New(opt)
|
service, err := proxy.New(opt)
|
||||||
|
@ -151,7 +151,7 @@ func newProxyService(opt *config.Options, mux *http.ServeMux) (*proxy.Proxy, err
|
||||||
return service, nil
|
return service, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func wrapMiddleware(o *config.Options, mux *http.ServeMux) http.Handler {
|
func wrapMiddleware(o config.Options, mux *http.ServeMux) http.Handler {
|
||||||
c := middleware.NewChain()
|
c := middleware.NewChain()
|
||||||
c = c.Append(log.NewHandler(log.Logger))
|
c = c.Append(log.NewHandler(log.Logger))
|
||||||
c = c.Append(log.AccessHandler(func(r *http.Request, status, size int, duration time.Duration) {
|
c = c.Append(log.AccessHandler(func(r *http.Request, status, size int, duration time.Duration) {
|
||||||
|
@ -166,7 +166,7 @@ func wrapMiddleware(o *config.Options, mux *http.ServeMux) http.Handler {
|
||||||
Str("url", r.URL.String()).
|
Str("url", r.URL.String()).
|
||||||
Msg("http-request")
|
Msg("http-request")
|
||||||
}))
|
}))
|
||||||
if o != nil && len(o.Headers) != 0 {
|
if len(o.Headers) != 0 {
|
||||||
c = c.Append(middleware.SetHeaders(o.Headers))
|
c = c.Append(middleware.SetHeaders(o.Headers))
|
||||||
}
|
}
|
||||||
c = c.Append(log.ForwardedAddrHandler("fwd_ip"))
|
c = c.Append(log.ForwardedAddrHandler("fwd_ip"))
|
||||||
|
@ -178,10 +178,10 @@ func wrapMiddleware(o *config.Options, mux *http.ServeMux) http.Handler {
|
||||||
return c.Then(mux)
|
return c.Then(mux)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseOptions(configFile string) (*config.Options, error) {
|
func parseOptions(configFile string) (config.Options, error) {
|
||||||
o, err := config.OptionsFromViper(configFile)
|
o, err := config.OptionsFromViper(configFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return o, err
|
||||||
}
|
}
|
||||||
if o.Debug {
|
if o.Debug {
|
||||||
log.SetDebugMode()
|
log.SetDebugMode()
|
||||||
|
@ -192,7 +192,7 @@ func parseOptions(configFile string) (*config.Options, error) {
|
||||||
return o, nil
|
return o, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleConfigUpdate(opt *config.Options, services []config.OptionsUpdater) *config.Options {
|
func handleConfigUpdate(opt config.Options, services []config.OptionsUpdater) config.Options {
|
||||||
newOpt, err := parseOptions(*configFile)
|
newOpt, err := parseOptions(*configFile)
|
||||||
optChecksum := opt.Checksum()
|
optChecksum := opt.Checksum()
|
||||||
newOptChecksum := newOpt.Checksum()
|
newOptChecksum := newOpt.Checksum()
|
||||||
|
|
|
@ -78,11 +78,11 @@ func Test_newAuthenticateService(t *testing.T) {
|
||||||
testOpts.ClientSecret = "TEST"
|
testOpts.ClientSecret = "TEST"
|
||||||
testOpts.SharedKey = "YixWi1MYh77NMECGGIJQevoonYtVF+ZPRkQZrrmeRqM="
|
testOpts.SharedKey = "YixWi1MYh77NMECGGIJQevoonYtVF+ZPRkQZrrmeRqM="
|
||||||
testOpts.CookieSecret = "YixWi1MYh77NMECGGIJQevoonYtVF+ZPRkQZrrmeRqM="
|
testOpts.CookieSecret = "YixWi1MYh77NMECGGIJQevoonYtVF+ZPRkQZrrmeRqM="
|
||||||
testOpts.AuthenticateURL = authURL
|
testOpts.AuthenticateURL = *authURL
|
||||||
testOpts.Services = tt.s
|
testOpts.Services = tt.s
|
||||||
|
|
||||||
if tt.Field != "" {
|
if tt.Field != "" {
|
||||||
testOptsField := reflect.ValueOf(testOpts).Elem().FieldByName(tt.Field)
|
testOptsField := reflect.ValueOf(&testOpts).Elem().FieldByName(tt.Field)
|
||||||
testOptsField.Set(reflect.ValueOf(tt).FieldByName("Value"))
|
testOptsField.Set(reflect.ValueOf(tt).FieldByName("Value"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ func Test_newAuthorizeService(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if tt.Field != "" {
|
if tt.Field != "" {
|
||||||
testOptsField := reflect.ValueOf(testOpts).Elem().FieldByName(tt.Field)
|
testOptsField := reflect.ValueOf(&testOpts).Elem().FieldByName(tt.Field)
|
||||||
testOptsField.Set(reflect.ValueOf(tt).FieldByName("Value"))
|
testOptsField.Set(reflect.ValueOf(tt).FieldByName("Value"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,13 +162,17 @@ func Test_newProxyeService(t *testing.T) {
|
||||||
testOpts.Policies = []policy.Policy{
|
testOpts.Policies = []policy.Policy{
|
||||||
testPolicy,
|
testPolicy,
|
||||||
}
|
}
|
||||||
testOpts.AuthenticateURL, _ = url.Parse("https://authenticate.example.com")
|
|
||||||
testOpts.AuthorizeURL, _ = url.Parse("https://authorize.example.com")
|
AuthenticateURL, _ := url.Parse("https://authenticate.example.com")
|
||||||
|
AuthorizeURL, _ := url.Parse("https://authorize.example.com")
|
||||||
|
|
||||||
|
testOpts.AuthenticateURL = *AuthenticateURL
|
||||||
|
testOpts.AuthorizeURL = *AuthorizeURL
|
||||||
testOpts.CookieSecret = "YixWi1MYh77NMECGGIJQevoonYtVF+ZPRkQZrrmeRqM="
|
testOpts.CookieSecret = "YixWi1MYh77NMECGGIJQevoonYtVF+ZPRkQZrrmeRqM="
|
||||||
testOpts.Services = tt.s
|
testOpts.Services = tt.s
|
||||||
|
|
||||||
if tt.Field != "" {
|
if tt.Field != "" {
|
||||||
testOptsField := reflect.ValueOf(testOpts).Elem().FieldByName(tt.Field)
|
testOptsField := reflect.ValueOf(&testOpts).Elem().FieldByName(tt.Field)
|
||||||
testOptsField.Set(reflect.ValueOf(tt).FieldByName("Value"))
|
testOptsField.Set(reflect.ValueOf(tt).FieldByName("Value"))
|
||||||
}
|
}
|
||||||
_, err := newProxyService(testOpts, mux)
|
_, err := newProxyService(testOpts, mux)
|
||||||
|
@ -181,7 +185,7 @@ func Test_newProxyeService(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_wrapMiddleware(t *testing.T) {
|
func Test_wrapMiddleware(t *testing.T) {
|
||||||
o := &config.Options{
|
o := config.Options{
|
||||||
Services: "all",
|
Services: "all",
|
||||||
Headers: map[string]string{
|
Headers: map[string]string{
|
||||||
"X-Content-Type-Options": "nosniff",
|
"X-Content-Type-Options": "nosniff",
|
||||||
|
@ -232,7 +236,7 @@ func Test_parseOptions(t *testing.T) {
|
||||||
t.Errorf("parseOptions() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("parseOptions() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if got != nil && got.SharedKey != tt.wantSharedKey {
|
if got.SharedKey != tt.wantSharedKey {
|
||||||
t.Errorf("parseOptions()\n")
|
t.Errorf("parseOptions()\n")
|
||||||
t.Errorf("got: %+v\n", got.SharedKey)
|
t.Errorf("got: %+v\n", got.SharedKey)
|
||||||
t.Errorf("want: %+v\n", tt.wantSharedKey)
|
t.Errorf("want: %+v\n", tt.wantSharedKey)
|
||||||
|
@ -247,7 +251,7 @@ type mockService struct {
|
||||||
Updated bool
|
Updated bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockService) UpdateOptions(o *config.Options) error {
|
func (m *mockService) UpdateOptions(o config.Options) error {
|
||||||
|
|
||||||
m.Updated = true
|
m.Updated = true
|
||||||
if m.fail {
|
if m.fail {
|
||||||
|
@ -266,7 +270,7 @@ func Test_handleConfigUpdate(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
service *mockService
|
service *mockService
|
||||||
oldOpts *config.Options
|
oldOpts config.Options
|
||||||
wantUpdate bool
|
wantUpdate bool
|
||||||
}{
|
}{
|
||||||
{"good", &mockService{fail: false}, blankOpts, true},
|
{"good", &mockService{fail: false}, blankOpts, true},
|
||||||
|
|
|
@ -70,8 +70,8 @@ type Options struct {
|
||||||
|
|
||||||
// AuthenticateURL represents the externally accessible http endpoints
|
// AuthenticateURL represents the externally accessible http endpoints
|
||||||
// used for authentication requests and callbacks
|
// used for authentication requests and callbacks
|
||||||
AuthenticateURLString string `mapstructure:"authenticate_service_url"`
|
AuthenticateURLString string `mapstructure:"authenticate_service_url"`
|
||||||
AuthenticateURL *url.URL `hash:"ignore"`
|
AuthenticateURL url.URL
|
||||||
|
|
||||||
// Session/Cookie management
|
// Session/Cookie management
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
|
||||||
|
@ -103,13 +103,13 @@ type Options struct {
|
||||||
// NOTE: As many load balancers do not support externally routed gRPC so
|
// NOTE: As many load balancers do not support externally routed gRPC so
|
||||||
// this may be an internal location.
|
// this may be an internal location.
|
||||||
AuthenticateInternalAddrString string `mapstructure:"authenticate_internal_url"`
|
AuthenticateInternalAddrString string `mapstructure:"authenticate_internal_url"`
|
||||||
AuthenticateInternalAddr *url.URL
|
AuthenticateInternalAddr url.URL
|
||||||
|
|
||||||
// AuthorizeURL is the routable destination of the authorize service's
|
// AuthorizeURL is the routable destination of the authorize service's
|
||||||
// gRPC endpoint. NOTE: As many load balancers do not support
|
// gRPC endpoint. NOTE: As many load balancers do not support
|
||||||
// externally routed gRPC so this may be an internal location.
|
// externally routed gRPC so this may be an internal location.
|
||||||
AuthorizeURLString string `mapstructure:"authorize_service_url"`
|
AuthorizeURLString string `mapstructure:"authorize_service_url"`
|
||||||
AuthorizeURL *url.URL
|
AuthorizeURL url.URL
|
||||||
|
|
||||||
// Settings to enable custom behind-the-ingress service communication
|
// Settings to enable custom behind-the-ingress service communication
|
||||||
OverrideCertificateName string `mapstructure:"override_certificate_name"`
|
OverrideCertificateName string `mapstructure:"override_certificate_name"`
|
||||||
|
@ -136,8 +136,8 @@ type Options struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewOptions returns a new options struct with default values
|
// NewOptions returns a new options struct with default values
|
||||||
func NewOptions() *Options {
|
func NewOptions() Options {
|
||||||
o := &Options{
|
o := Options{
|
||||||
Debug: false,
|
Debug: false,
|
||||||
LogLevel: "debug",
|
LogLevel: "debug",
|
||||||
Services: "all",
|
Services: "all",
|
||||||
|
@ -153,25 +153,22 @@ func NewOptions() *Options {
|
||||||
"X-XSS-Protection": "1; mode=block",
|
"X-XSS-Protection": "1; mode=block",
|
||||||
"Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload",
|
"Strict-Transport-Security": "max-age=31536000; includeSubDomains; preload",
|
||||||
},
|
},
|
||||||
Addr: ":https",
|
Addr: ":https",
|
||||||
CertFile: filepath.Join(findPwd(), "cert.pem"),
|
CertFile: filepath.Join(findPwd(), "cert.pem"),
|
||||||
KeyFile: filepath.Join(findPwd(), "privkey.pem"),
|
KeyFile: filepath.Join(findPwd(), "privkey.pem"),
|
||||||
ReadHeaderTimeout: 10 * time.Second,
|
ReadHeaderTimeout: 10 * time.Second,
|
||||||
ReadTimeout: 30 * time.Second,
|
ReadTimeout: 30 * time.Second,
|
||||||
WriteTimeout: 0, // support streaming by default
|
WriteTimeout: 0, // support streaming by default
|
||||||
IdleTimeout: 5 * time.Minute,
|
IdleTimeout: 5 * time.Minute,
|
||||||
AuthenticateURL: new(url.URL),
|
RefreshCooldown: time.Duration(5 * time.Minute),
|
||||||
AuthenticateInternalAddr: new(url.URL),
|
AllowWebsockets: false,
|
||||||
AuthorizeURL: new(url.URL),
|
|
||||||
RefreshCooldown: time.Duration(5 * time.Minute),
|
|
||||||
AllowWebsockets: false,
|
|
||||||
}
|
}
|
||||||
return o
|
return o
|
||||||
}
|
}
|
||||||
|
|
||||||
// OptionsFromViper builds the main binary's configuration
|
// OptionsFromViper builds the main binary's configuration
|
||||||
// options by parsing environmental variables and config file
|
// options by parsing environmental variables and config file
|
||||||
func OptionsFromViper(configFile string) (*Options, error) {
|
func OptionsFromViper(configFile string) (Options, error) {
|
||||||
o := NewOptions()
|
o := NewOptions()
|
||||||
|
|
||||||
// Load up config
|
// Load up config
|
||||||
|
@ -184,25 +181,25 @@ func OptionsFromViper(configFile string) (*Options, error) {
|
||||||
viper.SetConfigFile(configFile)
|
viper.SetConfigFile(configFile)
|
||||||
err := viper.ReadInConfig()
|
err := viper.ReadInConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to read config: %s", err)
|
return o, fmt.Errorf("failed to read config: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := viper.Unmarshal(o)
|
err := viper.Unmarshal(&o)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to load options from config: %s", err)
|
return o, fmt.Errorf("failed to load options from config: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Turn URL strings into url structs
|
// Turn URL strings into url structs
|
||||||
err = o.parseURLs()
|
err = o.parseURLs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse URLs: %s", err)
|
return o, fmt.Errorf("failed to parse URLs: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load and initialize policy
|
// Load and initialize policy
|
||||||
err = o.parsePolicy()
|
err = o.parsePolicy()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse Policy: %s", err)
|
return o, fmt.Errorf("failed to parse Policy: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.Debug {
|
if o.Debug {
|
||||||
|
@ -217,7 +214,7 @@ func OptionsFromViper(configFile string) (*Options, error) {
|
||||||
|
|
||||||
err = o.validate()
|
err = o.validate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return o, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug().
|
log.Debug().
|
||||||
|
@ -302,7 +299,7 @@ func (o *Options) parseURLs() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("internal/config: bad authenticate-url %s : %v", o.AuthenticateURLString, err)
|
return fmt.Errorf("internal/config: bad authenticate-url %s : %v", o.AuthenticateURLString, err)
|
||||||
}
|
}
|
||||||
o.AuthenticateURL = AuthenticateURL
|
o.AuthenticateURL = *AuthenticateURL
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.AuthorizeURLString != "" {
|
if o.AuthorizeURLString != "" {
|
||||||
|
@ -310,7 +307,7 @@ func (o *Options) parseURLs() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("internal/config: bad authorize-url %s : %v", o.AuthorizeURLString, err)
|
return fmt.Errorf("internal/config: bad authorize-url %s : %v", o.AuthorizeURLString, err)
|
||||||
}
|
}
|
||||||
o.AuthorizeURL = AuthorizeURL
|
o.AuthorizeURL = *AuthorizeURL
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.AuthenticateInternalAddrString != "" {
|
if o.AuthenticateInternalAddrString != "" {
|
||||||
|
@ -318,7 +315,7 @@ func (o *Options) parseURLs() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("internal/config: bad authenticate-internal-addr %s : %v", o.AuthenticateInternalAddrString, err)
|
return fmt.Errorf("internal/config: bad authenticate-internal-addr %s : %v", o.AuthenticateInternalAddrString, err)
|
||||||
}
|
}
|
||||||
o.AuthenticateInternalAddr = AuthenticateInternalAddr
|
o.AuthenticateInternalAddr = *AuthenticateInternalAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -396,7 +393,7 @@ func IsProxy(s string) bool {
|
||||||
|
|
||||||
// OptionsUpdater updates local state based on an Options struct
|
// OptionsUpdater updates local state based on an Options struct
|
||||||
type OptionsUpdater interface {
|
type OptionsUpdater interface {
|
||||||
UpdateOptions(*Options) error
|
UpdateOptions(Options) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checksum returns the checksum of the current options struct
|
// Checksum returns the checksum of the current options struct
|
||||||
|
|
|
@ -16,7 +16,7 @@ import (
|
||||||
|
|
||||||
func Test_validate(t *testing.T) {
|
func Test_validate(t *testing.T) {
|
||||||
|
|
||||||
testOptions := func() *Options {
|
testOptions := func() Options {
|
||||||
o := NewOptions()
|
o := NewOptions()
|
||||||
o.SharedKey = "test"
|
o.SharedKey = "test"
|
||||||
o.Services = "all"
|
o.Services = "all"
|
||||||
|
@ -34,7 +34,7 @@ func Test_validate(t *testing.T) {
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
testOpts *Options
|
testOpts Options
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{"good default with no env settings", good, false},
|
{"good default with no env settings", good, false},
|
||||||
|
@ -194,10 +194,10 @@ func Test_parseURLs(t *testing.T) {
|
||||||
if (err != nil) != test.wantErr {
|
if (err != nil) != test.wantErr {
|
||||||
t.Errorf("Failed to parse URLs %v: %s", test, err)
|
t.Errorf("Failed to parse URLs %v: %s", test, err)
|
||||||
}
|
}
|
||||||
if o.AuthenticateURL != nil && o.AuthenticateURL.String() != test.authenticateURL {
|
if err == nil && o.AuthenticateURL.String() != test.authenticateURL {
|
||||||
t.Errorf("Failed to update AuthenticateURL: %v", test)
|
t.Errorf("Failed to update AuthenticateURL: %v", test)
|
||||||
}
|
}
|
||||||
if o.AuthorizeURL != nil && o.AuthorizeURL.String() != test.authorizeURL {
|
if err == nil && o.AuthorizeURL.String() != test.authorizeURL {
|
||||||
t.Errorf("Failed to update AuthorizeURL: %v", test)
|
t.Errorf("Failed to update AuthorizeURL: %v", test)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -230,8 +230,8 @@ func Test_OptionsFromViper(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
goodOptions.AuthorizeURL = authorize
|
goodOptions.AuthorizeURL = *authorize
|
||||||
goodOptions.AuthenticateURL = authenticate
|
goodOptions.AuthenticateURL = *authenticate
|
||||||
|
|
||||||
badConfigBytes := []byte("badjson!")
|
badConfigBytes := []byte("badjson!")
|
||||||
badUnmarshalConfigBytes := []byte(`"debug": "blue"`)
|
badUnmarshalConfigBytes := []byte(`"debug": "blue"`)
|
||||||
|
@ -239,12 +239,12 @@ func Test_OptionsFromViper(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
configBytes []byte
|
configBytes []byte
|
||||||
want *Options
|
want Options
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{"good", goodConfigBytes, goodOptions, false},
|
{"good", goodConfigBytes, goodOptions, false},
|
||||||
{"bad json", badConfigBytes, nil, true},
|
{"bad json", badConfigBytes, NewOptions(), true},
|
||||||
{"bad unmarshal", badUnmarshalConfigBytes, nil, true},
|
{"bad unmarshal", badUnmarshalConfigBytes, NewOptions(), true},
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
@ -268,8 +268,8 @@ func Test_OptionsFromViper(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test for missing config file
|
// Test for missing config file
|
||||||
o, err := OptionsFromViper("filedoesnotexist")
|
_, err = OptionsFromViper("filedoesnotexist")
|
||||||
if o != nil || err == nil {
|
if err == nil {
|
||||||
t.Errorf("OptionsFromViper(): Did when loading missing file")
|
t.Errorf("OptionsFromViper(): Did when loading missing file")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pomerium/pomerium/internal/config"
|
"github.com/pomerium/pomerium/internal/config"
|
||||||
|
|
||||||
"github.com/pomerium/pomerium/internal/cryptutil"
|
"github.com/pomerium/pomerium/internal/cryptutil"
|
||||||
"github.com/pomerium/pomerium/internal/httputil"
|
"github.com/pomerium/pomerium/internal/httputil"
|
||||||
"github.com/pomerium/pomerium/internal/log"
|
"github.com/pomerium/pomerium/internal/log"
|
||||||
|
@ -529,7 +530,7 @@ func extendDeadline(ttl time.Duration) time.Time {
|
||||||
}
|
}
|
||||||
|
|
||||||
// websocketHandlerFunc splits request serving with timeouts depending on the protocol
|
// websocketHandlerFunc splits request serving with timeouts depending on the protocol
|
||||||
func websocketHandlerFunc(baseHandler http.Handler, timeoutHandler http.Handler, o *config.Options) http.Handler {
|
func websocketHandlerFunc(baseHandler http.Handler, timeoutHandler http.Handler, o config.Options) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
// Do not use timeouts for websockets because they are long-lived connections.
|
// Do not use timeouts for websockets because they are long-lived connections.
|
||||||
|
|
|
@ -290,7 +290,7 @@ func TestProxy_Proxy(t *testing.T) {
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
options *config.Options
|
options config.Options
|
||||||
method string
|
method string
|
||||||
header http.Header
|
header http.Header
|
||||||
host string
|
host string
|
||||||
|
@ -356,7 +356,7 @@ func TestProxy_UserDashboard(t *testing.T) {
|
||||||
opts := testOptions()
|
opts := testOptions()
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
options *config.Options
|
options config.Options
|
||||||
method string
|
method string
|
||||||
cipher cryptutil.Cipher
|
cipher cryptutil.Cipher
|
||||||
session sessions.SessionStore
|
session sessions.SessionStore
|
||||||
|
@ -408,7 +408,7 @@ func TestProxy_Refresh(t *testing.T) {
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
options *config.Options
|
options config.Options
|
||||||
method string
|
method string
|
||||||
cipher cryptutil.Cipher
|
cipher cryptutil.Cipher
|
||||||
session sessions.SessionStore
|
session sessions.SessionStore
|
||||||
|
@ -452,7 +452,7 @@ func TestProxy_Impersonate(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
malformed bool
|
malformed bool
|
||||||
options *config.Options
|
options config.Options
|
||||||
method string
|
method string
|
||||||
email string
|
email string
|
||||||
groups string
|
groups string
|
||||||
|
|
|
@ -35,7 +35,7 @@ const (
|
||||||
|
|
||||||
// ValidateOptions checks that proper configuration settings are set to create
|
// ValidateOptions checks that proper configuration settings are set to create
|
||||||
// a proper Proxy instance
|
// a proper Proxy instance
|
||||||
func ValidateOptions(o *config.Options) error {
|
func ValidateOptions(o config.Options) error {
|
||||||
decoded, err := base64.StdEncoding.DecodeString(o.SharedKey)
|
decoded, err := base64.StdEncoding.DecodeString(o.SharedKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("authorize: `SHARED_SECRET` setting is invalid base64: %v", err)
|
return fmt.Errorf("authorize: `SHARED_SECRET` setting is invalid base64: %v", err)
|
||||||
|
@ -46,13 +46,13 @@ func ValidateOptions(o *config.Options) error {
|
||||||
if len(o.Policies) == 0 {
|
if len(o.Policies) == 0 {
|
||||||
return errors.New("missing setting: no policies defined")
|
return errors.New("missing setting: no policies defined")
|
||||||
}
|
}
|
||||||
if o.AuthenticateURL == nil {
|
if o.AuthenticateURL.String() == "" {
|
||||||
return errors.New("missing setting: authenticate-service-url")
|
return errors.New("missing setting: authenticate-service-url")
|
||||||
}
|
}
|
||||||
if o.AuthenticateURL.Scheme != "https" {
|
if o.AuthenticateURL.Scheme != "https" {
|
||||||
return errors.New("authenticate-service-url must be a valid https url")
|
return errors.New("authenticate-service-url must be a valid https url")
|
||||||
}
|
}
|
||||||
if o.AuthorizeURL == nil {
|
if o.AuthorizeURL.String() == "" {
|
||||||
return errors.New("missing setting: authorize-service-url")
|
return errors.New("missing setting: authorize-service-url")
|
||||||
}
|
}
|
||||||
if o.AuthorizeURL.Scheme != "https" {
|
if o.AuthorizeURL.Scheme != "https" {
|
||||||
|
@ -106,10 +106,7 @@ type routeConfig struct {
|
||||||
|
|
||||||
// New takes a Proxy service from options and a validation function.
|
// New takes a Proxy service from options and a validation function.
|
||||||
// Function returns an error if options fail to validate.
|
// Function returns an error if options fail to validate.
|
||||||
func New(opts *config.Options) (*Proxy, error) {
|
func New(opts config.Options) (*Proxy, error) {
|
||||||
if opts == nil {
|
|
||||||
return nil, errors.New("options cannot be nil")
|
|
||||||
}
|
|
||||||
if err := ValidateOptions(opts); err != nil {
|
if err := ValidateOptions(opts); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -137,7 +134,7 @@ func New(opts *config.Options) (*Proxy, error) {
|
||||||
p := &Proxy{
|
p := &Proxy{
|
||||||
routeConfigs: make(map[string]*routeConfig),
|
routeConfigs: make(map[string]*routeConfig),
|
||||||
// services
|
// services
|
||||||
AuthenticateURL: opts.AuthenticateURL,
|
AuthenticateURL: &opts.AuthenticateURL,
|
||||||
// session state
|
// session state
|
||||||
cipher: cipher,
|
cipher: cipher,
|
||||||
csrfStore: cookieStore,
|
csrfStore: cookieStore,
|
||||||
|
@ -177,7 +174,7 @@ func New(opts *config.Options) (*Proxy, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdatePolicies updates the handlers based on the configured policies
|
// UpdatePolicies updates the handlers based on the configured policies
|
||||||
func (p *Proxy) UpdatePolicies(opts *config.Options) error {
|
func (p *Proxy) UpdatePolicies(opts config.Options) error {
|
||||||
routeConfigs := make(map[string]*routeConfig)
|
routeConfigs := make(map[string]*routeConfig)
|
||||||
for _, route := range opts.Policies {
|
for _, route := range opts.Policies {
|
||||||
proxy := NewReverseProxy(route.Destination)
|
proxy := NewReverseProxy(route.Destination)
|
||||||
|
@ -254,7 +251,7 @@ func NewReverseProxy(to *url.URL) *httputil.ReverseProxy {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewReverseProxyHandler applies handler specific options to a given route.
|
// NewReverseProxyHandler applies handler specific options to a given route.
|
||||||
func NewReverseProxyHandler(o *config.Options, proxy *httputil.ReverseProxy, route *policy.Policy) (http.Handler, error) {
|
func NewReverseProxyHandler(o config.Options, proxy *httputil.ReverseProxy, route *policy.Policy) (http.Handler, error) {
|
||||||
up := &UpstreamProxy{
|
up := &UpstreamProxy{
|
||||||
name: route.Destination.Host,
|
name: route.Destination.Host,
|
||||||
handler: proxy,
|
handler: proxy,
|
||||||
|
@ -287,7 +284,7 @@ func urlParse(uri string) (*url.URL, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateOptions updates internal structres based on config.Options
|
// UpdateOptions updates internal structres based on config.Options
|
||||||
func (p *Proxy) UpdateOptions(o *config.Options) error {
|
func (p *Proxy) UpdateOptions(o config.Options) error {
|
||||||
log.Info().Msg("proxy: updating options")
|
log.Info().Msg("proxy: updating options")
|
||||||
err := p.UpdatePolicies(o)
|
err := p.UpdatePolicies(o)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -80,7 +80,7 @@ func TestNewReverseProxyHandler(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testOptions() *config.Options {
|
func testOptions() config.Options {
|
||||||
authenticateService, _ := url.Parse("https://authenticate.corp.beyondperimeter.com")
|
authenticateService, _ := url.Parse("https://authenticate.corp.beyondperimeter.com")
|
||||||
authorizeService, _ := url.Parse("https://authorize.corp.beyondperimeter.com")
|
authorizeService, _ := url.Parse("https://authorize.corp.beyondperimeter.com")
|
||||||
|
|
||||||
|
@ -88,15 +88,15 @@ func testOptions() *config.Options {
|
||||||
testPolicy := policy.Policy{From: "corp.example.notatld", To: "example.notatld"}
|
testPolicy := policy.Policy{From: "corp.example.notatld", To: "example.notatld"}
|
||||||
testPolicy.Validate()
|
testPolicy.Validate()
|
||||||
opts.Policies = []policy.Policy{testPolicy}
|
opts.Policies = []policy.Policy{testPolicy}
|
||||||
opts.AuthenticateURL = authenticateService
|
opts.AuthenticateURL = *authenticateService
|
||||||
opts.AuthorizeURL = authorizeService
|
opts.AuthorizeURL = *authorizeService
|
||||||
opts.SharedKey = "80ldlrU2d7w+wVpKNfevk6fmb8otEx6CqOfshj2LwhQ="
|
opts.SharedKey = "80ldlrU2d7w+wVpKNfevk6fmb8otEx6CqOfshj2LwhQ="
|
||||||
opts.CookieSecret = "OromP1gurwGWjQPYb1nNgSxtbVB5NnLzX6z5WOKr0Yw="
|
opts.CookieSecret = "OromP1gurwGWjQPYb1nNgSxtbVB5NnLzX6z5WOKr0Yw="
|
||||||
opts.CookieName = "pomerium"
|
opts.CookieName = "pomerium"
|
||||||
return opts
|
return opts
|
||||||
}
|
}
|
||||||
|
|
||||||
func testOptionsTestServer(uri string) *config.Options {
|
func testOptionsTestServer(uri string) config.Options {
|
||||||
authenticateService, _ := url.Parse("https://authenticate.corp.beyondperimeter.com")
|
authenticateService, _ := url.Parse("https://authenticate.corp.beyondperimeter.com")
|
||||||
authorizeService, _ := url.Parse("https://authorize.corp.beyondperimeter.com")
|
authorizeService, _ := url.Parse("https://authorize.corp.beyondperimeter.com")
|
||||||
// RFC 2606
|
// RFC 2606
|
||||||
|
@ -107,15 +107,15 @@ func testOptionsTestServer(uri string) *config.Options {
|
||||||
testPolicy.Validate()
|
testPolicy.Validate()
|
||||||
opts := config.NewOptions()
|
opts := config.NewOptions()
|
||||||
opts.Policies = []policy.Policy{testPolicy}
|
opts.Policies = []policy.Policy{testPolicy}
|
||||||
opts.AuthenticateURL = authenticateService
|
opts.AuthenticateURL = *authenticateService
|
||||||
opts.AuthorizeURL = authorizeService
|
opts.AuthorizeURL = *authorizeService
|
||||||
opts.SharedKey = "80ldlrU2d7w+wVpKNfevk6fmb8otEx6CqOfshj2LwhQ="
|
opts.SharedKey = "80ldlrU2d7w+wVpKNfevk6fmb8otEx6CqOfshj2LwhQ="
|
||||||
opts.CookieSecret = "OromP1gurwGWjQPYb1nNgSxtbVB5NnLzX6z5WOKr0Yw="
|
opts.CookieSecret = "OromP1gurwGWjQPYb1nNgSxtbVB5NnLzX6z5WOKr0Yw="
|
||||||
opts.CookieName = "pomerium"
|
opts.CookieName = "pomerium"
|
||||||
return opts
|
return opts
|
||||||
}
|
}
|
||||||
|
|
||||||
func testOptionsWithCORS(uri string) *config.Options {
|
func testOptionsWithCORS(uri string) config.Options {
|
||||||
testPolicy := policy.Policy{
|
testPolicy := policy.Policy{
|
||||||
From: "httpbin.corp.example",
|
From: "httpbin.corp.example",
|
||||||
To: uri,
|
To: uri,
|
||||||
|
@ -127,7 +127,7 @@ func testOptionsWithCORS(uri string) *config.Options {
|
||||||
return opts
|
return opts
|
||||||
}
|
}
|
||||||
|
|
||||||
func testOptionsWithPublicAccess(uri string) *config.Options {
|
func testOptionsWithPublicAccess(uri string) config.Options {
|
||||||
testPolicy := policy.Policy{
|
testPolicy := policy.Policy{
|
||||||
From: "httpbin.corp.example",
|
From: "httpbin.corp.example",
|
||||||
To: uri,
|
To: uri,
|
||||||
|
@ -139,7 +139,7 @@ func testOptionsWithPublicAccess(uri string) *config.Options {
|
||||||
return opts
|
return opts
|
||||||
}
|
}
|
||||||
|
|
||||||
func testOptionsWithPublicAccessAndWhitelist(uri string) *config.Options {
|
func testOptionsWithPublicAccessAndWhitelist(uri string) config.Options {
|
||||||
testPolicy := policy.Policy{
|
testPolicy := policy.Policy{
|
||||||
From: "httpbin.corp.example",
|
From: "httpbin.corp.example",
|
||||||
To: uri,
|
To: uri,
|
||||||
|
@ -155,14 +155,14 @@ func testOptionsWithPublicAccessAndWhitelist(uri string) *config.Options {
|
||||||
func TestOptions_Validate(t *testing.T) {
|
func TestOptions_Validate(t *testing.T) {
|
||||||
good := testOptions()
|
good := testOptions()
|
||||||
badAuthURL := testOptions()
|
badAuthURL := testOptions()
|
||||||
badAuthURL.AuthenticateURL = nil
|
badAuthURL.AuthenticateURL = url.URL{}
|
||||||
authurl, _ := url.Parse("http://authenticate.corp.beyondperimeter.com")
|
authurl, _ := url.Parse("http://authenticate.corp.beyondperimeter.com")
|
||||||
authenticateBadScheme := testOptions()
|
authenticateBadScheme := testOptions()
|
||||||
authenticateBadScheme.AuthenticateURL = authurl
|
authenticateBadScheme.AuthenticateURL = *authurl
|
||||||
authorizeBadSCheme := testOptions()
|
authorizeBadSCheme := testOptions()
|
||||||
authorizeBadSCheme.AuthorizeURL = authurl
|
authorizeBadSCheme.AuthorizeURL = *authurl
|
||||||
authorizeNil := testOptions()
|
authorizeNil := testOptions()
|
||||||
authorizeNil.AuthorizeURL = nil
|
authorizeNil.AuthorizeURL = url.URL{}
|
||||||
emptyCookieSecret := testOptions()
|
emptyCookieSecret := testOptions()
|
||||||
emptyCookieSecret.CookieSecret = ""
|
emptyCookieSecret.CookieSecret = ""
|
||||||
invalidCookieSecret := testOptions()
|
invalidCookieSecret := testOptions()
|
||||||
|
@ -178,11 +178,11 @@ func TestOptions_Validate(t *testing.T) {
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
o *config.Options
|
o config.Options
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{"good - minimum options", good, false},
|
{"good - minimum options", good, false},
|
||||||
{"nil options", &config.Options{}, true},
|
{"nil options", config.Options{}, true},
|
||||||
{"authenticate service url", badAuthURL, true},
|
{"authenticate service url", badAuthURL, true},
|
||||||
{"authenticate service url not https", authenticateBadScheme, true},
|
{"authenticate service url not https", authenticateBadScheme, true},
|
||||||
{"authorize service url not https", authorizeBadSCheme, true},
|
{"authorize service url not https", authorizeBadSCheme, true},
|
||||||
|
@ -213,14 +213,13 @@ func TestNew(t *testing.T) {
|
||||||
badRoutedProxy.SigningKey = "YmFkIGtleQo="
|
badRoutedProxy.SigningKey = "YmFkIGtleQo="
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
opts *config.Options
|
opts config.Options
|
||||||
wantProxy bool
|
wantProxy bool
|
||||||
numRoutes int
|
numRoutes int
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{"good", good, true, 1, false},
|
{"good", good, true, 1, false},
|
||||||
{"empty options", &config.Options{}, false, 0, true},
|
{"empty options", config.Options{}, false, 0, true},
|
||||||
{"nil options", nil, false, 0, true},
|
|
||||||
{"short secret/validate sanity check", shortCookieLength, false, 0, true},
|
{"short secret/validate sanity check", shortCookieLength, false, 0, true},
|
||||||
{"invalid ec key, valid base64 though", badRoutedProxy, false, 0, true},
|
{"invalid ec key, valid base64 though", badRoutedProxy, false, 0, true},
|
||||||
}
|
}
|
||||||
|
@ -296,7 +295,7 @@ func Test_UpdateOptions(t *testing.T) {
|
||||||
}
|
}
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
opts *config.Options
|
opts config.Options
|
||||||
newPolicy []policy.Policy
|
newPolicy []policy.Policy
|
||||||
host string
|
host string
|
||||||
wantErr bool
|
wantErr bool
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue