mirror of
https://github.com/oauth2-proxy/oauth2-proxy.git
synced 2025-03-23 21:50:48 +02:00
Move Options and Validation to package
This commit is contained in:
parent
de0c92af06
commit
44b27e0208
5
http.go
5
http.go
@ -9,13 +9,14 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Server represents an HTTP server
|
// Server represents an HTTP server
|
||||||
type Server struct {
|
type Server struct {
|
||||||
Handler http.Handler
|
Handler http.Handler
|
||||||
Opts *Options
|
Opts *options.Options
|
||||||
stop chan struct{} // channel for waiting shutdown
|
stop chan struct{} // channel for waiting shutdown
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,7 +168,7 @@ func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
|
|||||||
return tc, nil
|
return tc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func redirectToHTTPS(opts *Options, h http.Handler) http.Handler {
|
func redirectToHTTPS(opts *options.Options, h http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
proto := r.Header.Get("X-Forwarded-Proto")
|
proto := r.Header.Get("X-Forwarded-Proto")
|
||||||
if opts.ForceHTTPS && (r.TLS == nil || (proto != "" && strings.ToLower(proto) != "https")) {
|
if opts.ForceHTTPS && (r.TLS == nil || (proto != "" && strings.ToLower(proto) != "https")) {
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -110,7 +111,7 @@ func TestGCPHealthcheckNotIngressPut(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRedirectToHTTPSTrue(t *testing.T) {
|
func TestRedirectToHTTPSTrue(t *testing.T) {
|
||||||
opts := NewOptions()
|
opts := options.NewOptions()
|
||||||
opts.ForceHTTPS = true
|
opts.ForceHTTPS = true
|
||||||
handler := func(w http.ResponseWriter, req *http.Request) {
|
handler := func(w http.ResponseWriter, req *http.Request) {
|
||||||
w.Write([]byte("test"))
|
w.Write([]byte("test"))
|
||||||
@ -125,7 +126,7 @@ func TestRedirectToHTTPSTrue(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRedirectToHTTPSFalse(t *testing.T) {
|
func TestRedirectToHTTPSFalse(t *testing.T) {
|
||||||
opts := NewOptions()
|
opts := options.NewOptions()
|
||||||
handler := func(w http.ResponseWriter, req *http.Request) {
|
handler := func(w http.ResponseWriter, req *http.Request) {
|
||||||
w.Write([]byte("test"))
|
w.Write([]byte("test"))
|
||||||
}
|
}
|
||||||
@ -139,7 +140,7 @@ func TestRedirectToHTTPSFalse(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRedirectNotWhenHTTPS(t *testing.T) {
|
func TestRedirectNotWhenHTTPS(t *testing.T) {
|
||||||
opts := NewOptions()
|
opts := options.NewOptions()
|
||||||
opts.ForceHTTPS = true
|
opts.ForceHTTPS = true
|
||||||
handler := func(w http.ResponseWriter, req *http.Request) {
|
handler := func(w http.ResponseWriter, req *http.Request) {
|
||||||
w.Write([]byte("test"))
|
w.Write([]byte("test"))
|
||||||
@ -160,7 +161,7 @@ func TestRedirectNotWhenHTTPS(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGracefulShutdown(t *testing.T) {
|
func TestGracefulShutdown(t *testing.T) {
|
||||||
opts := NewOptions()
|
opts := options.NewOptions()
|
||||||
stop := make(chan struct{}, 1)
|
stop := make(chan struct{}, 1)
|
||||||
srv := Server{Handler: http.DefaultServeMux, Opts: opts, stop: stop}
|
srv := Server{Handler: http.DefaultServeMux, Opts: opts, stop: stop}
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
|
5
main.go
5
main.go
@ -13,6 +13,7 @@ import (
|
|||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
||||||
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/validation"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -148,14 +149,14 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
opts := NewOptions()
|
opts := options.NewOptions()
|
||||||
err := options.Load(*config, flagSet, opts)
|
err := options.Load(*config, flagSet, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Printf("ERROR: Failed to load config: %v", err)
|
logger.Printf("ERROR: Failed to load config: %v", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = opts.Validate()
|
err = validation.Validate(opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Printf("%s", err)
|
logger.Printf("%s", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
|
@ -19,6 +19,8 @@ import (
|
|||||||
|
|
||||||
"github.com/coreos/go-oidc"
|
"github.com/coreos/go-oidc"
|
||||||
"github.com/mbland/hmacauth"
|
"github.com/mbland/hmacauth"
|
||||||
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/logging"
|
||||||
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
||||||
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/cookies"
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/cookies"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/encryption"
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/encryption"
|
||||||
@ -112,7 +114,7 @@ type OAuthProxy struct {
|
|||||||
jwtBearerVerifiers []*oidc.IDTokenVerifier
|
jwtBearerVerifiers []*oidc.IDTokenVerifier
|
||||||
compiledRegex []*regexp.Regexp
|
compiledRegex []*regexp.Regexp
|
||||||
templates *template.Template
|
templates *template.Template
|
||||||
realClientIPParser realClientIPParser
|
realClientIPParser logging.RealClientIPParser
|
||||||
Banner string
|
Banner string
|
||||||
Footer string
|
Footer string
|
||||||
}
|
}
|
||||||
@ -143,7 +145,7 @@ func (u *UpstreamProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
// NewReverseProxy creates a new reverse proxy for proxying requests to upstream
|
// NewReverseProxy creates a new reverse proxy for proxying requests to upstream
|
||||||
// servers
|
// servers
|
||||||
func NewReverseProxy(target *url.URL, opts *Options) (proxy *httputil.ReverseProxy) {
|
func NewReverseProxy(target *url.URL, opts *options.Options) (proxy *httputil.ReverseProxy) {
|
||||||
proxy = httputil.NewSingleHostReverseProxy(target)
|
proxy = httputil.NewSingleHostReverseProxy(target)
|
||||||
proxy.FlushInterval = opts.FlushInterval
|
proxy.FlushInterval = opts.FlushInterval
|
||||||
if opts.SSLUpstreamInsecureSkipVerify {
|
if opts.SSLUpstreamInsecureSkipVerify {
|
||||||
@ -181,7 +183,7 @@ func NewFileServer(path string, filesystemPath string) (proxy http.Handler) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewWebSocketOrRestReverseProxy creates a reverse proxy for REST or websocket based on url
|
// NewWebSocketOrRestReverseProxy creates a reverse proxy for REST or websocket based on url
|
||||||
func NewWebSocketOrRestReverseProxy(u *url.URL, opts *Options, auth hmacauth.HmacAuth) http.Handler {
|
func NewWebSocketOrRestReverseProxy(u *url.URL, opts *options.Options, auth hmacauth.HmacAuth) http.Handler {
|
||||||
u.Path = ""
|
u.Path = ""
|
||||||
proxy := NewReverseProxy(u, opts)
|
proxy := NewReverseProxy(u, opts)
|
||||||
if !opts.PassHostHeader {
|
if !opts.PassHostHeader {
|
||||||
@ -209,14 +211,14 @@ func NewWebSocketOrRestReverseProxy(u *url.URL, opts *Options, auth hmacauth.Hma
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewOAuthProxy creates a new instance of OAuthProxy from the options provided
|
// NewOAuthProxy creates a new instance of OAuthProxy from the options provided
|
||||||
func NewOAuthProxy(opts *Options, validator func(string) bool) *OAuthProxy {
|
func NewOAuthProxy(opts *options.Options, validator func(string) bool) *OAuthProxy {
|
||||||
serveMux := http.NewServeMux()
|
serveMux := http.NewServeMux()
|
||||||
var auth hmacauth.HmacAuth
|
var auth hmacauth.HmacAuth
|
||||||
if sigData := opts.signatureData; sigData != nil {
|
if sigData := opts.GetSignatureData(); sigData != nil {
|
||||||
auth = hmacauth.NewHmacAuth(sigData.hash, []byte(sigData.key),
|
auth = hmacauth.NewHmacAuth(sigData.Hash, []byte(sigData.Key),
|
||||||
SignatureHeader, SignatureHeaders)
|
SignatureHeader, SignatureHeaders)
|
||||||
}
|
}
|
||||||
for _, u := range opts.proxyURLs {
|
for _, u := range opts.GetProxyURLs() {
|
||||||
path := u.Path
|
path := u.Path
|
||||||
host := u.Host
|
host := u.Host
|
||||||
switch u.Scheme {
|
switch u.Scheme {
|
||||||
@ -252,7 +254,7 @@ func NewOAuthProxy(opts *Options, validator func(string) bool) *OAuthProxy {
|
|||||||
panic(fmt.Sprintf("unknown upstream protocol %s", u.Scheme))
|
panic(fmt.Sprintf("unknown upstream protocol %s", u.Scheme))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, u := range opts.compiledRegex {
|
for _, u := range opts.GetCompiledRegex() {
|
||||||
logger.Printf("compiled skip-auth-regex => %q", u)
|
logger.Printf("compiled skip-auth-regex => %q", u)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,12 +264,12 @@ func NewOAuthProxy(opts *Options, validator func(string) bool) *OAuthProxy {
|
|||||||
logger.Printf("Skipping JWT tokens from extra JWT issuer: %q", issuer)
|
logger.Printf("Skipping JWT tokens from extra JWT issuer: %q", issuer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
redirectURL := opts.redirectURL
|
redirectURL := opts.GetRedirectURL()
|
||||||
if redirectURL.Path == "" {
|
if redirectURL.Path == "" {
|
||||||
redirectURL.Path = fmt.Sprintf("%s/callback", opts.ProxyPrefix)
|
redirectURL.Path = fmt.Sprintf("%s/callback", opts.ProxyPrefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Printf("OAuthProxy configured for %s Client ID: %s", opts.provider.Data().ProviderName, opts.ClientID)
|
logger.Printf("OAuthProxy configured for %s Client ID: %s", opts.GetProvider().Data().ProviderName, opts.ClientID)
|
||||||
refresh := "disabled"
|
refresh := "disabled"
|
||||||
if opts.Cookie.Refresh != time.Duration(0) {
|
if opts.Cookie.Refresh != time.Duration(0) {
|
||||||
refresh = fmt.Sprintf("after %s", opts.Cookie.Refresh)
|
refresh = fmt.Sprintf("after %s", opts.Cookie.Refresh)
|
||||||
@ -298,18 +300,18 @@ func NewOAuthProxy(opts *Options, validator func(string) bool) *OAuthProxy {
|
|||||||
UserInfoPath: fmt.Sprintf("%s/userinfo", opts.ProxyPrefix),
|
UserInfoPath: fmt.Sprintf("%s/userinfo", opts.ProxyPrefix),
|
||||||
|
|
||||||
ProxyPrefix: opts.ProxyPrefix,
|
ProxyPrefix: opts.ProxyPrefix,
|
||||||
provider: opts.provider,
|
provider: opts.GetProvider(),
|
||||||
providerNameOverride: opts.ProviderName,
|
providerNameOverride: opts.ProviderName,
|
||||||
sessionStore: opts.sessionStore,
|
sessionStore: opts.GetSessionStore(),
|
||||||
serveMux: serveMux,
|
serveMux: serveMux,
|
||||||
redirectURL: redirectURL,
|
redirectURL: redirectURL,
|
||||||
whitelistDomains: opts.WhitelistDomains,
|
whitelistDomains: opts.WhitelistDomains,
|
||||||
skipAuthRegex: opts.SkipAuthRegex,
|
skipAuthRegex: opts.SkipAuthRegex,
|
||||||
skipAuthPreflight: opts.SkipAuthPreflight,
|
skipAuthPreflight: opts.SkipAuthPreflight,
|
||||||
skipJwtBearerTokens: opts.SkipJwtBearerTokens,
|
skipJwtBearerTokens: opts.SkipJwtBearerTokens,
|
||||||
jwtBearerVerifiers: opts.jwtBearerVerifiers,
|
jwtBearerVerifiers: opts.GetJWTBearerVerifiers(),
|
||||||
compiledRegex: opts.compiledRegex,
|
compiledRegex: opts.GetCompiledRegex(),
|
||||||
realClientIPParser: opts.realClientIPParser,
|
realClientIPParser: opts.GetRealClientIPParser(),
|
||||||
SetXAuthRequest: opts.SetXAuthRequest,
|
SetXAuthRequest: opts.SetXAuthRequest,
|
||||||
PassBasicAuth: opts.PassBasicAuth,
|
PassBasicAuth: opts.PassBasicAuth,
|
||||||
SetBasicAuth: opts.SetBasicAuth,
|
SetBasicAuth: opts.SetBasicAuth,
|
||||||
@ -760,7 +762,7 @@ func (p *OAuthProxy) OAuthStart(rw http.ResponseWriter, req *http.Request) {
|
|||||||
// OAuthCallback is the OAuth2 authentication flow callback that finishes the
|
// OAuthCallback is the OAuth2 authentication flow callback that finishes the
|
||||||
// OAuth2 authentication flow
|
// OAuth2 authentication flow
|
||||||
func (p *OAuthProxy) OAuthCallback(rw http.ResponseWriter, req *http.Request) {
|
func (p *OAuthProxy) OAuthCallback(rw http.ResponseWriter, req *http.Request) {
|
||||||
remoteAddr := getClientString(p.realClientIPParser, req, true)
|
remoteAddr := logging.GetClientString(p.realClientIPParser, req, true)
|
||||||
|
|
||||||
// finish the oauth cycle
|
// finish the oauth cycle
|
||||||
err := req.ParseForm()
|
err := req.ParseForm()
|
||||||
@ -888,7 +890,7 @@ func (p *OAuthProxy) getAuthenticatedSession(rw http.ResponseWriter, req *http.R
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
remoteAddr := getClientString(p.realClientIPParser, req, true)
|
remoteAddr := logging.GetClientString(p.realClientIPParser, req, true)
|
||||||
if session == nil {
|
if session == nil {
|
||||||
session, err = p.LoadCookiedSession(req)
|
session, err = p.LoadCookiedSession(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -18,9 +18,11 @@ import (
|
|||||||
|
|
||||||
"github.com/coreos/go-oidc"
|
"github.com/coreos/go-oidc"
|
||||||
"github.com/mbland/hmacauth"
|
"github.com/mbland/hmacauth"
|
||||||
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/sessions/cookie"
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/sessions/cookie"
|
||||||
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/validation"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/providers"
|
"github.com/oauth2-proxy/oauth2-proxy/providers"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@ -71,7 +73,7 @@ func TestWebSocketProxy(t *testing.T) {
|
|||||||
|
|
||||||
backendURL, _ := url.Parse(backend.URL)
|
backendURL, _ := url.Parse(backend.URL)
|
||||||
|
|
||||||
options := NewOptions()
|
options := options.NewOptions()
|
||||||
var auth hmacauth.HmacAuth
|
var auth hmacauth.HmacAuth
|
||||||
options.PassHostHeader = true
|
options.PassHostHeader = true
|
||||||
proxyHandler := NewWebSocketOrRestReverseProxy(backendURL, options, auth)
|
proxyHandler := NewWebSocketOrRestReverseProxy(backendURL, options, auth)
|
||||||
@ -121,7 +123,7 @@ func TestNewReverseProxy(t *testing.T) {
|
|||||||
backendHost := net.JoinHostPort(backendHostname, backendPort)
|
backendHost := net.JoinHostPort(backendHostname, backendPort)
|
||||||
proxyURL, _ := url.Parse(backendURL.Scheme + "://" + backendHost + "/")
|
proxyURL, _ := url.Parse(backendURL.Scheme + "://" + backendHost + "/")
|
||||||
|
|
||||||
proxyHandler := NewReverseProxy(proxyURL, &Options{FlushInterval: time.Second})
|
proxyHandler := NewReverseProxy(proxyURL, &options.Options{FlushInterval: time.Second})
|
||||||
setProxyUpstreamHostHeader(proxyHandler, proxyURL)
|
setProxyUpstreamHostHeader(proxyHandler, proxyURL)
|
||||||
frontend := httptest.NewServer(proxyHandler)
|
frontend := httptest.NewServer(proxyHandler)
|
||||||
defer frontend.Close()
|
defer frontend.Close()
|
||||||
@ -143,7 +145,7 @@ func TestEncodedSlashes(t *testing.T) {
|
|||||||
defer backend.Close()
|
defer backend.Close()
|
||||||
|
|
||||||
b, _ := url.Parse(backend.URL)
|
b, _ := url.Parse(backend.URL)
|
||||||
proxyHandler := NewReverseProxy(b, &Options{FlushInterval: time.Second})
|
proxyHandler := NewReverseProxy(b, &options.Options{FlushInterval: time.Second})
|
||||||
setProxyDirector(proxyHandler)
|
setProxyDirector(proxyHandler)
|
||||||
frontend := httptest.NewServer(proxyHandler)
|
frontend := httptest.NewServer(proxyHandler)
|
||||||
defer frontend.Close()
|
defer frontend.Close()
|
||||||
@ -161,11 +163,11 @@ func TestEncodedSlashes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRobotsTxt(t *testing.T) {
|
func TestRobotsTxt(t *testing.T) {
|
||||||
opts := NewOptions()
|
opts := options.NewOptions()
|
||||||
opts.ClientID = "asdlkjx"
|
opts.ClientID = "asdlkjx"
|
||||||
opts.ClientSecret = "alkgks"
|
opts.ClientSecret = "alkgks"
|
||||||
opts.Cookie.Secret = "asdkugkj"
|
opts.Cookie.Secret = "asdkugkj"
|
||||||
opts.Validate()
|
validation.Validate(opts)
|
||||||
|
|
||||||
proxy := NewOAuthProxy(opts, func(string) bool { return true })
|
proxy := NewOAuthProxy(opts, func(string) bool { return true })
|
||||||
rw := httptest.NewRecorder()
|
rw := httptest.NewRecorder()
|
||||||
@ -176,7 +178,7 @@ func TestRobotsTxt(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestIsValidRedirect(t *testing.T) {
|
func TestIsValidRedirect(t *testing.T) {
|
||||||
opts := NewOptions()
|
opts := options.NewOptions()
|
||||||
opts.ClientID = "skdlfj"
|
opts.ClientID = "skdlfj"
|
||||||
opts.ClientSecret = "fgkdsgj"
|
opts.ClientSecret = "fgkdsgj"
|
||||||
opts.Cookie.Secret = "ljgiogbj"
|
opts.Cookie.Secret = "ljgiogbj"
|
||||||
@ -189,7 +191,7 @@ func TestIsValidRedirect(t *testing.T) {
|
|||||||
"anyport.bar:*",
|
"anyport.bar:*",
|
||||||
".sub.anyport.bar:*",
|
".sub.anyport.bar:*",
|
||||||
}
|
}
|
||||||
opts.Validate()
|
validation.Validate(opts)
|
||||||
|
|
||||||
proxy := NewOAuthProxy(opts, func(string) bool { return true })
|
proxy := NewOAuthProxy(opts, func(string) bool { return true })
|
||||||
|
|
||||||
@ -451,7 +453,7 @@ func TestBasicAuthPassword(t *testing.T) {
|
|||||||
w.WriteHeader(200)
|
w.WriteHeader(200)
|
||||||
w.Write([]byte(payload))
|
w.Write([]byte(payload))
|
||||||
}))
|
}))
|
||||||
opts := NewOptions()
|
opts := options.NewOptions()
|
||||||
opts.Upstreams = append(opts.Upstreams, providerServer.URL)
|
opts.Upstreams = append(opts.Upstreams, providerServer.URL)
|
||||||
// The CookieSecret must be 32 bytes in order to create the AES
|
// The CookieSecret must be 32 bytes in order to create the AES
|
||||||
// cipher.
|
// cipher.
|
||||||
@ -464,12 +466,12 @@ func TestBasicAuthPassword(t *testing.T) {
|
|||||||
opts.PassUserHeaders = true
|
opts.PassUserHeaders = true
|
||||||
opts.PreferEmailToUser = true
|
opts.PreferEmailToUser = true
|
||||||
opts.BasicAuthPassword = "This is a secure password"
|
opts.BasicAuthPassword = "This is a secure password"
|
||||||
opts.Validate()
|
validation.Validate(opts)
|
||||||
|
|
||||||
providerURL, _ := url.Parse(providerServer.URL)
|
providerURL, _ := url.Parse(providerServer.URL)
|
||||||
const emailAddress = "john.doe@example.com"
|
const emailAddress = "john.doe@example.com"
|
||||||
|
|
||||||
opts.provider = NewTestProvider(providerURL, emailAddress)
|
opts.SetProvider(NewTestProvider(providerURL, emailAddress))
|
||||||
proxy := NewOAuthProxy(opts, func(email string) bool {
|
proxy := NewOAuthProxy(opts, func(email string) bool {
|
||||||
return email == emailAddress
|
return email == emailAddress
|
||||||
})
|
})
|
||||||
@ -518,12 +520,12 @@ func TestBasicAuthPassword(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestBasicAuthWithEmail(t *testing.T) {
|
func TestBasicAuthWithEmail(t *testing.T) {
|
||||||
opts := NewOptions()
|
opts := options.NewOptions()
|
||||||
opts.PassBasicAuth = true
|
opts.PassBasicAuth = true
|
||||||
opts.PassUserHeaders = false
|
opts.PassUserHeaders = false
|
||||||
opts.PreferEmailToUser = false
|
opts.PreferEmailToUser = false
|
||||||
opts.BasicAuthPassword = "This is a secure password"
|
opts.BasicAuthPassword = "This is a secure password"
|
||||||
opts.Validate()
|
validation.Validate(opts)
|
||||||
|
|
||||||
const emailAddress = "john.doe@example.com"
|
const emailAddress = "john.doe@example.com"
|
||||||
const userName = "9fcab5c9b889a557"
|
const userName = "9fcab5c9b889a557"
|
||||||
@ -564,11 +566,11 @@ func TestBasicAuthWithEmail(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPassUserHeadersWithEmail(t *testing.T) {
|
func TestPassUserHeadersWithEmail(t *testing.T) {
|
||||||
opts := NewOptions()
|
opts := options.NewOptions()
|
||||||
opts.PassBasicAuth = false
|
opts.PassBasicAuth = false
|
||||||
opts.PassUserHeaders = true
|
opts.PassUserHeaders = true
|
||||||
opts.PreferEmailToUser = false
|
opts.PreferEmailToUser = false
|
||||||
opts.Validate()
|
validation.Validate(opts)
|
||||||
|
|
||||||
const emailAddress = "john.doe@example.com"
|
const emailAddress = "john.doe@example.com"
|
||||||
const userName = "9fcab5c9b889a557"
|
const userName = "9fcab5c9b889a557"
|
||||||
@ -605,7 +607,7 @@ func TestPassUserHeadersWithEmail(t *testing.T) {
|
|||||||
type PassAccessTokenTest struct {
|
type PassAccessTokenTest struct {
|
||||||
providerServer *httptest.Server
|
providerServer *httptest.Server
|
||||||
proxy *OAuthProxy
|
proxy *OAuthProxy
|
||||||
opts *Options
|
opts *options.Options
|
||||||
}
|
}
|
||||||
|
|
||||||
type PassAccessTokenTestOptions struct {
|
type PassAccessTokenTestOptions struct {
|
||||||
@ -632,7 +634,7 @@ func NewPassAccessTokenTest(opts PassAccessTokenTestOptions) *PassAccessTokenTes
|
|||||||
w.Write([]byte(payload))
|
w.Write([]byte(payload))
|
||||||
}))
|
}))
|
||||||
|
|
||||||
t.opts = NewOptions()
|
t.opts = options.NewOptions()
|
||||||
t.opts.Upstreams = append(t.opts.Upstreams, t.providerServer.URL)
|
t.opts.Upstreams = append(t.opts.Upstreams, t.providerServer.URL)
|
||||||
if opts.ProxyUpstream != "" {
|
if opts.ProxyUpstream != "" {
|
||||||
t.opts.Upstreams = append(t.opts.Upstreams, opts.ProxyUpstream)
|
t.opts.Upstreams = append(t.opts.Upstreams, opts.ProxyUpstream)
|
||||||
@ -644,12 +646,12 @@ func NewPassAccessTokenTest(opts PassAccessTokenTestOptions) *PassAccessTokenTes
|
|||||||
t.opts.ClientSecret = "gfjgojl"
|
t.opts.ClientSecret = "gfjgojl"
|
||||||
t.opts.Cookie.Secure = false
|
t.opts.Cookie.Secure = false
|
||||||
t.opts.PassAccessToken = opts.PassAccessToken
|
t.opts.PassAccessToken = opts.PassAccessToken
|
||||||
t.opts.Validate()
|
validation.Validate(t.opts)
|
||||||
|
|
||||||
providerURL, _ := url.Parse(t.providerServer.URL)
|
providerURL, _ := url.Parse(t.providerServer.URL)
|
||||||
const emailAddress = "michael.bland@gsa.gov"
|
const emailAddress = "michael.bland@gsa.gov"
|
||||||
|
|
||||||
t.opts.provider = NewTestProvider(providerURL, emailAddress)
|
t.opts.SetProvider(NewTestProvider(providerURL, emailAddress))
|
||||||
t.proxy = NewOAuthProxy(t.opts, func(email string) bool {
|
t.proxy = NewOAuthProxy(t.opts, func(email string) bool {
|
||||||
return email == emailAddress
|
return email == emailAddress
|
||||||
})
|
})
|
||||||
@ -779,7 +781,7 @@ func TestDoNotForwardAccessTokenUpstream(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SignInPageTest struct {
|
type SignInPageTest struct {
|
||||||
opts *Options
|
opts *options.Options
|
||||||
proxy *OAuthProxy
|
proxy *OAuthProxy
|
||||||
signInRegexp *regexp.Regexp
|
signInRegexp *regexp.Regexp
|
||||||
signInProviderRegexp *regexp.Regexp
|
signInProviderRegexp *regexp.Regexp
|
||||||
@ -791,12 +793,12 @@ const signInSkipProvider = `>Found<`
|
|||||||
func NewSignInPageTest(skipProvider bool) *SignInPageTest {
|
func NewSignInPageTest(skipProvider bool) *SignInPageTest {
|
||||||
var sipTest SignInPageTest
|
var sipTest SignInPageTest
|
||||||
|
|
||||||
sipTest.opts = NewOptions()
|
sipTest.opts = options.NewOptions()
|
||||||
sipTest.opts.Cookie.Secret = "adklsj2"
|
sipTest.opts.Cookie.Secret = "adklsj2"
|
||||||
sipTest.opts.ClientID = "lkdgj"
|
sipTest.opts.ClientID = "lkdgj"
|
||||||
sipTest.opts.ClientSecret = "sgiufgoi"
|
sipTest.opts.ClientSecret = "sgiufgoi"
|
||||||
sipTest.opts.SkipProviderButton = skipProvider
|
sipTest.opts.SkipProviderButton = skipProvider
|
||||||
sipTest.opts.Validate()
|
validation.Validate(sipTest.opts)
|
||||||
|
|
||||||
sipTest.proxy = NewOAuthProxy(sipTest.opts, func(email string) bool {
|
sipTest.proxy = NewOAuthProxy(sipTest.opts, func(email string) bool {
|
||||||
return true
|
return true
|
||||||
@ -876,7 +878,7 @@ func TestSignInPageSkipProviderDirect(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ProcessCookieTest struct {
|
type ProcessCookieTest struct {
|
||||||
opts *Options
|
opts *options.Options
|
||||||
proxy *OAuthProxy
|
proxy *OAuthProxy
|
||||||
rw *httptest.ResponseRecorder
|
rw *httptest.ResponseRecorder
|
||||||
req *http.Request
|
req *http.Request
|
||||||
@ -887,12 +889,12 @@ type ProcessCookieTestOpts struct {
|
|||||||
providerValidateCookieResponse bool
|
providerValidateCookieResponse bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type OptionsModifier func(*Options)
|
type OptionsModifier func(*options.Options)
|
||||||
|
|
||||||
func NewProcessCookieTest(opts ProcessCookieTestOpts, modifiers ...OptionsModifier) *ProcessCookieTest {
|
func NewProcessCookieTest(opts ProcessCookieTestOpts, modifiers ...OptionsModifier) *ProcessCookieTest {
|
||||||
var pcTest ProcessCookieTest
|
var pcTest ProcessCookieTest
|
||||||
|
|
||||||
pcTest.opts = NewOptions()
|
pcTest.opts = options.NewOptions()
|
||||||
for _, modifier := range modifiers {
|
for _, modifier := range modifiers {
|
||||||
modifier(pcTest.opts)
|
modifier(pcTest.opts)
|
||||||
}
|
}
|
||||||
@ -902,7 +904,7 @@ func NewProcessCookieTest(opts ProcessCookieTestOpts, modifiers ...OptionsModifi
|
|||||||
// First, set the CookieRefresh option so proxy.AesCipher is created,
|
// First, set the CookieRefresh option so proxy.AesCipher is created,
|
||||||
// needed to encrypt the access_token.
|
// needed to encrypt the access_token.
|
||||||
pcTest.opts.Cookie.Refresh = time.Hour
|
pcTest.opts.Cookie.Refresh = time.Hour
|
||||||
pcTest.opts.Validate()
|
validation.Validate(pcTest.opts)
|
||||||
|
|
||||||
pcTest.proxy = NewOAuthProxy(pcTest.opts, func(email string) bool {
|
pcTest.proxy = NewOAuthProxy(pcTest.opts, func(email string) bool {
|
||||||
return pcTest.validateUser
|
return pcTest.validateUser
|
||||||
@ -971,7 +973,7 @@ func TestProcessCookieNoCookieError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestProcessCookieRefreshNotSet(t *testing.T) {
|
func TestProcessCookieRefreshNotSet(t *testing.T) {
|
||||||
pcTest := NewProcessCookieTestWithOptionsModifiers(func(opts *Options) {
|
pcTest := NewProcessCookieTestWithOptionsModifiers(func(opts *options.Options) {
|
||||||
opts.Cookie.Expire = time.Duration(23) * time.Hour
|
opts.Cookie.Expire = time.Duration(23) * time.Hour
|
||||||
})
|
})
|
||||||
reference := time.Now().Add(time.Duration(-2) * time.Hour)
|
reference := time.Now().Add(time.Duration(-2) * time.Hour)
|
||||||
@ -988,7 +990,7 @@ func TestProcessCookieRefreshNotSet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestProcessCookieFailIfCookieExpired(t *testing.T) {
|
func TestProcessCookieFailIfCookieExpired(t *testing.T) {
|
||||||
pcTest := NewProcessCookieTestWithOptionsModifiers(func(opts *Options) {
|
pcTest := NewProcessCookieTestWithOptionsModifiers(func(opts *options.Options) {
|
||||||
opts.Cookie.Expire = time.Duration(24) * time.Hour
|
opts.Cookie.Expire = time.Duration(24) * time.Hour
|
||||||
})
|
})
|
||||||
reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
|
reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
|
||||||
@ -1003,7 +1005,7 @@ func TestProcessCookieFailIfCookieExpired(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestProcessCookieFailIfRefreshSetAndCookieExpired(t *testing.T) {
|
func TestProcessCookieFailIfRefreshSetAndCookieExpired(t *testing.T) {
|
||||||
pcTest := NewProcessCookieTestWithOptionsModifiers(func(opts *Options) {
|
pcTest := NewProcessCookieTestWithOptionsModifiers(func(opts *options.Options) {
|
||||||
opts.Cookie.Expire = time.Duration(24) * time.Hour
|
opts.Cookie.Expire = time.Duration(24) * time.Hour
|
||||||
})
|
})
|
||||||
reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
|
reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
|
||||||
@ -1073,7 +1075,7 @@ func TestAuthOnlyEndpointUnauthorizedOnNoCookieSetError(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAuthOnlyEndpointUnauthorizedOnExpiration(t *testing.T) {
|
func TestAuthOnlyEndpointUnauthorizedOnExpiration(t *testing.T) {
|
||||||
test := NewAuthOnlyEndpointTest(func(opts *Options) {
|
test := NewAuthOnlyEndpointTest(func(opts *options.Options) {
|
||||||
opts.Cookie.Expire = time.Duration(24) * time.Hour
|
opts.Cookie.Expire = time.Duration(24) * time.Hour
|
||||||
})
|
})
|
||||||
reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
|
reference := time.Now().Add(time.Duration(25) * time.Hour * -1)
|
||||||
@ -1103,9 +1105,9 @@ func TestAuthOnlyEndpointUnauthorizedOnEmailValidationFailure(t *testing.T) {
|
|||||||
func TestAuthOnlyEndpointSetXAuthRequestHeaders(t *testing.T) {
|
func TestAuthOnlyEndpointSetXAuthRequestHeaders(t *testing.T) {
|
||||||
var pcTest ProcessCookieTest
|
var pcTest ProcessCookieTest
|
||||||
|
|
||||||
pcTest.opts = NewOptions()
|
pcTest.opts = options.NewOptions()
|
||||||
pcTest.opts.SetXAuthRequest = true
|
pcTest.opts.SetXAuthRequest = true
|
||||||
pcTest.opts.Validate()
|
validation.Validate(pcTest.opts)
|
||||||
|
|
||||||
pcTest.proxy = NewOAuthProxy(pcTest.opts, func(email string) bool {
|
pcTest.proxy = NewOAuthProxy(pcTest.opts, func(email string) bool {
|
||||||
return pcTest.validateUser
|
return pcTest.validateUser
|
||||||
@ -1133,10 +1135,10 @@ func TestAuthOnlyEndpointSetXAuthRequestHeaders(t *testing.T) {
|
|||||||
func TestAuthOnlyEndpointSetBasicAuthTrueRequestHeaders(t *testing.T) {
|
func TestAuthOnlyEndpointSetBasicAuthTrueRequestHeaders(t *testing.T) {
|
||||||
var pcTest ProcessCookieTest
|
var pcTest ProcessCookieTest
|
||||||
|
|
||||||
pcTest.opts = NewOptions()
|
pcTest.opts = options.NewOptions()
|
||||||
pcTest.opts.SetXAuthRequest = true
|
pcTest.opts.SetXAuthRequest = true
|
||||||
pcTest.opts.SetBasicAuth = true
|
pcTest.opts.SetBasicAuth = true
|
||||||
pcTest.opts.Validate()
|
validation.Validate(pcTest.opts)
|
||||||
|
|
||||||
pcTest.proxy = NewOAuthProxy(pcTest.opts, func(email string) bool {
|
pcTest.proxy = NewOAuthProxy(pcTest.opts, func(email string) bool {
|
||||||
return pcTest.validateUser
|
return pcTest.validateUser
|
||||||
@ -1166,10 +1168,10 @@ func TestAuthOnlyEndpointSetBasicAuthTrueRequestHeaders(t *testing.T) {
|
|||||||
func TestAuthOnlyEndpointSetBasicAuthFalseRequestHeaders(t *testing.T) {
|
func TestAuthOnlyEndpointSetBasicAuthFalseRequestHeaders(t *testing.T) {
|
||||||
var pcTest ProcessCookieTest
|
var pcTest ProcessCookieTest
|
||||||
|
|
||||||
pcTest.opts = NewOptions()
|
pcTest.opts = options.NewOptions()
|
||||||
pcTest.opts.SetXAuthRequest = true
|
pcTest.opts.SetXAuthRequest = true
|
||||||
pcTest.opts.SetBasicAuth = false
|
pcTest.opts.SetBasicAuth = false
|
||||||
pcTest.opts.Validate()
|
validation.Validate(pcTest.opts)
|
||||||
|
|
||||||
pcTest.proxy = NewOAuthProxy(pcTest.opts, func(email string) bool {
|
pcTest.proxy = NewOAuthProxy(pcTest.opts, func(email string) bool {
|
||||||
return pcTest.validateUser
|
return pcTest.validateUser
|
||||||
@ -1202,16 +1204,16 @@ func TestAuthSkippedForPreflightRequests(t *testing.T) {
|
|||||||
}))
|
}))
|
||||||
defer upstream.Close()
|
defer upstream.Close()
|
||||||
|
|
||||||
opts := NewOptions()
|
opts := options.NewOptions()
|
||||||
opts.Upstreams = append(opts.Upstreams, upstream.URL)
|
opts.Upstreams = append(opts.Upstreams, upstream.URL)
|
||||||
opts.ClientID = "aljsal"
|
opts.ClientID = "aljsal"
|
||||||
opts.ClientSecret = "jglkfsdgj"
|
opts.ClientSecret = "jglkfsdgj"
|
||||||
opts.Cookie.Secret = "dkfjgdls"
|
opts.Cookie.Secret = "dkfjgdls"
|
||||||
opts.SkipAuthPreflight = true
|
opts.SkipAuthPreflight = true
|
||||||
opts.Validate()
|
validation.Validate(opts)
|
||||||
|
|
||||||
upstreamURL, _ := url.Parse(upstream.URL)
|
upstreamURL, _ := url.Parse(upstream.URL)
|
||||||
opts.provider = NewTestProvider(upstreamURL, "")
|
opts.SetProvider(NewTestProvider(upstreamURL, ""))
|
||||||
|
|
||||||
proxy := NewOAuthProxy(opts, func(string) bool { return false })
|
proxy := NewOAuthProxy(opts, func(string) bool { return false })
|
||||||
rw := httptest.NewRecorder()
|
rw := httptest.NewRecorder()
|
||||||
@ -1242,7 +1244,7 @@ func (v *SignatureAuthenticator) Authenticate(w http.ResponseWriter, r *http.Req
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SignatureTest struct {
|
type SignatureTest struct {
|
||||||
opts *Options
|
opts *options.Options
|
||||||
upstream *httptest.Server
|
upstream *httptest.Server
|
||||||
upstreamHost string
|
upstreamHost string
|
||||||
provider *httptest.Server
|
provider *httptest.Server
|
||||||
@ -1252,7 +1254,7 @@ type SignatureTest struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewSignatureTest() *SignatureTest {
|
func NewSignatureTest() *SignatureTest {
|
||||||
opts := NewOptions()
|
opts := options.NewOptions()
|
||||||
opts.Cookie.Secret = "cookie secret"
|
opts.Cookie.Secret = "cookie secret"
|
||||||
opts.ClientID = "client ID"
|
opts.ClientID = "client ID"
|
||||||
opts.ClientSecret = "client secret"
|
opts.ClientSecret = "client secret"
|
||||||
@ -1269,7 +1271,7 @@ func NewSignatureTest() *SignatureTest {
|
|||||||
}
|
}
|
||||||
provider := httptest.NewServer(http.HandlerFunc(providerHandler))
|
provider := httptest.NewServer(http.HandlerFunc(providerHandler))
|
||||||
providerURL, _ := url.Parse(provider.URL)
|
providerURL, _ := url.Parse(provider.URL)
|
||||||
opts.provider = NewTestProvider(providerURL, "mbland@acm.org")
|
opts.SetProvider(NewTestProvider(providerURL, "mbland@acm.org"))
|
||||||
|
|
||||||
return &SignatureTest{
|
return &SignatureTest{
|
||||||
opts,
|
opts,
|
||||||
@ -1304,7 +1306,7 @@ func (fnc *fakeNetConn) Read(p []byte) (n int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (st *SignatureTest) MakeRequestWithExpectedKey(method, body, key string) {
|
func (st *SignatureTest) MakeRequestWithExpectedKey(method, body, key string) {
|
||||||
err := st.opts.Validate()
|
err := validation.Validate(st.opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -1360,8 +1362,8 @@ func TestRequestSignaturePostRequest(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGetRedirect(t *testing.T) {
|
func TestGetRedirect(t *testing.T) {
|
||||||
options := NewOptions()
|
options := options.NewOptions()
|
||||||
_ = options.Validate()
|
_ = validation.Validate(options)
|
||||||
require.NotEmpty(t, options.ProxyPrefix)
|
require.NotEmpty(t, options.ProxyPrefix)
|
||||||
proxy := NewOAuthProxy(options, func(s string) bool { return false })
|
proxy := NewOAuthProxy(options, func(s string) bool { return false })
|
||||||
|
|
||||||
@ -1393,17 +1395,17 @@ func TestGetRedirect(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ajaxRequestTest struct {
|
type ajaxRequestTest struct {
|
||||||
opts *Options
|
opts *options.Options
|
||||||
proxy *OAuthProxy
|
proxy *OAuthProxy
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAjaxRequestTest() *ajaxRequestTest {
|
func newAjaxRequestTest() *ajaxRequestTest {
|
||||||
test := &ajaxRequestTest{}
|
test := &ajaxRequestTest{}
|
||||||
test.opts = NewOptions()
|
test.opts = options.NewOptions()
|
||||||
test.opts.Cookie.Secret = "sdflsw"
|
test.opts.Cookie.Secret = "sdflsw"
|
||||||
test.opts.ClientID = "gkljfdl"
|
test.opts.ClientID = "gkljfdl"
|
||||||
test.opts.ClientSecret = "sdflkjs"
|
test.opts.ClientSecret = "sdflkjs"
|
||||||
test.opts.Validate()
|
validation.Validate(test.opts)
|
||||||
test.proxy = NewOAuthProxy(test.opts, func(email string) bool {
|
test.proxy = NewOAuthProxy(test.opts, func(email string) bool {
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
@ -1457,7 +1459,7 @@ func TestAjaxForbiddendRequest(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClearSplitCookie(t *testing.T) {
|
func TestClearSplitCookie(t *testing.T) {
|
||||||
opts := NewOptions()
|
opts := options.NewOptions()
|
||||||
opts.Cookie.Name = "oauth2"
|
opts.Cookie.Name = "oauth2"
|
||||||
opts.Cookie.Domains = []string{"abc"}
|
opts.Cookie.Domains = []string{"abc"}
|
||||||
store, err := cookie.NewCookieSessionStore(&opts.Session, &opts.Cookie)
|
store, err := cookie.NewCookieSessionStore(&opts.Session, &opts.Cookie)
|
||||||
@ -1486,7 +1488,7 @@ func TestClearSplitCookie(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClearSingleCookie(t *testing.T) {
|
func TestClearSingleCookie(t *testing.T) {
|
||||||
opts := NewOptions()
|
opts := options.NewOptions()
|
||||||
opts.Cookie.Name = "oauth2"
|
opts.Cookie.Name = "oauth2"
|
||||||
opts.Cookie.Domains = []string{"abc"}
|
opts.Cookie.Domains = []string{"abc"}
|
||||||
store, err := cookie.NewCookieSessionStore(&opts.Session, &opts.Cookie)
|
store, err := cookie.NewCookieSessionStore(&opts.Session, &opts.Cookie)
|
||||||
@ -1542,12 +1544,12 @@ func TestGetJwtSession(t *testing.T) {
|
|||||||
verifier := oidc.NewVerifier("https://issuer.example.com", keyset,
|
verifier := oidc.NewVerifier("https://issuer.example.com", keyset,
|
||||||
&oidc.Config{ClientID: "https://test.myapp.com", SkipExpiryCheck: true})
|
&oidc.Config{ClientID: "https://test.myapp.com", SkipExpiryCheck: true})
|
||||||
|
|
||||||
test := NewAuthOnlyEndpointTest(func(opts *Options) {
|
test := NewAuthOnlyEndpointTest(func(opts *options.Options) {
|
||||||
opts.PassAuthorization = true
|
opts.PassAuthorization = true
|
||||||
opts.SetAuthorization = true
|
opts.SetAuthorization = true
|
||||||
opts.SetXAuthRequest = true
|
opts.SetXAuthRequest = true
|
||||||
opts.SkipJwtBearerTokens = true
|
opts.SkipJwtBearerTokens = true
|
||||||
opts.jwtBearerVerifiers = append(opts.jwtBearerVerifiers, verifier)
|
opts.SetJWTBearerVerifiers(append(opts.GetJWTBearerVerifiers(), verifier))
|
||||||
})
|
})
|
||||||
tp, _ := test.proxy.provider.(*TestProvider)
|
tp, _ := test.proxy.provider.(*TestProvider)
|
||||||
tp.GroupValidator = func(s string) bool {
|
tp.GroupValidator = func(s string) bool {
|
||||||
@ -1666,10 +1668,10 @@ func Test_noCacheHeadersDoesNotExistsInResponseHeadersFromUpstream(t *testing.T)
|
|||||||
}))
|
}))
|
||||||
t.Cleanup(upstream.Close)
|
t.Cleanup(upstream.Close)
|
||||||
|
|
||||||
opts := NewOptions()
|
opts := options.NewOptions()
|
||||||
opts.Upstreams = []string{upstream.URL}
|
opts.Upstreams = []string{upstream.URL}
|
||||||
opts.SkipAuthRegex = []string{".*"}
|
opts.SkipAuthRegex = []string{".*"}
|
||||||
_ = opts.Validate()
|
_ = validation.Validate(opts)
|
||||||
proxy := NewOAuthProxy(opts, func(email string) bool {
|
proxy := NewOAuthProxy(opts, func(email string) bool {
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
@ -1,19 +1,18 @@
|
|||||||
package main
|
package logging
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type realClientIPParser interface {
|
// RealClientIPParser is an interface for a getting the client's real IP to be used for logging.
|
||||||
|
type RealClientIPParser interface {
|
||||||
GetRealClientIP(http.Header) (net.IP, error)
|
GetRealClientIP(http.Header) (net.IP, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRealClientIPParser(headerKey string) (realClientIPParser, error) {
|
func GetRealClientIPParser(headerKey string) (RealClientIPParser, error) {
|
||||||
headerKey = http.CanonicalHeaderKey(headerKey)
|
headerKey = http.CanonicalHeaderKey(headerKey)
|
||||||
|
|
||||||
switch headerKey {
|
switch headerKey {
|
||||||
@ -73,13 +72,11 @@ func getRemoteIP(req *http.Request) (net.IP, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// getClientString obtains the human readable string of the remote IP and optionally the real client IP if available
|
// GetClientString obtains the human readable string of the remote IP and optionally the real client IP if available
|
||||||
func getClientString(p realClientIPParser, req *http.Request, full bool) (s string) {
|
func GetClientString(p RealClientIPParser, req *http.Request, full bool) (s string) {
|
||||||
var realClientIPStr string
|
var realClientIPStr string
|
||||||
if p != nil {
|
if p != nil {
|
||||||
if realClientIP, err := p.GetRealClientIP(req.Header); err != nil {
|
if realClientIP, err := p.GetRealClientIP(req.Header); err == nil && realClientIP != nil {
|
||||||
logger.Printf("Unable to get real client IP: %v", err)
|
|
||||||
} else if realClientIP != nil {
|
|
||||||
realClientIPStr = realClientIP.String()
|
realClientIPStr = realClientIP.String()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,9 +84,6 @@ func getClientString(p realClientIPParser, req *http.Request, full bool) (s stri
|
|||||||
var remoteIPStr string
|
var remoteIPStr string
|
||||||
if remoteIP, err := getRemoteIP(req); err == nil {
|
if remoteIP, err := getRemoteIP(req); err == nil {
|
||||||
remoteIPStr = remoteIP.String()
|
remoteIPStr = remoteIP.String()
|
||||||
} else {
|
|
||||||
// Should not happen, if it does, likely a bug.
|
|
||||||
logger.Printf("Unable to get remote IP(?!?!): %v", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !full && realClientIPStr != "" {
|
if !full && realClientIPStr != "" {
|
@ -1,4 +1,4 @@
|
|||||||
package main
|
package logging
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
@ -26,7 +26,7 @@ func TestGetRealClientIPParser(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
p, err := getRealClientIPParser(test.header)
|
p, err := GetRealClientIPParser(test.header)
|
||||||
|
|
||||||
if test.errString == "" {
|
if test.errString == "" {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
@ -144,7 +144,7 @@ func TestGetClientString(t *testing.T) {
|
|||||||
p := &xForwardedForClientIPParser{header: http.CanonicalHeaderKey("X-Forwarded-For")}
|
p := &xForwardedForClientIPParser{header: http.CanonicalHeaderKey("X-Forwarded-For")}
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
parser realClientIPParser
|
parser RealClientIPParser
|
||||||
remoteAddr string
|
remoteAddr string
|
||||||
headerValue string
|
headerValue string
|
||||||
expectedClient string
|
expectedClient string
|
||||||
@ -167,10 +167,10 @@ func TestGetClientString(t *testing.T) {
|
|||||||
RemoteAddr: test.remoteAddr,
|
RemoteAddr: test.remoteAddr,
|
||||||
}
|
}
|
||||||
|
|
||||||
client := getClientString(test.parser, req, false)
|
client := GetClientString(test.parser, req, false)
|
||||||
assert.Equal(t, test.expectedClient, client)
|
assert.Equal(t, test.expectedClient, client)
|
||||||
|
|
||||||
clientFull := getClientString(test.parser, req, true)
|
clientFull := GetClientString(test.parser, req, true)
|
||||||
assert.Equal(t, test.expectedClientFull, clientFull)
|
assert.Equal(t, test.expectedClientFull, clientFull)
|
||||||
}
|
}
|
||||||
}
|
}
|
210
pkg/apis/options/options.go
Normal file
210
pkg/apis/options/options.go
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
package options
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto"
|
||||||
|
"net/url"
|
||||||
|
"regexp"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
oidc "github.com/coreos/go-oidc"
|
||||||
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/logging"
|
||||||
|
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
||||||
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
||||||
|
"github.com/oauth2-proxy/oauth2-proxy/providers"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SignatureData holds hmacauth signature hash and key
|
||||||
|
type SignatureData struct {
|
||||||
|
Hash crypto.Hash
|
||||||
|
Key string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Options holds Configuration Options that can be set by Command Line Flag,
|
||||||
|
// or Config File
|
||||||
|
type Options struct {
|
||||||
|
ProxyPrefix string `flag:"proxy-prefix" cfg:"proxy_prefix" env:"OAUTH2_PROXY_PROXY_PREFIX"`
|
||||||
|
PingPath string `flag:"ping-path" cfg:"ping_path" env:"OAUTH2_PROXY_PING_PATH"`
|
||||||
|
ProxyWebSockets bool `flag:"proxy-websockets" cfg:"proxy_websockets" env:"OAUTH2_PROXY_PROXY_WEBSOCKETS"`
|
||||||
|
HTTPAddress string `flag:"http-address" cfg:"http_address" env:"OAUTH2_PROXY_HTTP_ADDRESS"`
|
||||||
|
HTTPSAddress string `flag:"https-address" cfg:"https_address" env:"OAUTH2_PROXY_HTTPS_ADDRESS"`
|
||||||
|
ReverseProxy bool `flag:"reverse-proxy" cfg:"reverse_proxy" env:"OAUTH2_PROXY_REVERSE_PROXY"`
|
||||||
|
RealClientIPHeader string `flag:"real-client-ip-header" cfg:"real_client_ip_header" env:"OAUTH2_PROXY_REAL_CLIENT_IP_HEADER"`
|
||||||
|
ForceHTTPS bool `flag:"force-https" cfg:"force_https" env:"OAUTH2_PROXY_FORCE_HTTPS"`
|
||||||
|
RawRedirectURL string `flag:"redirect-url" cfg:"redirect_url" env:"OAUTH2_PROXY_REDIRECT_URL"`
|
||||||
|
ClientID string `flag:"client-id" cfg:"client_id" env:"OAUTH2_PROXY_CLIENT_ID"`
|
||||||
|
ClientSecret string `flag:"client-secret" cfg:"client_secret" env:"OAUTH2_PROXY_CLIENT_SECRET"`
|
||||||
|
ClientSecretFile string `flag:"client-secret-file" cfg:"client_secret_file" env:"OAUTH2_PROXY_CLIENT_SECRET_FILE"`
|
||||||
|
TLSCertFile string `flag:"tls-cert-file" cfg:"tls_cert_file" env:"OAUTH2_PROXY_TLS_CERT_FILE"`
|
||||||
|
TLSKeyFile string `flag:"tls-key-file" cfg:"tls_key_file" env:"OAUTH2_PROXY_TLS_KEY_FILE"`
|
||||||
|
|
||||||
|
AuthenticatedEmailsFile string `flag:"authenticated-emails-file" cfg:"authenticated_emails_file" env:"OAUTH2_PROXY_AUTHENTICATED_EMAILS_FILE"`
|
||||||
|
KeycloakGroup string `flag:"keycloak-group" cfg:"keycloak_group" env:"OAUTH2_PROXY_KEYCLOAK_GROUP"`
|
||||||
|
AzureTenant string `flag:"azure-tenant" cfg:"azure_tenant" env:"OAUTH2_PROXY_AZURE_TENANT"`
|
||||||
|
BitbucketTeam string `flag:"bitbucket-team" cfg:"bitbucket_team" env:"OAUTH2_PROXY_BITBUCKET_TEAM"`
|
||||||
|
BitbucketRepository string `flag:"bitbucket-repository" cfg:"bitbucket_repository" env:"OAUTH2_PROXY_BITBUCKET_REPOSITORY"`
|
||||||
|
EmailDomains []string `flag:"email-domain" cfg:"email_domains" env:"OAUTH2_PROXY_EMAIL_DOMAINS"`
|
||||||
|
WhitelistDomains []string `flag:"whitelist-domain" cfg:"whitelist_domains" env:"OAUTH2_PROXY_WHITELIST_DOMAINS"`
|
||||||
|
GitHubOrg string `flag:"github-org" cfg:"github_org" env:"OAUTH2_PROXY_GITHUB_ORG"`
|
||||||
|
GitHubTeam string `flag:"github-team" cfg:"github_team" env:"OAUTH2_PROXY_GITHUB_TEAM"`
|
||||||
|
GitHubRepo string `flag:"github-repo" cfg:"github_repo" env:"OAUTH2_PROXY_GITHUB_REPO"`
|
||||||
|
GitHubToken string `flag:"github-token" cfg:"github_token" env:"OAUTH2_PROXY_GITHUB_TOKEN"`
|
||||||
|
GitLabGroup string `flag:"gitlab-group" cfg:"gitlab_group" env:"OAUTH2_PROXY_GITLAB_GROUP"`
|
||||||
|
GoogleGroups []string `flag:"google-group" cfg:"google_group" env:"OAUTH2_PROXY_GOOGLE_GROUPS"`
|
||||||
|
GoogleAdminEmail string `flag:"google-admin-email" cfg:"google_admin_email" env:"OAUTH2_PROXY_GOOGLE_ADMIN_EMAIL"`
|
||||||
|
GoogleServiceAccountJSON string `flag:"google-service-account-json" cfg:"google_service_account_json" env:"OAUTH2_PROXY_GOOGLE_SERVICE_ACCOUNT_JSON"`
|
||||||
|
HtpasswdFile string `flag:"htpasswd-file" cfg:"htpasswd_file" env:"OAUTH2_PROXY_HTPASSWD_FILE"`
|
||||||
|
DisplayHtpasswdForm bool `flag:"display-htpasswd-form" cfg:"display_htpasswd_form" env:"OAUTH2_PROXY_DISPLAY_HTPASSWD_FORM"`
|
||||||
|
CustomTemplatesDir string `flag:"custom-templates-dir" cfg:"custom_templates_dir" env:"OAUTH2_PROXY_CUSTOM_TEMPLATES_DIR"`
|
||||||
|
Banner string `flag:"banner" cfg:"banner" env:"OAUTH2_PROXY_BANNER"`
|
||||||
|
Footer string `flag:"footer" cfg:"footer" env:"OAUTH2_PROXY_FOOTER"`
|
||||||
|
|
||||||
|
Cookie CookieOptions `cfg:",squash"`
|
||||||
|
Session SessionOptions `cfg:",squash"`
|
||||||
|
|
||||||
|
Upstreams []string `flag:"upstream" cfg:"upstreams" env:"OAUTH2_PROXY_UPSTREAMS"`
|
||||||
|
SkipAuthRegex []string `flag:"skip-auth-regex" cfg:"skip_auth_regex" env:"OAUTH2_PROXY_SKIP_AUTH_REGEX"`
|
||||||
|
SkipJwtBearerTokens bool `flag:"skip-jwt-bearer-tokens" cfg:"skip_jwt_bearer_tokens" env:"OAUTH2_PROXY_SKIP_JWT_BEARER_TOKENS"`
|
||||||
|
ExtraJwtIssuers []string `flag:"extra-jwt-issuers" cfg:"extra_jwt_issuers" env:"OAUTH2_PROXY_EXTRA_JWT_ISSUERS"`
|
||||||
|
PassBasicAuth bool `flag:"pass-basic-auth" cfg:"pass_basic_auth" env:"OAUTH2_PROXY_PASS_BASIC_AUTH"`
|
||||||
|
SetBasicAuth bool `flag:"set-basic-auth" cfg:"set_basic_auth" env:"OAUTH2_PROXY_SET_BASIC_AUTH"`
|
||||||
|
PreferEmailToUser bool `flag:"prefer-email-to-user" cfg:"prefer_email_to_user" env:"OAUTH2_PROXY_PREFER_EMAIL_TO_USER"`
|
||||||
|
BasicAuthPassword string `flag:"basic-auth-password" cfg:"basic_auth_password" env:"OAUTH2_PROXY_BASIC_AUTH_PASSWORD"`
|
||||||
|
PassAccessToken bool `flag:"pass-access-token" cfg:"pass_access_token" env:"OAUTH2_PROXY_PASS_ACCESS_TOKEN"`
|
||||||
|
PassHostHeader bool `flag:"pass-host-header" cfg:"pass_host_header" env:"OAUTH2_PROXY_PASS_HOST_HEADER"`
|
||||||
|
SkipProviderButton bool `flag:"skip-provider-button" cfg:"skip_provider_button" env:"OAUTH2_PROXY_SKIP_PROVIDER_BUTTON"`
|
||||||
|
PassUserHeaders bool `flag:"pass-user-headers" cfg:"pass_user_headers" env:"OAUTH2_PROXY_PASS_USER_HEADERS"`
|
||||||
|
SSLInsecureSkipVerify bool `flag:"ssl-insecure-skip-verify" cfg:"ssl_insecure_skip_verify" env:"OAUTH2_PROXY_SSL_INSECURE_SKIP_VERIFY"`
|
||||||
|
SSLUpstreamInsecureSkipVerify bool `flag:"ssl-upstream-insecure-skip-verify" cfg:"ssl_upstream_insecure_skip_verify" env:"OAUTH2_PROXY_SSL_UPSTREAM_INSECURE_SKIP_VERIFY"`
|
||||||
|
SetXAuthRequest bool `flag:"set-xauthrequest" cfg:"set_xauthrequest" env:"OAUTH2_PROXY_SET_XAUTHREQUEST"`
|
||||||
|
SetAuthorization bool `flag:"set-authorization-header" cfg:"set_authorization_header" env:"OAUTH2_PROXY_SET_AUTHORIZATION_HEADER"`
|
||||||
|
PassAuthorization bool `flag:"pass-authorization-header" cfg:"pass_authorization_header" env:"OAUTH2_PROXY_PASS_AUTHORIZATION_HEADER"`
|
||||||
|
SkipAuthPreflight bool `flag:"skip-auth-preflight" cfg:"skip_auth_preflight" env:"OAUTH2_PROXY_SKIP_AUTH_PREFLIGHT"`
|
||||||
|
FlushInterval time.Duration `flag:"flush-interval" cfg:"flush_interval" env:"OAUTH2_PROXY_FLUSH_INTERVAL"`
|
||||||
|
|
||||||
|
// These options allow for other providers besides Google, with
|
||||||
|
// potential overrides.
|
||||||
|
ProviderType string `flag:"provider" cfg:"provider" env:"OAUTH2_PROXY_PROVIDER"`
|
||||||
|
ProviderName string `flag:"provider-display-name" cfg:"provider_display_name" env:"OAUTH2_PROXY_PROVIDER_DISPLAY_NAME"`
|
||||||
|
OIDCIssuerURL string `flag:"oidc-issuer-url" cfg:"oidc_issuer_url" env:"OAUTH2_PROXY_OIDC_ISSUER_URL"`
|
||||||
|
InsecureOIDCAllowUnverifiedEmail bool `flag:"insecure-oidc-allow-unverified-email" cfg:"insecure_oidc_allow_unverified_email" env:"OAUTH2_PROXY_INSECURE_OIDC_ALLOW_UNVERIFIED_EMAIL"`
|
||||||
|
InsecureOIDCSkipIssuerVerification bool `flag:"insecure-oidc-skip-issuer-verification" cfg:"insecure_oidc_skip_issuer_verification" env:"OAUTH2_PROXY_INSECURE_OIDC_SKIP_ISSUER_VERIFICATION"`
|
||||||
|
SkipOIDCDiscovery bool `flag:"skip-oidc-discovery" cfg:"skip_oidc_discovery" env:"OAUTH2_PROXY_SKIP_OIDC_DISCOVERY"`
|
||||||
|
OIDCJwksURL string `flag:"oidc-jwks-url" cfg:"oidc_jwks_url" env:"OAUTH2_PROXY_OIDC_JWKS_URL"`
|
||||||
|
LoginURL string `flag:"login-url" cfg:"login_url" env:"OAUTH2_PROXY_LOGIN_URL"`
|
||||||
|
RedeemURL string `flag:"redeem-url" cfg:"redeem_url" env:"OAUTH2_PROXY_REDEEM_URL"`
|
||||||
|
ProfileURL string `flag:"profile-url" cfg:"profile_url" env:"OAUTH2_PROXY_PROFILE_URL"`
|
||||||
|
ProtectedResource string `flag:"resource" cfg:"resource" env:"OAUTH2_PROXY_RESOURCE"`
|
||||||
|
ValidateURL string `flag:"validate-url" cfg:"validate_url" env:"OAUTH2_PROXY_VALIDATE_URL"`
|
||||||
|
Scope string `flag:"scope" cfg:"scope" env:"OAUTH2_PROXY_SCOPE"`
|
||||||
|
Prompt string `flag:"prompt" cfg:"prompt" env:"OAUTH2_PROXY_PROMPT"`
|
||||||
|
ApprovalPrompt string `flag:"approval-prompt" cfg:"approval_prompt" env:"OAUTH2_PROXY_APPROVAL_PROMPT"` // Deprecated by OIDC 1.0
|
||||||
|
UserIDClaim string `flag:"user-id-claim" cfg:"user_id_claim" env:"OAUTH2_PROXY_USER_ID_CLAIM"`
|
||||||
|
|
||||||
|
// Configuration values for logging
|
||||||
|
LoggingFilename string `flag:"logging-filename" cfg:"logging_filename" env:"OAUTH2_PROXY_LOGGING_FILENAME"`
|
||||||
|
LoggingMaxSize int `flag:"logging-max-size" cfg:"logging_max_size" env:"OAUTH2_PROXY_LOGGING_MAX_SIZE"`
|
||||||
|
LoggingMaxAge int `flag:"logging-max-age" cfg:"logging_max_age" env:"OAUTH2_PROXY_LOGGING_MAX_AGE"`
|
||||||
|
LoggingMaxBackups int `flag:"logging-max-backups" cfg:"logging_max_backups" env:"OAUTH2_PROXY_LOGGING_MAX_BACKUPS"`
|
||||||
|
LoggingLocalTime bool `flag:"logging-local-time" cfg:"logging_local_time" env:"OAUTH2_PROXY_LOGGING_LOCAL_TIME"`
|
||||||
|
LoggingCompress bool `flag:"logging-compress" cfg:"logging_compress" env:"OAUTH2_PROXY_LOGGING_COMPRESS"`
|
||||||
|
StandardLogging bool `flag:"standard-logging" cfg:"standard_logging" env:"OAUTH2_PROXY_STANDARD_LOGGING"`
|
||||||
|
StandardLoggingFormat string `flag:"standard-logging-format" cfg:"standard_logging_format" env:"OAUTH2_PROXY_STANDARD_LOGGING_FORMAT"`
|
||||||
|
RequestLogging bool `flag:"request-logging" cfg:"request_logging" env:"OAUTH2_PROXY_REQUEST_LOGGING"`
|
||||||
|
RequestLoggingFormat string `flag:"request-logging-format" cfg:"request_logging_format" env:"OAUTH2_PROXY_REQUEST_LOGGING_FORMAT"`
|
||||||
|
ExcludeLoggingPaths string `flag:"exclude-logging-paths" cfg:"exclude_logging_paths" env:"OAUTH2_PROXY_EXCLUDE_LOGGING_PATHS"`
|
||||||
|
SilencePingLogging bool `flag:"silence-ping-logging" cfg:"silence_ping_logging" env:"OAUTH2_PROXY_SILENCE_PING_LOGGING"`
|
||||||
|
AuthLogging bool `flag:"auth-logging" cfg:"auth_logging" env:"OAUTH2_PROXY_LOGGING_AUTH_LOGGING"`
|
||||||
|
AuthLoggingFormat string `flag:"auth-logging-format" cfg:"auth_logging_format" env:"OAUTH2_PROXY_AUTH_LOGGING_FORMAT"`
|
||||||
|
SignatureKey string `flag:"signature-key" cfg:"signature_key" env:"OAUTH2_PROXY_SIGNATURE_KEY"`
|
||||||
|
AcrValues string `flag:"acr-values" cfg:"acr_values" env:"OAUTH2_PROXY_ACR_VALUES"`
|
||||||
|
JWTKey string `flag:"jwt-key" cfg:"jwt_key" env:"OAUTH2_PROXY_JWT_KEY"`
|
||||||
|
JWTKeyFile string `flag:"jwt-key-file" cfg:"jwt_key_file" env:"OAUTH2_PROXY_JWT_KEY_FILE"`
|
||||||
|
PubJWKURL string `flag:"pubjwk-url" cfg:"pubjwk_url" env:"OAUTH2_PROXY_PUBJWK_URL"`
|
||||||
|
GCPHealthChecks bool `flag:"gcp-healthchecks" cfg:"gcp_healthchecks" env:"OAUTH2_PROXY_GCP_HEALTHCHECKS"`
|
||||||
|
|
||||||
|
// internal values that are set after config validation
|
||||||
|
redirectURL *url.URL
|
||||||
|
proxyURLs []*url.URL
|
||||||
|
compiledRegex []*regexp.Regexp
|
||||||
|
provider providers.Provider
|
||||||
|
sessionStore sessionsapi.SessionStore
|
||||||
|
signatureData *SignatureData
|
||||||
|
oidcVerifier *oidc.IDTokenVerifier
|
||||||
|
jwtBearerVerifiers []*oidc.IDTokenVerifier
|
||||||
|
realClientIPParser logging.RealClientIPParser
|
||||||
|
}
|
||||||
|
|
||||||
|
// Options for Getting internal values
|
||||||
|
func (o *Options) GetRedirectURL() *url.URL { return o.redirectURL }
|
||||||
|
func (o *Options) GetProxyURLs() []*url.URL { return o.proxyURLs }
|
||||||
|
func (o *Options) GetCompiledRegex() []*regexp.Regexp { return o.compiledRegex }
|
||||||
|
func (o *Options) GetProvider() providers.Provider { return o.provider }
|
||||||
|
func (o *Options) GetSessionStore() sessionsapi.SessionStore { return o.sessionStore }
|
||||||
|
func (o *Options) GetSignatureData() *SignatureData { return o.signatureData }
|
||||||
|
func (o *Options) GetOIDCVerifier() *oidc.IDTokenVerifier { return o.oidcVerifier }
|
||||||
|
func (o *Options) GetJWTBearerVerifiers() []*oidc.IDTokenVerifier { return o.jwtBearerVerifiers }
|
||||||
|
func (o *Options) GetRealClientIPParser() logging.RealClientIPParser { return o.realClientIPParser }
|
||||||
|
|
||||||
|
// Options for Setting internal values
|
||||||
|
func (o *Options) SetRedirectURL(s *url.URL) { o.redirectURL = s }
|
||||||
|
func (o *Options) SetProxyURLs(s []*url.URL) { o.proxyURLs = s }
|
||||||
|
func (o *Options) SetCompiledRegex(s []*regexp.Regexp) { o.compiledRegex = s }
|
||||||
|
func (o *Options) SetProvider(s providers.Provider) { o.provider = s }
|
||||||
|
func (o *Options) SetSessionStore(s sessionsapi.SessionStore) { o.sessionStore = s }
|
||||||
|
func (o *Options) SetSignatureData(s *SignatureData) { o.signatureData = s }
|
||||||
|
func (o *Options) SetOIDCVerifier(s *oidc.IDTokenVerifier) { o.oidcVerifier = s }
|
||||||
|
func (o *Options) SetJWTBearerVerifiers(s []*oidc.IDTokenVerifier) { o.jwtBearerVerifiers = s }
|
||||||
|
func (o *Options) SetRealClientIPParser(s logging.RealClientIPParser) { o.realClientIPParser = s }
|
||||||
|
|
||||||
|
// NewOptions constructs a new Options with defaulted values
|
||||||
|
func NewOptions() *Options {
|
||||||
|
return &Options{
|
||||||
|
ProxyPrefix: "/oauth2",
|
||||||
|
PingPath: "/ping",
|
||||||
|
ProxyWebSockets: true,
|
||||||
|
HTTPAddress: "127.0.0.1:4180",
|
||||||
|
HTTPSAddress: ":443",
|
||||||
|
RealClientIPHeader: "X-Real-IP",
|
||||||
|
ForceHTTPS: false,
|
||||||
|
DisplayHtpasswdForm: true,
|
||||||
|
Cookie: CookieOptions{
|
||||||
|
Name: "_oauth2_proxy",
|
||||||
|
Secure: true,
|
||||||
|
HTTPOnly: true,
|
||||||
|
Expire: time.Duration(168) * time.Hour,
|
||||||
|
Refresh: time.Duration(0),
|
||||||
|
},
|
||||||
|
Session: SessionOptions{
|
||||||
|
Type: "cookie",
|
||||||
|
},
|
||||||
|
SetXAuthRequest: false,
|
||||||
|
SkipAuthPreflight: false,
|
||||||
|
PassBasicAuth: true,
|
||||||
|
SetBasicAuth: false,
|
||||||
|
PassUserHeaders: true,
|
||||||
|
PassAccessToken: false,
|
||||||
|
PassHostHeader: true,
|
||||||
|
SetAuthorization: false,
|
||||||
|
PassAuthorization: false,
|
||||||
|
PreferEmailToUser: false,
|
||||||
|
Prompt: "", // Change to "login" when ApprovalPrompt officially deprecated
|
||||||
|
ApprovalPrompt: "force",
|
||||||
|
UserIDClaim: "email",
|
||||||
|
InsecureOIDCAllowUnverifiedEmail: false,
|
||||||
|
SkipOIDCDiscovery: false,
|
||||||
|
LoggingFilename: "",
|
||||||
|
LoggingMaxSize: 100,
|
||||||
|
LoggingMaxAge: 7,
|
||||||
|
LoggingMaxBackups: 0,
|
||||||
|
LoggingLocalTime: true,
|
||||||
|
LoggingCompress: false,
|
||||||
|
ExcludeLoggingPaths: "",
|
||||||
|
SilencePingLogging: false,
|
||||||
|
StandardLogging: true,
|
||||||
|
StandardLoggingFormat: logger.DefaultStandardLoggingFormat,
|
||||||
|
RequestLogging: true,
|
||||||
|
RequestLoggingFormat: logger.DefaultRequestLoggingFormat,
|
||||||
|
AuthLogging: true,
|
||||||
|
AuthLoggingFormat: logger.DefaultAuthLoggingFormat,
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package main
|
package validation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -14,11 +14,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
oidc "github.com/coreos/go-oidc"
|
"github.com/coreos/go-oidc"
|
||||||
"github.com/dgrijalva/jwt-go"
|
"github.com/dgrijalva/jwt-go"
|
||||||
"github.com/mbland/hmacauth"
|
"github.com/mbland/hmacauth"
|
||||||
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/logging"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
||||||
sessionsapi "github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/encryption"
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/encryption"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/logger"
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/requests"
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/requests"
|
||||||
@ -27,197 +27,9 @@ import (
|
|||||||
"gopkg.in/natefinch/lumberjack.v2"
|
"gopkg.in/natefinch/lumberjack.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options holds Configuration Options that can be set by Command Line Flag,
|
|
||||||
// or Config File
|
|
||||||
type Options struct {
|
|
||||||
ProxyPrefix string `flag:"proxy-prefix" cfg:"proxy_prefix" env:"OAUTH2_PROXY_PROXY_PREFIX"`
|
|
||||||
PingPath string `flag:"ping-path" cfg:"ping_path" env:"OAUTH2_PROXY_PING_PATH"`
|
|
||||||
ProxyWebSockets bool `flag:"proxy-websockets" cfg:"proxy_websockets" env:"OAUTH2_PROXY_PROXY_WEBSOCKETS"`
|
|
||||||
HTTPAddress string `flag:"http-address" cfg:"http_address" env:"OAUTH2_PROXY_HTTP_ADDRESS"`
|
|
||||||
HTTPSAddress string `flag:"https-address" cfg:"https_address" env:"OAUTH2_PROXY_HTTPS_ADDRESS"`
|
|
||||||
ReverseProxy bool `flag:"reverse-proxy" cfg:"reverse_proxy" env:"OAUTH2_PROXY_REVERSE_PROXY"`
|
|
||||||
RealClientIPHeader string `flag:"real-client-ip-header" cfg:"real_client_ip_header" env:"OAUTH2_PROXY_REAL_CLIENT_IP_HEADER"`
|
|
||||||
ForceHTTPS bool `flag:"force-https" cfg:"force_https" env:"OAUTH2_PROXY_FORCE_HTTPS"`
|
|
||||||
RedirectURL string `flag:"redirect-url" cfg:"redirect_url" env:"OAUTH2_PROXY_REDIRECT_URL"`
|
|
||||||
ClientID string `flag:"client-id" cfg:"client_id" env:"OAUTH2_PROXY_CLIENT_ID"`
|
|
||||||
ClientSecret string `flag:"client-secret" cfg:"client_secret" env:"OAUTH2_PROXY_CLIENT_SECRET"`
|
|
||||||
ClientSecretFile string `flag:"client-secret-file" cfg:"client_secret_file" env:"OAUTH2_PROXY_CLIENT_SECRET_FILE"`
|
|
||||||
TLSCertFile string `flag:"tls-cert-file" cfg:"tls_cert_file" env:"OAUTH2_PROXY_TLS_CERT_FILE"`
|
|
||||||
TLSKeyFile string `flag:"tls-key-file" cfg:"tls_key_file" env:"OAUTH2_PROXY_TLS_KEY_FILE"`
|
|
||||||
|
|
||||||
AuthenticatedEmailsFile string `flag:"authenticated-emails-file" cfg:"authenticated_emails_file" env:"OAUTH2_PROXY_AUTHENTICATED_EMAILS_FILE"`
|
|
||||||
KeycloakGroup string `flag:"keycloak-group" cfg:"keycloak_group" env:"OAUTH2_PROXY_KEYCLOAK_GROUP"`
|
|
||||||
AzureTenant string `flag:"azure-tenant" cfg:"azure_tenant" env:"OAUTH2_PROXY_AZURE_TENANT"`
|
|
||||||
BitbucketTeam string `flag:"bitbucket-team" cfg:"bitbucket_team" env:"OAUTH2_PROXY_BITBUCKET_TEAM"`
|
|
||||||
BitbucketRepository string `flag:"bitbucket-repository" cfg:"bitbucket_repository" env:"OAUTH2_PROXY_BITBUCKET_REPOSITORY"`
|
|
||||||
EmailDomains []string `flag:"email-domain" cfg:"email_domains" env:"OAUTH2_PROXY_EMAIL_DOMAINS"`
|
|
||||||
WhitelistDomains []string `flag:"whitelist-domain" cfg:"whitelist_domains" env:"OAUTH2_PROXY_WHITELIST_DOMAINS"`
|
|
||||||
GitHubOrg string `flag:"github-org" cfg:"github_org" env:"OAUTH2_PROXY_GITHUB_ORG"`
|
|
||||||
GitHubTeam string `flag:"github-team" cfg:"github_team" env:"OAUTH2_PROXY_GITHUB_TEAM"`
|
|
||||||
GitHubRepo string `flag:"github-repo" cfg:"github_repo" env:"OAUTH2_PROXY_GITHUB_REPO"`
|
|
||||||
GitHubToken string `flag:"github-token" cfg:"github_token" env:"OAUTH2_PROXY_GITHUB_TOKEN"`
|
|
||||||
GitLabGroup string `flag:"gitlab-group" cfg:"gitlab_group" env:"OAUTH2_PROXY_GITLAB_GROUP"`
|
|
||||||
GoogleGroups []string `flag:"google-group" cfg:"google_group" env:"OAUTH2_PROXY_GOOGLE_GROUPS"`
|
|
||||||
GoogleAdminEmail string `flag:"google-admin-email" cfg:"google_admin_email" env:"OAUTH2_PROXY_GOOGLE_ADMIN_EMAIL"`
|
|
||||||
GoogleServiceAccountJSON string `flag:"google-service-account-json" cfg:"google_service_account_json" env:"OAUTH2_PROXY_GOOGLE_SERVICE_ACCOUNT_JSON"`
|
|
||||||
HtpasswdFile string `flag:"htpasswd-file" cfg:"htpasswd_file" env:"OAUTH2_PROXY_HTPASSWD_FILE"`
|
|
||||||
DisplayHtpasswdForm bool `flag:"display-htpasswd-form" cfg:"display_htpasswd_form" env:"OAUTH2_PROXY_DISPLAY_HTPASSWD_FORM"`
|
|
||||||
CustomTemplatesDir string `flag:"custom-templates-dir" cfg:"custom_templates_dir" env:"OAUTH2_PROXY_CUSTOM_TEMPLATES_DIR"`
|
|
||||||
Banner string `flag:"banner" cfg:"banner" env:"OAUTH2_PROXY_BANNER"`
|
|
||||||
Footer string `flag:"footer" cfg:"footer" env:"OAUTH2_PROXY_FOOTER"`
|
|
||||||
|
|
||||||
Cookie options.CookieOptions `cfg:",squash"`
|
|
||||||
Session options.SessionOptions `cfg:",squash"`
|
|
||||||
|
|
||||||
Upstreams []string `flag:"upstream" cfg:"upstreams" env:"OAUTH2_PROXY_UPSTREAMS"`
|
|
||||||
SkipAuthRegex []string `flag:"skip-auth-regex" cfg:"skip_auth_regex" env:"OAUTH2_PROXY_SKIP_AUTH_REGEX"`
|
|
||||||
SkipJwtBearerTokens bool `flag:"skip-jwt-bearer-tokens" cfg:"skip_jwt_bearer_tokens" env:"OAUTH2_PROXY_SKIP_JWT_BEARER_TOKENS"`
|
|
||||||
ExtraJwtIssuers []string `flag:"extra-jwt-issuers" cfg:"extra_jwt_issuers" env:"OAUTH2_PROXY_EXTRA_JWT_ISSUERS"`
|
|
||||||
PassBasicAuth bool `flag:"pass-basic-auth" cfg:"pass_basic_auth" env:"OAUTH2_PROXY_PASS_BASIC_AUTH"`
|
|
||||||
SetBasicAuth bool `flag:"set-basic-auth" cfg:"set_basic_auth" env:"OAUTH2_PROXY_SET_BASIC_AUTH"`
|
|
||||||
PreferEmailToUser bool `flag:"prefer-email-to-user" cfg:"prefer_email_to_user" env:"OAUTH2_PROXY_PREFER_EMAIL_TO_USER"`
|
|
||||||
BasicAuthPassword string `flag:"basic-auth-password" cfg:"basic_auth_password" env:"OAUTH2_PROXY_BASIC_AUTH_PASSWORD"`
|
|
||||||
PassAccessToken bool `flag:"pass-access-token" cfg:"pass_access_token" env:"OAUTH2_PROXY_PASS_ACCESS_TOKEN"`
|
|
||||||
PassHostHeader bool `flag:"pass-host-header" cfg:"pass_host_header" env:"OAUTH2_PROXY_PASS_HOST_HEADER"`
|
|
||||||
SkipProviderButton bool `flag:"skip-provider-button" cfg:"skip_provider_button" env:"OAUTH2_PROXY_SKIP_PROVIDER_BUTTON"`
|
|
||||||
PassUserHeaders bool `flag:"pass-user-headers" cfg:"pass_user_headers" env:"OAUTH2_PROXY_PASS_USER_HEADERS"`
|
|
||||||
SSLInsecureSkipVerify bool `flag:"ssl-insecure-skip-verify" cfg:"ssl_insecure_skip_verify" env:"OAUTH2_PROXY_SSL_INSECURE_SKIP_VERIFY"`
|
|
||||||
SSLUpstreamInsecureSkipVerify bool `flag:"ssl-upstream-insecure-skip-verify" cfg:"ssl_upstream_insecure_skip_verify" env:"OAUTH2_PROXY_SSL_UPSTREAM_INSECURE_SKIP_VERIFY"`
|
|
||||||
SetXAuthRequest bool `flag:"set-xauthrequest" cfg:"set_xauthrequest" env:"OAUTH2_PROXY_SET_XAUTHREQUEST"`
|
|
||||||
SetAuthorization bool `flag:"set-authorization-header" cfg:"set_authorization_header" env:"OAUTH2_PROXY_SET_AUTHORIZATION_HEADER"`
|
|
||||||
PassAuthorization bool `flag:"pass-authorization-header" cfg:"pass_authorization_header" env:"OAUTH2_PROXY_PASS_AUTHORIZATION_HEADER"`
|
|
||||||
SkipAuthPreflight bool `flag:"skip-auth-preflight" cfg:"skip_auth_preflight" env:"OAUTH2_PROXY_SKIP_AUTH_PREFLIGHT"`
|
|
||||||
FlushInterval time.Duration `flag:"flush-interval" cfg:"flush_interval" env:"OAUTH2_PROXY_FLUSH_INTERVAL"`
|
|
||||||
|
|
||||||
// These options allow for other providers besides Google, with
|
|
||||||
// potential overrides.
|
|
||||||
Provider string `flag:"provider" cfg:"provider" env:"OAUTH2_PROXY_PROVIDER"`
|
|
||||||
ProviderName string `flag:"provider-display-name" cfg:"provider_display_name" env:"OAUTH2_PROXY_PROVIDER_DISPLAY_NAME"`
|
|
||||||
OIDCIssuerURL string `flag:"oidc-issuer-url" cfg:"oidc_issuer_url" env:"OAUTH2_PROXY_OIDC_ISSUER_URL"`
|
|
||||||
InsecureOIDCAllowUnverifiedEmail bool `flag:"insecure-oidc-allow-unverified-email" cfg:"insecure_oidc_allow_unverified_email" env:"OAUTH2_PROXY_INSECURE_OIDC_ALLOW_UNVERIFIED_EMAIL"`
|
|
||||||
InsecureOIDCSkipIssuerVerification bool `flag:"insecure-oidc-skip-issuer-verification" cfg:"insecure_oidc_skip_issuer_verification" env:"OAUTH2_PROXY_INSECURE_OIDC_SKIP_ISSUER_VERIFICATION"`
|
|
||||||
SkipOIDCDiscovery bool `flag:"skip-oidc-discovery" cfg:"skip_oidc_discovery" env:"OAUTH2_PROXY_SKIP_OIDC_DISCOVERY"`
|
|
||||||
OIDCJwksURL string `flag:"oidc-jwks-url" cfg:"oidc_jwks_url" env:"OAUTH2_PROXY_OIDC_JWKS_URL"`
|
|
||||||
LoginURL string `flag:"login-url" cfg:"login_url" env:"OAUTH2_PROXY_LOGIN_URL"`
|
|
||||||
RedeemURL string `flag:"redeem-url" cfg:"redeem_url" env:"OAUTH2_PROXY_REDEEM_URL"`
|
|
||||||
ProfileURL string `flag:"profile-url" cfg:"profile_url" env:"OAUTH2_PROXY_PROFILE_URL"`
|
|
||||||
ProtectedResource string `flag:"resource" cfg:"resource" env:"OAUTH2_PROXY_RESOURCE"`
|
|
||||||
ValidateURL string `flag:"validate-url" cfg:"validate_url" env:"OAUTH2_PROXY_VALIDATE_URL"`
|
|
||||||
Scope string `flag:"scope" cfg:"scope" env:"OAUTH2_PROXY_SCOPE"`
|
|
||||||
Prompt string `flag:"prompt" cfg:"prompt" env:"OAUTH2_PROXY_PROMPT"`
|
|
||||||
ApprovalPrompt string `flag:"approval-prompt" cfg:"approval_prompt" env:"OAUTH2_PROXY_APPROVAL_PROMPT"` // Deprecated by OIDC 1.0
|
|
||||||
UserIDClaim string `flag:"user-id-claim" cfg:"user_id_claim" env:"OAUTH2_PROXY_USER_ID_CLAIM"`
|
|
||||||
|
|
||||||
// Configuration values for logging
|
|
||||||
LoggingFilename string `flag:"logging-filename" cfg:"logging_filename" env:"OAUTH2_PROXY_LOGGING_FILENAME"`
|
|
||||||
LoggingMaxSize int `flag:"logging-max-size" cfg:"logging_max_size" env:"OAUTH2_PROXY_LOGGING_MAX_SIZE"`
|
|
||||||
LoggingMaxAge int `flag:"logging-max-age" cfg:"logging_max_age" env:"OAUTH2_PROXY_LOGGING_MAX_AGE"`
|
|
||||||
LoggingMaxBackups int `flag:"logging-max-backups" cfg:"logging_max_backups" env:"OAUTH2_PROXY_LOGGING_MAX_BACKUPS"`
|
|
||||||
LoggingLocalTime bool `flag:"logging-local-time" cfg:"logging_local_time" env:"OAUTH2_PROXY_LOGGING_LOCAL_TIME"`
|
|
||||||
LoggingCompress bool `flag:"logging-compress" cfg:"logging_compress" env:"OAUTH2_PROXY_LOGGING_COMPRESS"`
|
|
||||||
StandardLogging bool `flag:"standard-logging" cfg:"standard_logging" env:"OAUTH2_PROXY_STANDARD_LOGGING"`
|
|
||||||
StandardLoggingFormat string `flag:"standard-logging-format" cfg:"standard_logging_format" env:"OAUTH2_PROXY_STANDARD_LOGGING_FORMAT"`
|
|
||||||
RequestLogging bool `flag:"request-logging" cfg:"request_logging" env:"OAUTH2_PROXY_REQUEST_LOGGING"`
|
|
||||||
RequestLoggingFormat string `flag:"request-logging-format" cfg:"request_logging_format" env:"OAUTH2_PROXY_REQUEST_LOGGING_FORMAT"`
|
|
||||||
ExcludeLoggingPaths string `flag:"exclude-logging-paths" cfg:"exclude_logging_paths" env:"OAUTH2_PROXY_EXCLUDE_LOGGING_PATHS"`
|
|
||||||
SilencePingLogging bool `flag:"silence-ping-logging" cfg:"silence_ping_logging" env:"OAUTH2_PROXY_SILENCE_PING_LOGGING"`
|
|
||||||
AuthLogging bool `flag:"auth-logging" cfg:"auth_logging" env:"OAUTH2_PROXY_LOGGING_AUTH_LOGGING"`
|
|
||||||
AuthLoggingFormat string `flag:"auth-logging-format" cfg:"auth_logging_format" env:"OAUTH2_PROXY_AUTH_LOGGING_FORMAT"`
|
|
||||||
SignatureKey string `flag:"signature-key" cfg:"signature_key" env:"OAUTH2_PROXY_SIGNATURE_KEY"`
|
|
||||||
AcrValues string `flag:"acr-values" cfg:"acr_values" env:"OAUTH2_PROXY_ACR_VALUES"`
|
|
||||||
JWTKey string `flag:"jwt-key" cfg:"jwt_key" env:"OAUTH2_PROXY_JWT_KEY"`
|
|
||||||
JWTKeyFile string `flag:"jwt-key-file" cfg:"jwt_key_file" env:"OAUTH2_PROXY_JWT_KEY_FILE"`
|
|
||||||
PubJWKURL string `flag:"pubjwk-url" cfg:"pubjwk_url" env:"OAUTH2_PROXY_PUBJWK_URL"`
|
|
||||||
GCPHealthChecks bool `flag:"gcp-healthchecks" cfg:"gcp_healthchecks" env:"OAUTH2_PROXY_GCP_HEALTHCHECKS"`
|
|
||||||
|
|
||||||
// internal values that are set after config validation
|
|
||||||
redirectURL *url.URL
|
|
||||||
proxyURLs []*url.URL
|
|
||||||
compiledRegex []*regexp.Regexp
|
|
||||||
provider providers.Provider
|
|
||||||
sessionStore sessionsapi.SessionStore
|
|
||||||
signatureData *SignatureData
|
|
||||||
oidcVerifier *oidc.IDTokenVerifier
|
|
||||||
jwtBearerVerifiers []*oidc.IDTokenVerifier
|
|
||||||
realClientIPParser realClientIPParser
|
|
||||||
}
|
|
||||||
|
|
||||||
// SignatureData holds hmacauth signature hash and key
|
|
||||||
type SignatureData struct {
|
|
||||||
hash crypto.Hash
|
|
||||||
key string
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewOptions constructs a new Options with defaulted values
|
|
||||||
func NewOptions() *Options {
|
|
||||||
return &Options{
|
|
||||||
ProxyPrefix: "/oauth2",
|
|
||||||
PingPath: "/ping",
|
|
||||||
ProxyWebSockets: true,
|
|
||||||
HTTPAddress: "127.0.0.1:4180",
|
|
||||||
HTTPSAddress: ":443",
|
|
||||||
ForceHTTPS: false,
|
|
||||||
DisplayHtpasswdForm: true,
|
|
||||||
Cookie: options.CookieOptions{
|
|
||||||
Name: "_oauth2_proxy",
|
|
||||||
Secure: true,
|
|
||||||
HTTPOnly: true,
|
|
||||||
Expire: time.Duration(168) * time.Hour,
|
|
||||||
Refresh: time.Duration(0),
|
|
||||||
},
|
|
||||||
Session: options.SessionOptions{
|
|
||||||
Type: "cookie",
|
|
||||||
},
|
|
||||||
SetXAuthRequest: false,
|
|
||||||
SkipAuthPreflight: false,
|
|
||||||
PassBasicAuth: true,
|
|
||||||
SetBasicAuth: false,
|
|
||||||
PassUserHeaders: true,
|
|
||||||
PassAccessToken: false,
|
|
||||||
PassHostHeader: true,
|
|
||||||
SetAuthorization: false,
|
|
||||||
PassAuthorization: false,
|
|
||||||
PreferEmailToUser: false,
|
|
||||||
Prompt: "", // Change to "login" when ApprovalPrompt officially deprecated
|
|
||||||
ApprovalPrompt: "force",
|
|
||||||
UserIDClaim: "email",
|
|
||||||
InsecureOIDCAllowUnverifiedEmail: false,
|
|
||||||
SkipOIDCDiscovery: false,
|
|
||||||
LoggingFilename: "",
|
|
||||||
LoggingMaxSize: 100,
|
|
||||||
LoggingMaxAge: 7,
|
|
||||||
LoggingMaxBackups: 0,
|
|
||||||
LoggingLocalTime: true,
|
|
||||||
LoggingCompress: false,
|
|
||||||
ExcludeLoggingPaths: "",
|
|
||||||
SilencePingLogging: false,
|
|
||||||
StandardLogging: true,
|
|
||||||
StandardLoggingFormat: logger.DefaultStandardLoggingFormat,
|
|
||||||
RequestLogging: true,
|
|
||||||
RequestLoggingFormat: logger.DefaultRequestLoggingFormat,
|
|
||||||
AuthLogging: true,
|
|
||||||
AuthLoggingFormat: logger.DefaultAuthLoggingFormat,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// jwtIssuer hold parsed JWT issuer info that's used to construct a verifier.
|
|
||||||
type jwtIssuer struct {
|
|
||||||
issuerURI string
|
|
||||||
audience string
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseURL(toParse string, urltype string, msgs []string) (*url.URL, []string) {
|
|
||||||
parsed, err := url.Parse(toParse)
|
|
||||||
if err != nil {
|
|
||||||
return nil, append(msgs, fmt.Sprintf(
|
|
||||||
"error parsing %s-url=%q %s", urltype, toParse, err))
|
|
||||||
}
|
|
||||||
return parsed, msgs
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate checks that required options are set and validates those that they
|
// Validate checks that required options are set and validates those that they
|
||||||
// are of the correct format
|
// are of the correct format
|
||||||
func (o *Options) Validate() error {
|
func Validate(o *options.Options) error {
|
||||||
if o.SSLInsecureSkipVerify {
|
if o.SSLInsecureSkipVerify {
|
||||||
// TODO: Accept a certificate bundle.
|
// TODO: Accept a certificate bundle.
|
||||||
insecureTransport := &http.Transport{
|
insecureTransport := &http.Transport{
|
||||||
@ -234,7 +46,7 @@ func (o *Options) Validate() error {
|
|||||||
msgs = append(msgs, "missing setting: client-id")
|
msgs = append(msgs, "missing setting: client-id")
|
||||||
}
|
}
|
||||||
// login.gov uses a signed JWT to authenticate, not a client-secret
|
// login.gov uses a signed JWT to authenticate, not a client-secret
|
||||||
if o.Provider != "login.gov" {
|
if o.ProviderType != "login.gov" {
|
||||||
if o.ClientSecret == "" && o.ClientSecretFile == "" {
|
if o.ClientSecret == "" && o.ClientSecretFile == "" {
|
||||||
msgs = append(msgs, "missing setting: client-secret or client-secret-file")
|
msgs = append(msgs, "missing setting: client-secret or client-secret-file")
|
||||||
}
|
}
|
||||||
@ -311,20 +123,20 @@ func (o *Options) Validate() error {
|
|||||||
msgs = append(msgs, "missing setting: oidc-jwks-url")
|
msgs = append(msgs, "missing setting: oidc-jwks-url")
|
||||||
}
|
}
|
||||||
keySet := oidc.NewRemoteKeySet(ctx, o.OIDCJwksURL)
|
keySet := oidc.NewRemoteKeySet(ctx, o.OIDCJwksURL)
|
||||||
o.oidcVerifier = oidc.NewVerifier(o.OIDCIssuerURL, keySet, &oidc.Config{
|
o.SetOIDCVerifier(oidc.NewVerifier(o.OIDCIssuerURL, keySet, &oidc.Config{
|
||||||
ClientID: o.ClientID,
|
ClientID: o.ClientID,
|
||||||
SkipIssuerCheck: o.InsecureOIDCSkipIssuerVerification,
|
SkipIssuerCheck: o.InsecureOIDCSkipIssuerVerification,
|
||||||
})
|
}))
|
||||||
} else {
|
} else {
|
||||||
// Configure discoverable provider data.
|
// Configure discoverable provider data.
|
||||||
provider, err := oidc.NewProvider(ctx, o.OIDCIssuerURL)
|
provider, err := oidc.NewProvider(ctx, o.OIDCIssuerURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
o.oidcVerifier = provider.Verifier(&oidc.Config{
|
o.SetOIDCVerifier(provider.Verifier(&oidc.Config{
|
||||||
ClientID: o.ClientID,
|
ClientID: o.ClientID,
|
||||||
SkipIssuerCheck: o.InsecureOIDCSkipIssuerVerification,
|
SkipIssuerCheck: o.InsecureOIDCSkipIssuerVerification,
|
||||||
})
|
}))
|
||||||
|
|
||||||
o.LoginURL = provider.Endpoint().AuthURL
|
o.LoginURL = provider.Endpoint().AuthURL
|
||||||
o.RedeemURL = provider.Endpoint().TokenURL
|
o.RedeemURL = provider.Endpoint().TokenURL
|
||||||
@ -340,8 +152,8 @@ func (o *Options) Validate() error {
|
|||||||
|
|
||||||
if o.SkipJwtBearerTokens {
|
if o.SkipJwtBearerTokens {
|
||||||
// If we are using an oidc provider, go ahead and add that provider to the list
|
// If we are using an oidc provider, go ahead and add that provider to the list
|
||||||
if o.oidcVerifier != nil {
|
if o.GetOIDCVerifier() != nil {
|
||||||
o.jwtBearerVerifiers = append(o.jwtBearerVerifiers, o.oidcVerifier)
|
o.SetJWTBearerVerifiers(append(o.GetJWTBearerVerifiers(), o.GetOIDCVerifier()))
|
||||||
}
|
}
|
||||||
// Configure extra issuers
|
// Configure extra issuers
|
||||||
if len(o.ExtraJwtIssuers) > 0 {
|
if len(o.ExtraJwtIssuers) > 0 {
|
||||||
@ -352,12 +164,14 @@ func (o *Options) Validate() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
msgs = append(msgs, fmt.Sprintf("error building verifiers: %s", err))
|
msgs = append(msgs, fmt.Sprintf("error building verifiers: %s", err))
|
||||||
}
|
}
|
||||||
o.jwtBearerVerifiers = append(o.jwtBearerVerifiers, verifier)
|
o.SetJWTBearerVerifiers(append(o.GetJWTBearerVerifiers(), verifier))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
o.redirectURL, msgs = parseURL(o.RedirectURL, "redirect", msgs)
|
var redirectURL *url.URL
|
||||||
|
redirectURL, msgs = parseURL(o.RawRedirectURL, "redirect", msgs)
|
||||||
|
o.SetRedirectURL(redirectURL)
|
||||||
|
|
||||||
for _, u := range o.Upstreams {
|
for _, u := range o.Upstreams {
|
||||||
upstreamURL, err := url.Parse(u)
|
upstreamURL, err := url.Parse(u)
|
||||||
@ -367,7 +181,7 @@ func (o *Options) Validate() error {
|
|||||||
if upstreamURL.Path == "" {
|
if upstreamURL.Path == "" {
|
||||||
upstreamURL.Path = "/"
|
upstreamURL.Path = "/"
|
||||||
}
|
}
|
||||||
o.proxyURLs = append(o.proxyURLs, upstreamURL)
|
o.SetProxyURLs(append(o.GetProxyURLs(), upstreamURL))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,7 +191,7 @@ func (o *Options) Validate() error {
|
|||||||
msgs = append(msgs, fmt.Sprintf("error compiling regex=%q %s", u, err))
|
msgs = append(msgs, fmt.Sprintf("error compiling regex=%q %s", u, err))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
o.compiledRegex = append(o.compiledRegex, compiledRegex)
|
o.SetCompiledRegex(append(o.GetCompiledRegex(), compiledRegex))
|
||||||
}
|
}
|
||||||
msgs = parseProviderInfo(o, msgs)
|
msgs = parseProviderInfo(o, msgs)
|
||||||
|
|
||||||
@ -418,7 +232,7 @@ func (o *Options) Validate() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
msgs = append(msgs, fmt.Sprintf("error initialising session storage: %v", err))
|
msgs = append(msgs, fmt.Sprintf("error initialising session storage: %v", err))
|
||||||
} else {
|
} else {
|
||||||
o.sessionStore = sessionStore
|
o.SetSessionStore(sessionStore)
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.Cookie.Refresh >= o.Cookie.Expire {
|
if o.Cookie.Refresh >= o.Cookie.Expire {
|
||||||
@ -458,10 +272,11 @@ func (o *Options) Validate() error {
|
|||||||
msgs = setupLogger(o, msgs)
|
msgs = setupLogger(o, msgs)
|
||||||
|
|
||||||
if o.ReverseProxy {
|
if o.ReverseProxy {
|
||||||
o.realClientIPParser, err = getRealClientIPParser(o.RealClientIPHeader)
|
parser, err := logging.GetRealClientIPParser(o.RealClientIPHeader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msgs = append(msgs, fmt.Sprintf("real_client_ip_header (%s) not accepted parameter value: %v", o.RealClientIPHeader, err))
|
msgs = append(msgs, fmt.Sprintf("real_client_ip_header (%s) not accepted parameter value: %v", o.RealClientIPHeader, err))
|
||||||
}
|
}
|
||||||
|
o.SetRealClientIPParser(parser)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(msgs) != 0 {
|
if len(msgs) != 0 {
|
||||||
@ -471,7 +286,7 @@ func (o *Options) Validate() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseProviderInfo(o *Options, msgs []string) []string {
|
func parseProviderInfo(o *options.Options, msgs []string) []string {
|
||||||
p := &providers.ProviderData{
|
p := &providers.ProviderData{
|
||||||
Scope: o.Scope,
|
Scope: o.Scope,
|
||||||
ClientID: o.ClientID,
|
ClientID: o.ClientID,
|
||||||
@ -487,8 +302,8 @@ func parseProviderInfo(o *Options, msgs []string) []string {
|
|||||||
p.ValidateURL, msgs = parseURL(o.ValidateURL, "validate", msgs)
|
p.ValidateURL, msgs = parseURL(o.ValidateURL, "validate", msgs)
|
||||||
p.ProtectedResource, msgs = parseURL(o.ProtectedResource, "resource", msgs)
|
p.ProtectedResource, msgs = parseURL(o.ProtectedResource, "resource", msgs)
|
||||||
|
|
||||||
o.provider = providers.New(o.Provider, p)
|
o.SetProvider(providers.New(o.ProviderType, p))
|
||||||
switch p := o.provider.(type) {
|
switch p := o.GetProvider().(type) {
|
||||||
case *providers.AzureProvider:
|
case *providers.AzureProvider:
|
||||||
p.Configure(o.AzureTenant)
|
p.Configure(o.AzureTenant)
|
||||||
case *providers.GitHubProvider:
|
case *providers.GitHubProvider:
|
||||||
@ -511,18 +326,18 @@ func parseProviderInfo(o *Options, msgs []string) []string {
|
|||||||
case *providers.OIDCProvider:
|
case *providers.OIDCProvider:
|
||||||
p.AllowUnverifiedEmail = o.InsecureOIDCAllowUnverifiedEmail
|
p.AllowUnverifiedEmail = o.InsecureOIDCAllowUnverifiedEmail
|
||||||
p.UserIDClaim = o.UserIDClaim
|
p.UserIDClaim = o.UserIDClaim
|
||||||
if o.oidcVerifier == nil {
|
if o.GetOIDCVerifier() == nil {
|
||||||
msgs = append(msgs, "oidc provider requires an oidc issuer URL")
|
msgs = append(msgs, "oidc provider requires an oidc issuer URL")
|
||||||
} else {
|
} else {
|
||||||
p.Verifier = o.oidcVerifier
|
p.Verifier = o.GetOIDCVerifier()
|
||||||
}
|
}
|
||||||
case *providers.GitLabProvider:
|
case *providers.GitLabProvider:
|
||||||
p.AllowUnverifiedEmail = o.InsecureOIDCAllowUnverifiedEmail
|
p.AllowUnverifiedEmail = o.InsecureOIDCAllowUnverifiedEmail
|
||||||
p.Group = o.GitLabGroup
|
p.Group = o.GitLabGroup
|
||||||
p.EmailDomains = o.EmailDomains
|
p.EmailDomains = o.EmailDomains
|
||||||
|
|
||||||
if o.oidcVerifier != nil {
|
if o.GetOIDCVerifier() != nil {
|
||||||
p.Verifier = o.oidcVerifier
|
p.Verifier = o.GetOIDCVerifier()
|
||||||
} else {
|
} else {
|
||||||
// Initialize with default verifier for gitlab.com
|
// Initialize with default verifier for gitlab.com
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
@ -573,7 +388,7 @@ func parseProviderInfo(o *Options, msgs []string) []string {
|
|||||||
return msgs
|
return msgs
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseSignatureKey(o *Options, msgs []string) []string {
|
func parseSignatureKey(o *options.Options, msgs []string) []string {
|
||||||
if o.SignatureKey == "" {
|
if o.SignatureKey == "" {
|
||||||
return msgs
|
return msgs
|
||||||
}
|
}
|
||||||
@ -591,7 +406,7 @@ func parseSignatureKey(o *Options, msgs []string) []string {
|
|||||||
return append(msgs, "unsupported signature hash algorithm: "+
|
return append(msgs, "unsupported signature hash algorithm: "+
|
||||||
o.SignatureKey)
|
o.SignatureKey)
|
||||||
}
|
}
|
||||||
o.signatureData = &SignatureData{hash: hash, key: secretKey}
|
o.SetSignatureData(&options.SignatureData{Hash: hash, Key: secretKey})
|
||||||
return msgs
|
return msgs
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -634,7 +449,7 @@ func newVerifierFromJwtIssuer(jwtIssuer jwtIssuer) (*oidc.IDTokenVerifier, error
|
|||||||
return verifier, nil
|
return verifier, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateCookieName(o *Options, msgs []string) []string {
|
func validateCookieName(o *options.Options, msgs []string) []string {
|
||||||
cookie := &http.Cookie{Name: o.Cookie.Name}
|
cookie := &http.Cookie{Name: o.Cookie.Name}
|
||||||
if cookie.String() == "" {
|
if cookie.String() == "" {
|
||||||
return append(msgs, fmt.Sprintf("invalid cookie name: %q", o.Cookie.Name))
|
return append(msgs, fmt.Sprintf("invalid cookie name: %q", o.Cookie.Name))
|
||||||
@ -642,7 +457,7 @@ func validateCookieName(o *Options, msgs []string) []string {
|
|||||||
return msgs
|
return msgs
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupLogger(o *Options, msgs []string) []string {
|
func setupLogger(o *options.Options, msgs []string) []string {
|
||||||
// Setup the log file
|
// Setup the log file
|
||||||
if len(o.LoggingFilename) > 0 {
|
if len(o.LoggingFilename) > 0 {
|
||||||
// Validate that the file/dir can be written
|
// Validate that the file/dir can be written
|
||||||
@ -681,7 +496,7 @@ func setupLogger(o *Options, msgs []string) []string {
|
|||||||
logger.SetAuthTemplate(o.AuthLoggingFormat)
|
logger.SetAuthTemplate(o.AuthLoggingFormat)
|
||||||
logger.SetReqTemplate(o.RequestLoggingFormat)
|
logger.SetReqTemplate(o.RequestLoggingFormat)
|
||||||
logger.SetGetClientFunc(func(r *http.Request) string {
|
logger.SetGetClientFunc(func(r *http.Request) string {
|
||||||
return getClientString(o.realClientIPParser, r, false)
|
return logging.GetClientString(o.GetRealClientIPParser(), r, false)
|
||||||
})
|
})
|
||||||
|
|
||||||
excludePaths := make([]string, 0)
|
excludePaths := make([]string, 0)
|
||||||
@ -698,3 +513,18 @@ func setupLogger(o *Options, msgs []string) []string {
|
|||||||
|
|
||||||
return msgs
|
return msgs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// jwtIssuer hold parsed JWT issuer info that's used to construct a verifier.
|
||||||
|
type jwtIssuer struct {
|
||||||
|
issuerURI string
|
||||||
|
audience string
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseURL(toParse string, urltype string, msgs []string) (*url.URL, []string) {
|
||||||
|
parsed, err := url.Parse(toParse)
|
||||||
|
if err != nil {
|
||||||
|
return nil, append(msgs, fmt.Sprintf(
|
||||||
|
"error parsing %s-url=%q %s", urltype, toParse, err))
|
||||||
|
}
|
||||||
|
return parsed, msgs
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package main
|
package validation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto"
|
"crypto"
|
||||||
@ -10,6 +10,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -19,8 +20,8 @@ const (
|
|||||||
clientSecret = "xyzzyplugh"
|
clientSecret = "xyzzyplugh"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testOptions() *Options {
|
func testOptions() *options.Options {
|
||||||
o := NewOptions()
|
o := options.NewOptions()
|
||||||
o.Upstreams = append(o.Upstreams, "http://127.0.0.1:8080/")
|
o.Upstreams = append(o.Upstreams, "http://127.0.0.1:8080/")
|
||||||
o.Cookie.Secret = cookieSecret
|
o.Cookie.Secret = cookieSecret
|
||||||
o.ClientID = clientID
|
o.ClientID = clientID
|
||||||
@ -37,9 +38,9 @@ func errorMsg(msgs []string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewOptions(t *testing.T) {
|
func TestNewOptions(t *testing.T) {
|
||||||
o := NewOptions()
|
o := options.NewOptions()
|
||||||
o.EmailDomains = []string{"*"}
|
o.EmailDomains = []string{"*"}
|
||||||
err := o.Validate()
|
err := Validate(o)
|
||||||
assert.NotEqual(t, nil, err)
|
assert.NotEqual(t, nil, err)
|
||||||
|
|
||||||
expected := errorMsg([]string{
|
expected := errorMsg([]string{
|
||||||
@ -50,15 +51,15 @@ func TestNewOptions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestClientSecretFileOptionFails(t *testing.T) {
|
func TestClientSecretFileOptionFails(t *testing.T) {
|
||||||
o := NewOptions()
|
o := options.NewOptions()
|
||||||
o.Cookie.Secret = cookieSecret
|
o.Cookie.Secret = cookieSecret
|
||||||
o.ClientID = clientID
|
o.ClientID = clientID
|
||||||
o.ClientSecretFile = clientSecret
|
o.ClientSecretFile = clientSecret
|
||||||
o.EmailDomains = []string{"*"}
|
o.EmailDomains = []string{"*"}
|
||||||
err := o.Validate()
|
err := Validate(o)
|
||||||
assert.NotEqual(t, nil, err)
|
assert.NotEqual(t, nil, err)
|
||||||
|
|
||||||
p := o.provider.Data()
|
p := o.GetProvider().Data()
|
||||||
assert.Equal(t, clientSecret, p.ClientSecretFile)
|
assert.Equal(t, clientSecret, p.ClientSecretFile)
|
||||||
assert.Equal(t, "", p.ClientSecret)
|
assert.Equal(t, "", p.ClientSecret)
|
||||||
|
|
||||||
@ -80,15 +81,15 @@ func TestClientSecretFileOption(t *testing.T) {
|
|||||||
clientSecretFileName := f.Name()
|
clientSecretFileName := f.Name()
|
||||||
defer os.Remove(clientSecretFileName)
|
defer os.Remove(clientSecretFileName)
|
||||||
|
|
||||||
o := NewOptions()
|
o := options.NewOptions()
|
||||||
o.Cookie.Secret = cookieSecret
|
o.Cookie.Secret = cookieSecret
|
||||||
o.ClientID = clientID
|
o.ClientID = clientID
|
||||||
o.ClientSecretFile = clientSecretFileName
|
o.ClientSecretFile = clientSecretFileName
|
||||||
o.EmailDomains = []string{"*"}
|
o.EmailDomains = []string{"*"}
|
||||||
err = o.Validate()
|
err = Validate(o)
|
||||||
assert.Equal(t, nil, err)
|
assert.Equal(t, nil, err)
|
||||||
|
|
||||||
p := o.provider.Data()
|
p := o.GetProvider().Data()
|
||||||
assert.Equal(t, clientSecretFileName, p.ClientSecretFile)
|
assert.Equal(t, clientSecretFileName, p.ClientSecretFile)
|
||||||
assert.Equal(t, "", p.ClientSecret)
|
assert.Equal(t, "", p.ClientSecret)
|
||||||
|
|
||||||
@ -100,7 +101,7 @@ func TestClientSecretFileOption(t *testing.T) {
|
|||||||
func TestGoogleGroupOptions(t *testing.T) {
|
func TestGoogleGroupOptions(t *testing.T) {
|
||||||
o := testOptions()
|
o := testOptions()
|
||||||
o.GoogleGroups = []string{"googlegroup"}
|
o.GoogleGroups = []string{"googlegroup"}
|
||||||
err := o.Validate()
|
err := Validate(o)
|
||||||
assert.NotEqual(t, nil, err)
|
assert.NotEqual(t, nil, err)
|
||||||
|
|
||||||
expected := errorMsg([]string{
|
expected := errorMsg([]string{
|
||||||
@ -114,7 +115,7 @@ func TestGoogleGroupInvalidFile(t *testing.T) {
|
|||||||
o.GoogleGroups = []string{"test_group"}
|
o.GoogleGroups = []string{"test_group"}
|
||||||
o.GoogleAdminEmail = "admin@example.com"
|
o.GoogleAdminEmail = "admin@example.com"
|
||||||
o.GoogleServiceAccountJSON = "file_doesnt_exist.json"
|
o.GoogleServiceAccountJSON = "file_doesnt_exist.json"
|
||||||
err := o.Validate()
|
err := Validate(o)
|
||||||
assert.NotEqual(t, nil, err)
|
assert.NotEqual(t, nil, err)
|
||||||
|
|
||||||
expected := errorMsg([]string{
|
expected := errorMsg([]string{
|
||||||
@ -125,36 +126,36 @@ func TestGoogleGroupInvalidFile(t *testing.T) {
|
|||||||
|
|
||||||
func TestInitializedOptions(t *testing.T) {
|
func TestInitializedOptions(t *testing.T) {
|
||||||
o := testOptions()
|
o := testOptions()
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, Validate(o))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that it's not worth testing nonparseable URLs, since url.Parse()
|
// Note that it's not worth testing nonparseable URLs, since url.Parse()
|
||||||
// seems to parse damn near anything.
|
// seems to parse damn near anything.
|
||||||
func TestRedirectURL(t *testing.T) {
|
func TestRedirectURL(t *testing.T) {
|
||||||
o := testOptions()
|
o := testOptions()
|
||||||
o.RedirectURL = "https://myhost.com/oauth2/callback"
|
o.RawRedirectURL = "https://myhost.com/oauth2/callback"
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, Validate(o))
|
||||||
expected := &url.URL{
|
expected := &url.URL{
|
||||||
Scheme: "https", Host: "myhost.com", Path: "/oauth2/callback"}
|
Scheme: "https", Host: "myhost.com", Path: "/oauth2/callback"}
|
||||||
assert.Equal(t, expected, o.redirectURL)
|
assert.Equal(t, expected, o.GetRedirectURL())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProxyURLs(t *testing.T) {
|
func TestProxyURLs(t *testing.T) {
|
||||||
o := testOptions()
|
o := testOptions()
|
||||||
o.Upstreams = append(o.Upstreams, "http://127.0.0.1:8081")
|
o.Upstreams = append(o.Upstreams, "http://127.0.0.1:8081")
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, Validate(o))
|
||||||
expected := []*url.URL{
|
expected := []*url.URL{
|
||||||
{Scheme: "http", Host: "127.0.0.1:8080", Path: "/"},
|
{Scheme: "http", Host: "127.0.0.1:8080", Path: "/"},
|
||||||
// note the '/' was added
|
// note the '/' was added
|
||||||
{Scheme: "http", Host: "127.0.0.1:8081", Path: "/"},
|
{Scheme: "http", Host: "127.0.0.1:8081", Path: "/"},
|
||||||
}
|
}
|
||||||
assert.Equal(t, expected, o.proxyURLs)
|
assert.Equal(t, expected, o.GetProxyURLs())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProxyURLsError(t *testing.T) {
|
func TestProxyURLsError(t *testing.T) {
|
||||||
o := testOptions()
|
o := testOptions()
|
||||||
o.Upstreams = append(o.Upstreams, "127.0.0.1:8081")
|
o.Upstreams = append(o.Upstreams, "127.0.0.1:8081")
|
||||||
err := o.Validate()
|
err := Validate(o)
|
||||||
assert.NotEqual(t, nil, err)
|
assert.NotEqual(t, nil, err)
|
||||||
assert.Contains(t, err.Error(), "error parsing upstream")
|
assert.Contains(t, err.Error(), "error parsing upstream")
|
||||||
}
|
}
|
||||||
@ -163,9 +164,9 @@ func TestCompiledRegex(t *testing.T) {
|
|||||||
o := testOptions()
|
o := testOptions()
|
||||||
regexps := []string{"/foo/.*", "/ba[rz]/quux"}
|
regexps := []string{"/foo/.*", "/ba[rz]/quux"}
|
||||||
o.SkipAuthRegex = regexps
|
o.SkipAuthRegex = regexps
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, Validate(o))
|
||||||
actual := make([]string, 0)
|
actual := make([]string, 0)
|
||||||
for _, regex := range o.compiledRegex {
|
for _, regex := range o.GetCompiledRegex() {
|
||||||
actual = append(actual, regex.String())
|
actual = append(actual, regex.String())
|
||||||
}
|
}
|
||||||
assert.Equal(t, regexps, actual)
|
assert.Equal(t, regexps, actual)
|
||||||
@ -174,7 +175,7 @@ func TestCompiledRegex(t *testing.T) {
|
|||||||
func TestCompiledRegexError(t *testing.T) {
|
func TestCompiledRegexError(t *testing.T) {
|
||||||
o := testOptions()
|
o := testOptions()
|
||||||
o.SkipAuthRegex = []string{"(foobaz", "barquux)"}
|
o.SkipAuthRegex = []string{"(foobaz", "barquux)"}
|
||||||
err := o.Validate()
|
err := Validate(o)
|
||||||
assert.NotEqual(t, nil, err)
|
assert.NotEqual(t, nil, err)
|
||||||
|
|
||||||
expected := errorMsg([]string{
|
expected := errorMsg([]string{
|
||||||
@ -185,7 +186,7 @@ func TestCompiledRegexError(t *testing.T) {
|
|||||||
assert.Equal(t, expected, err.Error())
|
assert.Equal(t, expected, err.Error())
|
||||||
|
|
||||||
o.SkipAuthRegex = []string{"foobaz", "barquux)"}
|
o.SkipAuthRegex = []string{"foobaz", "barquux)"}
|
||||||
err = o.Validate()
|
err = Validate(o)
|
||||||
assert.NotEqual(t, nil, err)
|
assert.NotEqual(t, nil, err)
|
||||||
|
|
||||||
expected = errorMsg([]string{
|
expected = errorMsg([]string{
|
||||||
@ -196,8 +197,8 @@ func TestCompiledRegexError(t *testing.T) {
|
|||||||
|
|
||||||
func TestDefaultProviderApiSettings(t *testing.T) {
|
func TestDefaultProviderApiSettings(t *testing.T) {
|
||||||
o := testOptions()
|
o := testOptions()
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, Validate(o))
|
||||||
p := o.provider.Data()
|
p := o.GetProvider().Data()
|
||||||
assert.Equal(t, "https://accounts.google.com/o/oauth2/auth?access_type=offline",
|
assert.Equal(t, "https://accounts.google.com/o/oauth2/auth?access_type=offline",
|
||||||
p.LoginURL.String())
|
p.LoginURL.String())
|
||||||
assert.Equal(t, "https://www.googleapis.com/oauth2/v3/token",
|
assert.Equal(t, "https://www.googleapis.com/oauth2/v3/token",
|
||||||
@ -208,76 +209,76 @@ func TestDefaultProviderApiSettings(t *testing.T) {
|
|||||||
|
|
||||||
func TestPassAccessTokenRequiresSpecificCookieSecretLengths(t *testing.T) {
|
func TestPassAccessTokenRequiresSpecificCookieSecretLengths(t *testing.T) {
|
||||||
o := testOptions()
|
o := testOptions()
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, Validate(o))
|
||||||
|
|
||||||
assert.Equal(t, false, o.PassAccessToken)
|
assert.Equal(t, false, o.PassAccessToken)
|
||||||
o.PassAccessToken = true
|
o.PassAccessToken = true
|
||||||
o.Cookie.Secret = "cookie of invalid length-"
|
o.Cookie.Secret = "cookie of invalid length-"
|
||||||
assert.NotEqual(t, nil, o.Validate())
|
assert.NotEqual(t, nil, Validate(o))
|
||||||
|
|
||||||
o.PassAccessToken = false
|
o.PassAccessToken = false
|
||||||
o.Cookie.Refresh = time.Duration(24) * time.Hour
|
o.Cookie.Refresh = time.Duration(24) * time.Hour
|
||||||
assert.NotEqual(t, nil, o.Validate())
|
assert.NotEqual(t, nil, Validate(o))
|
||||||
|
|
||||||
o.Cookie.Secret = "16 bytes AES-128"
|
o.Cookie.Secret = "16 bytes AES-128"
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, Validate(o))
|
||||||
|
|
||||||
o.Cookie.Secret = "24 byte secret AES-192--"
|
o.Cookie.Secret = "24 byte secret AES-192--"
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, Validate(o))
|
||||||
|
|
||||||
o.Cookie.Secret = "32 byte secret for AES-256------"
|
o.Cookie.Secret = "32 byte secret for AES-256------"
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, Validate(o))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCookieRefreshMustBeLessThanCookieExpire(t *testing.T) {
|
func TestCookieRefreshMustBeLessThanCookieExpire(t *testing.T) {
|
||||||
o := testOptions()
|
o := testOptions()
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, Validate(o))
|
||||||
|
|
||||||
o.Cookie.Secret = "0123456789abcdef"
|
o.Cookie.Secret = "0123456789abcdef"
|
||||||
o.Cookie.Refresh = o.Cookie.Expire
|
o.Cookie.Refresh = o.Cookie.Expire
|
||||||
assert.NotEqual(t, nil, o.Validate())
|
assert.NotEqual(t, nil, Validate(o))
|
||||||
|
|
||||||
o.Cookie.Refresh -= time.Duration(1)
|
o.Cookie.Refresh -= time.Duration(1)
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, Validate(o))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBase64CookieSecret(t *testing.T) {
|
func TestBase64CookieSecret(t *testing.T) {
|
||||||
o := testOptions()
|
o := testOptions()
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, Validate(o))
|
||||||
|
|
||||||
// 32 byte, base64 (urlsafe) encoded key
|
// 32 byte, base64 (urlsafe) encoded key
|
||||||
o.Cookie.Secret = "yHBw2lh2Cvo6aI_jn_qMTr-pRAjtq0nzVgDJNb36jgQ="
|
o.Cookie.Secret = "yHBw2lh2Cvo6aI_jn_qMTr-pRAjtq0nzVgDJNb36jgQ="
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, Validate(o))
|
||||||
|
|
||||||
// 32 byte, base64 (urlsafe) encoded key, w/o padding
|
// 32 byte, base64 (urlsafe) encoded key, w/o padding
|
||||||
o.Cookie.Secret = "yHBw2lh2Cvo6aI_jn_qMTr-pRAjtq0nzVgDJNb36jgQ"
|
o.Cookie.Secret = "yHBw2lh2Cvo6aI_jn_qMTr-pRAjtq0nzVgDJNb36jgQ"
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, Validate(o))
|
||||||
|
|
||||||
// 24 byte, base64 (urlsafe) encoded key
|
// 24 byte, base64 (urlsafe) encoded key
|
||||||
o.Cookie.Secret = "Kp33Gj-GQmYtz4zZUyUDdqQKx5_Hgkv3"
|
o.Cookie.Secret = "Kp33Gj-GQmYtz4zZUyUDdqQKx5_Hgkv3"
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, Validate(o))
|
||||||
|
|
||||||
// 16 byte, base64 (urlsafe) encoded key
|
// 16 byte, base64 (urlsafe) encoded key
|
||||||
o.Cookie.Secret = "LFEqZYvYUwKwzn0tEuTpLA=="
|
o.Cookie.Secret = "LFEqZYvYUwKwzn0tEuTpLA=="
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, Validate(o))
|
||||||
|
|
||||||
// 16 byte, base64 (urlsafe) encoded key, w/o padding
|
// 16 byte, base64 (urlsafe) encoded key, w/o padding
|
||||||
o.Cookie.Secret = "LFEqZYvYUwKwzn0tEuTpLA"
|
o.Cookie.Secret = "LFEqZYvYUwKwzn0tEuTpLA"
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, Validate(o))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateSignatureKey(t *testing.T) {
|
func TestValidateSignatureKey(t *testing.T) {
|
||||||
o := testOptions()
|
o := testOptions()
|
||||||
o.SignatureKey = "sha1:secret"
|
o.SignatureKey = "sha1:secret"
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, Validate(o))
|
||||||
assert.Equal(t, o.signatureData.hash, crypto.SHA1)
|
assert.Equal(t, o.GetSignatureData().Hash, crypto.SHA1)
|
||||||
assert.Equal(t, o.signatureData.key, "secret")
|
assert.Equal(t, o.GetSignatureData().Key, "secret")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateSignatureKeyInvalidSpec(t *testing.T) {
|
func TestValidateSignatureKeyInvalidSpec(t *testing.T) {
|
||||||
o := testOptions()
|
o := testOptions()
|
||||||
o.SignatureKey = "invalid spec"
|
o.SignatureKey = "invalid spec"
|
||||||
err := o.Validate()
|
err := Validate(o)
|
||||||
assert.Equal(t, err.Error(), "invalid configuration:\n"+
|
assert.Equal(t, err.Error(), "invalid configuration:\n"+
|
||||||
" invalid signature hash:key spec: "+o.SignatureKey)
|
" invalid signature hash:key spec: "+o.SignatureKey)
|
||||||
}
|
}
|
||||||
@ -285,7 +286,7 @@ func TestValidateSignatureKeyInvalidSpec(t *testing.T) {
|
|||||||
func TestValidateSignatureKeyUnsupportedAlgorithm(t *testing.T) {
|
func TestValidateSignatureKeyUnsupportedAlgorithm(t *testing.T) {
|
||||||
o := testOptions()
|
o := testOptions()
|
||||||
o.SignatureKey = "unsupported:default secret"
|
o.SignatureKey = "unsupported:default secret"
|
||||||
err := o.Validate()
|
err := Validate(o)
|
||||||
assert.Equal(t, err.Error(), "invalid configuration:\n"+
|
assert.Equal(t, err.Error(), "invalid configuration:\n"+
|
||||||
" unsupported signature hash algorithm: "+o.SignatureKey)
|
" unsupported signature hash algorithm: "+o.SignatureKey)
|
||||||
}
|
}
|
||||||
@ -293,24 +294,24 @@ func TestValidateSignatureKeyUnsupportedAlgorithm(t *testing.T) {
|
|||||||
func TestValidateCookie(t *testing.T) {
|
func TestValidateCookie(t *testing.T) {
|
||||||
o := testOptions()
|
o := testOptions()
|
||||||
o.Cookie.Name = "_valid_cookie_name"
|
o.Cookie.Name = "_valid_cookie_name"
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, Validate(o))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateCookieBadName(t *testing.T) {
|
func TestValidateCookieBadName(t *testing.T) {
|
||||||
o := testOptions()
|
o := testOptions()
|
||||||
o.Cookie.Name = "_bad_cookie_name{}"
|
o.Cookie.Name = "_bad_cookie_name{}"
|
||||||
err := o.Validate()
|
err := Validate(o)
|
||||||
assert.Equal(t, err.Error(), "invalid configuration:\n"+
|
assert.Equal(t, err.Error(), "invalid configuration:\n"+
|
||||||
fmt.Sprintf(" invalid cookie name: %q", o.Cookie.Name))
|
fmt.Sprintf(" invalid cookie name: %q", o.Cookie.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSkipOIDCDiscovery(t *testing.T) {
|
func TestSkipOIDCDiscovery(t *testing.T) {
|
||||||
o := testOptions()
|
o := testOptions()
|
||||||
o.Provider = "oidc"
|
o.ProviderType = "oidc"
|
||||||
o.OIDCIssuerURL = "https://login.microsoftonline.com/fabrikamb2c.onmicrosoft.com/v2.0/"
|
o.OIDCIssuerURL = "https://login.microsoftonline.com/fabrikamb2c.onmicrosoft.com/v2.0/"
|
||||||
o.SkipOIDCDiscovery = true
|
o.SkipOIDCDiscovery = true
|
||||||
|
|
||||||
err := o.Validate()
|
err := Validate(o)
|
||||||
assert.Equal(t, "invalid configuration:\n"+
|
assert.Equal(t, "invalid configuration:\n"+
|
||||||
" missing setting: login-url\n missing setting: redeem-url\n missing setting: oidc-jwks-url", err.Error())
|
" missing setting: login-url\n missing setting: redeem-url\n missing setting: oidc-jwks-url", err.Error())
|
||||||
|
|
||||||
@ -318,54 +319,50 @@ func TestSkipOIDCDiscovery(t *testing.T) {
|
|||||||
o.RedeemURL = "https://login.microsoftonline.com/fabrikamb2c.onmicrosoft.com/oauth2/v2.0/token?p=b2c_1_sign_in"
|
o.RedeemURL = "https://login.microsoftonline.com/fabrikamb2c.onmicrosoft.com/oauth2/v2.0/token?p=b2c_1_sign_in"
|
||||||
o.OIDCJwksURL = "https://login.microsoftonline.com/fabrikamb2c.onmicrosoft.com/discovery/v2.0/keys"
|
o.OIDCJwksURL = "https://login.microsoftonline.com/fabrikamb2c.onmicrosoft.com/discovery/v2.0/keys"
|
||||||
|
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, Validate(o))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGCPHealthcheck(t *testing.T) {
|
func TestGCPHealthcheck(t *testing.T) {
|
||||||
o := testOptions()
|
o := testOptions()
|
||||||
o.GCPHealthChecks = true
|
o.GCPHealthChecks = true
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, Validate(o))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRealClientIPHeader(t *testing.T) {
|
func TestRealClientIPHeader(t *testing.T) {
|
||||||
var o *Options
|
|
||||||
var err error
|
|
||||||
var expected string
|
|
||||||
|
|
||||||
// Ensure nil if ReverseProxy not set.
|
// Ensure nil if ReverseProxy not set.
|
||||||
o = testOptions()
|
o := testOptions()
|
||||||
o.RealClientIPHeader = "X-Real-IP"
|
o.RealClientIPHeader = "X-Real-IP"
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, Validate(o))
|
||||||
assert.Nil(t, o.realClientIPParser)
|
assert.Nil(t, o.GetRealClientIPParser())
|
||||||
|
|
||||||
// Ensure simple use case works.
|
// Ensure simple use case works.
|
||||||
o = testOptions()
|
o = testOptions()
|
||||||
o.ReverseProxy = true
|
o.ReverseProxy = true
|
||||||
o.RealClientIPHeader = "X-Forwarded-For"
|
o.RealClientIPHeader = "X-Forwarded-For"
|
||||||
assert.Equal(t, nil, o.Validate())
|
assert.Equal(t, nil, Validate(o))
|
||||||
assert.NotNil(t, o.realClientIPParser)
|
assert.NotNil(t, o.GetRealClientIPParser())
|
||||||
|
|
||||||
// Ensure unknown header format process an error.
|
// Ensure unknown header format process an error.
|
||||||
o = testOptions()
|
o = testOptions()
|
||||||
o.ReverseProxy = true
|
o.ReverseProxy = true
|
||||||
o.RealClientIPHeader = "Forwarded"
|
o.RealClientIPHeader = "Forwarded"
|
||||||
err = o.Validate()
|
err := Validate(o)
|
||||||
assert.NotEqual(t, nil, err)
|
assert.NotEqual(t, nil, err)
|
||||||
expected = errorMsg([]string{
|
expected := errorMsg([]string{
|
||||||
"real_client_ip_header (Forwarded) not accepted parameter value: the http header key (Forwarded) is either invalid or unsupported",
|
"real_client_ip_header (Forwarded) not accepted parameter value: the http header key (Forwarded) is either invalid or unsupported",
|
||||||
})
|
})
|
||||||
assert.Equal(t, expected, err.Error())
|
assert.Equal(t, expected, err.Error())
|
||||||
assert.Nil(t, o.realClientIPParser)
|
assert.Nil(t, o.GetRealClientIPParser())
|
||||||
|
|
||||||
// Ensure invalid header format produces an error.
|
// Ensure invalid header format produces an error.
|
||||||
o = testOptions()
|
o = testOptions()
|
||||||
o.ReverseProxy = true
|
o.ReverseProxy = true
|
||||||
o.RealClientIPHeader = "!934invalidheader-23:"
|
o.RealClientIPHeader = "!934invalidheader-23:"
|
||||||
err = o.Validate()
|
err = Validate(o)
|
||||||
assert.NotEqual(t, nil, err)
|
assert.NotEqual(t, nil, err)
|
||||||
expected = errorMsg([]string{
|
expected = errorMsg([]string{
|
||||||
"real_client_ip_header (!934invalidheader-23:) not accepted parameter value: the http header key (!934invalidheader-23:) is either invalid or unsupported",
|
"real_client_ip_header (!934invalidheader-23:) not accepted parameter value: the http header key (!934invalidheader-23:) is either invalid or unsupported",
|
||||||
})
|
})
|
||||||
assert.Equal(t, expected, err.Error())
|
assert.Equal(t, expected, err.Error())
|
||||||
assert.Nil(t, o.realClientIPParser)
|
assert.Nil(t, o.GetRealClientIPParser())
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user