diff --git a/main.go b/main.go index 3fe3961..93098dd 100644 --- a/main.go +++ b/main.go @@ -66,8 +66,8 @@ func main() { flagSet.String("redeem-url", "", "Token redemption endpoint") flagSet.String("profile-url", "", "Profile access endpoint") flagSet.String("validate-url", "", "Access token validation endpoint") - flagSet.String("scope", "", "Oauth scope specification") - flagSet.String("approval-prompt", "force", "Oauth approval_prompt") + flagSet.String("scope", "", "OAuth scope specification") + flagSet.String("approval-prompt", "force", "OAuth approval_prompt") flagSet.Parse(os.Args[1:]) @@ -95,7 +95,7 @@ func main() { } validator := NewValidator(opts.EmailDomains, opts.AuthenticatedEmailsFile) - oauthproxy := NewOauthProxy(opts, validator) + oauthproxy := NewOAuthProxy(opts, validator) if len(opts.EmailDomains) != 0 && opts.AuthenticatedEmailsFile == "" { if len(opts.EmailDomains) > 1 { diff --git a/oauthproxy.go b/oauthproxy.go index 5a12705..73fd6f2 100644 --- a/oauthproxy.go +++ b/oauthproxy.go @@ -18,7 +18,7 @@ import ( "github.com/bitly/oauth2_proxy/providers" ) -type OauthProxy struct { +type OAuthProxy struct { CookieSeed string CookieName string CookieDomain string @@ -31,10 +31,10 @@ type OauthProxy struct { RobotsPath string PingPath string SignInPath string - OauthStartPath string - OauthCallbackPath string + OAuthStartPath string + OAuthCallbackPath string - redirectUrl *url.URL // the url to receive requests at + redirectURL *url.URL // the url to receive requests at provider providers.Provider ProxyPrefix string SignInMessage string @@ -86,9 +86,9 @@ func NewFileServer(path string, filesystemPath string) (proxy http.Handler) { return http.StripPrefix(path, http.FileServer(http.Dir(filesystemPath))) } -func NewOauthProxy(opts *Options, validator func(string) bool) *OauthProxy { +func NewOAuthProxy(opts *Options, validator func(string) bool) *OAuthProxy { serveMux := http.NewServeMux() - for _, u := range opts.proxyUrls { + for _, u := range opts.proxyURLs { path := u.Path switch u.Scheme { case "http", "https": @@ -116,10 +116,10 @@ func NewOauthProxy(opts *Options, validator func(string) bool) *OauthProxy { log.Printf("compiled skip-auth-regex => %q", u) } - redirectUrl := opts.redirectUrl - redirectUrl.Path = fmt.Sprintf("%s/callback", opts.ProxyPrefix) + redirectURL := opts.redirectURL + redirectURL.Path = fmt.Sprintf("%s/callback", opts.ProxyPrefix) - log.Printf("OauthProxy configured for %s Client ID: %s", opts.provider.Data().ProviderName, opts.ClientID) + log.Printf("OAuthProxy configured for %s Client ID: %s", opts.provider.Data().ProviderName, opts.ClientID) domain := opts.CookieDomain if domain == "" { domain = "" @@ -141,7 +141,7 @@ func NewOauthProxy(opts *Options, validator func(string) bool) *OauthProxy { } } - return &OauthProxy{ + return &OAuthProxy{ CookieName: opts.CookieName, CookieSeed: opts.CookieSecret, CookieDomain: opts.CookieDomain, @@ -154,13 +154,13 @@ func NewOauthProxy(opts *Options, validator func(string) bool) *OauthProxy { RobotsPath: "/robots.txt", PingPath: "/ping", SignInPath: fmt.Sprintf("%s/sign_in", opts.ProxyPrefix), - OauthStartPath: fmt.Sprintf("%s/start", opts.ProxyPrefix), - OauthCallbackPath: fmt.Sprintf("%s/callback", opts.ProxyPrefix), + OAuthStartPath: fmt.Sprintf("%s/start", opts.ProxyPrefix), + OAuthCallbackPath: fmt.Sprintf("%s/callback", opts.ProxyPrefix), ProxyPrefix: opts.ProxyPrefix, provider: opts.provider, serveMux: serveMux, - redirectUrl: redirectUrl, + redirectURL: redirectURL, skipAuthRegex: opts.SkipAuthRegex, compiledRegex: opts.CompiledRegex, PassBasicAuth: opts.PassBasicAuth, @@ -171,13 +171,13 @@ func NewOauthProxy(opts *Options, validator func(string) bool) *OauthProxy { } } -func (p *OauthProxy) GetRedirectURI(host string) string { +func (p *OAuthProxy) GetRedirectURI(host string) string { // default to the request Host if not set - if p.redirectUrl.Host != "" { - return p.redirectUrl.String() + if p.redirectURL.Host != "" { + return p.redirectURL.String() } var u url.URL - u = *p.redirectUrl + u = *p.redirectURL if u.Scheme == "" { if p.CookieSecure { u.Scheme = "https" @@ -189,16 +189,16 @@ func (p *OauthProxy) GetRedirectURI(host string) string { return u.String() } -func (p *OauthProxy) displayCustomLoginForm() bool { +func (p *OAuthProxy) displayCustomLoginForm() bool { return p.HtpasswdFile != nil && p.DisplayHtpasswdForm } -func (p *OauthProxy) redeemCode(host, code string) (s *providers.SessionState, err error) { +func (p *OAuthProxy) redeemCode(host, code string) (s *providers.SessionState, err error) { if code == "" { return nil, errors.New("missing code") } - redirectUri := p.GetRedirectURI(host) - s, err = p.provider.Redeem(redirectUri, code) + redirectURI := p.GetRedirectURI(host) + s, err = p.provider.Redeem(redirectURI, code) if err != nil { return } @@ -209,7 +209,7 @@ func (p *OauthProxy) redeemCode(host, code string) (s *providers.SessionState, e return } -func (p *OauthProxy) MakeCookie(req *http.Request, value string, expiration time.Duration, now time.Time) *http.Cookie { +func (p *OAuthProxy) MakeCookie(req *http.Request, value string, expiration time.Duration, now time.Time) *http.Cookie { domain := req.Host if h, _, err := net.SplitHostPort(domain); err == nil { domain = h @@ -235,15 +235,15 @@ func (p *OauthProxy) MakeCookie(req *http.Request, value string, expiration time } } -func (p *OauthProxy) ClearCookie(rw http.ResponseWriter, req *http.Request) { +func (p *OAuthProxy) ClearCookie(rw http.ResponseWriter, req *http.Request) { http.SetCookie(rw, p.MakeCookie(req, "", time.Hour*-1, time.Now())) } -func (p *OauthProxy) SetCookie(rw http.ResponseWriter, req *http.Request, val string) { +func (p *OAuthProxy) SetCookie(rw http.ResponseWriter, req *http.Request, val string) { http.SetCookie(rw, p.MakeCookie(req, val, p.CookieExpire, time.Now())) } -func (p *OauthProxy) LoadCookiedSession(req *http.Request) (*providers.SessionState, time.Duration, error) { +func (p *OAuthProxy) LoadCookiedSession(req *http.Request) (*providers.SessionState, time.Duration, error) { var age time.Duration c, err := req.Cookie(p.CookieName) if err != nil { @@ -264,7 +264,7 @@ func (p *OauthProxy) LoadCookiedSession(req *http.Request) (*providers.SessionSt return session, age, nil } -func (p *OauthProxy) SaveSession(rw http.ResponseWriter, req *http.Request, s *providers.SessionState) error { +func (p *OAuthProxy) SaveSession(rw http.ResponseWriter, req *http.Request, s *providers.SessionState) error { value, err := p.provider.CookieForSession(s, p.CookieCipher) if err != nil { return err @@ -273,17 +273,17 @@ func (p *OauthProxy) SaveSession(rw http.ResponseWriter, req *http.Request, s *p return nil } -func (p *OauthProxy) RobotsTxt(rw http.ResponseWriter) { +func (p *OAuthProxy) RobotsTxt(rw http.ResponseWriter) { rw.WriteHeader(http.StatusOK) fmt.Fprintf(rw, "User-agent: *\nDisallow: /") } -func (p *OauthProxy) PingPage(rw http.ResponseWriter) { +func (p *OAuthProxy) PingPage(rw http.ResponseWriter) { rw.WriteHeader(http.StatusOK) fmt.Fprintf(rw, "OK") } -func (p *OauthProxy) ErrorPage(rw http.ResponseWriter, code int, title string, message string) { +func (p *OAuthProxy) ErrorPage(rw http.ResponseWriter, code int, title string, message string) { log.Printf("ErrorPage %d %s %s", code, title, message) rw.WriteHeader(code) t := struct { @@ -298,7 +298,7 @@ func (p *OauthProxy) ErrorPage(rw http.ResponseWriter, code int, title string, m p.templates.ExecuteTemplate(rw, "error.html", t) } -func (p *OauthProxy) SignInPage(rw http.ResponseWriter, req *http.Request, code int) { +func (p *OAuthProxy) SignInPage(rw http.ResponseWriter, req *http.Request, code int) { p.ClearCookie(rw, req) rw.WriteHeader(code) @@ -325,7 +325,7 @@ func (p *OauthProxy) SignInPage(rw http.ResponseWriter, req *http.Request, code p.templates.ExecuteTemplate(rw, "sign_in.html", t) } -func (p *OauthProxy) ManualSignIn(rw http.ResponseWriter, req *http.Request) (string, bool) { +func (p *OAuthProxy) ManualSignIn(rw http.ResponseWriter, req *http.Request) (string, bool) { if req.Method != "POST" || p.HtpasswdFile == nil { return "", false } @@ -342,7 +342,7 @@ func (p *OauthProxy) ManualSignIn(rw http.ResponseWriter, req *http.Request) (st return "", false } -func (p *OauthProxy) GetRedirect(req *http.Request) (string, error) { +func (p *OAuthProxy) GetRedirect(req *http.Request) (string, error) { err := req.ParseForm() if err != nil { @@ -358,7 +358,7 @@ func (p *OauthProxy) GetRedirect(req *http.Request) (string, error) { return redirect, err } -func (p *OauthProxy) IsWhitelistedPath(path string) (ok bool) { +func (p *OAuthProxy) IsWhitelistedPath(path string) (ok bool) { for _, u := range p.compiledRegex { ok = u.MatchString(path) if ok { @@ -376,7 +376,7 @@ func getRemoteAddr(req *http.Request) (s string) { return } -func (p *OauthProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { +func (p *OAuthProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { switch path := req.URL.Path; { case path == p.RobotsPath: p.RobotsTxt(rw) @@ -386,16 +386,16 @@ func (p *OauthProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { p.serveMux.ServeHTTP(rw, req) case path == p.SignInPath: p.SignIn(rw, req) - case path == p.OauthStartPath: - p.OauthStart(rw, req) - case path == p.OauthCallbackPath: - p.OauthCallback(rw, req) + case path == p.OAuthStartPath: + p.OAuthStart(rw, req) + case path == p.OAuthCallbackPath: + p.OAuthCallback(rw, req) default: p.Proxy(rw, req) } } -func (p *OauthProxy) SignIn(rw http.ResponseWriter, req *http.Request) { +func (p *OAuthProxy) SignIn(rw http.ResponseWriter, req *http.Request) { redirect, err := p.GetRedirect(req) if err != nil { p.ErrorPage(rw, 500, "Internal Error", err.Error()) @@ -412,7 +412,7 @@ func (p *OauthProxy) SignIn(rw http.ResponseWriter, req *http.Request) { } } -func (p *OauthProxy) OauthStart(rw http.ResponseWriter, req *http.Request) { +func (p *OAuthProxy) OAuthStart(rw http.ResponseWriter, req *http.Request) { redirect, err := p.GetRedirect(req) if err != nil { p.ErrorPage(rw, 500, "Internal Error", err.Error()) @@ -422,7 +422,7 @@ func (p *OauthProxy) OauthStart(rw http.ResponseWriter, req *http.Request) { http.Redirect(rw, req, p.provider.GetLoginURL(redirectURI, redirect), 302) } -func (p *OauthProxy) OauthCallback(rw http.ResponseWriter, req *http.Request) { +func (p *OAuthProxy) OAuthCallback(rw http.ResponseWriter, req *http.Request) { remoteAddr := getRemoteAddr(req) // finish the oauth cycle @@ -465,7 +465,7 @@ func (p *OauthProxy) OauthCallback(rw http.ResponseWriter, req *http.Request) { } } -func (p *OauthProxy) Proxy(rw http.ResponseWriter, req *http.Request) { +func (p *OAuthProxy) Proxy(rw http.ResponseWriter, req *http.Request) { var saveSession, clearSession, revalidated bool remoteAddr := getRemoteAddr(req) @@ -555,7 +555,7 @@ func (p *OauthProxy) Proxy(rw http.ResponseWriter, req *http.Request) { p.serveMux.ServeHTTP(rw, req) } -func (p *OauthProxy) CheckBasicAuth(req *http.Request) (*providers.SessionState, error) { +func (p *OAuthProxy) CheckBasicAuth(req *http.Request) (*providers.SessionState, error) { if p.HtpasswdFile == nil { return nil, nil } diff --git a/oauthproxy_test.go b/oauthproxy_test.go index ca0b9c4..cf3f5aa 100644 --- a/oauthproxy_test.go +++ b/oauthproxy_test.go @@ -80,7 +80,7 @@ func TestRobotsTxt(t *testing.T) { opts.CookieSecret = "xyzzyplugh" opts.Validate() - proxy := NewOauthProxy(opts, func(string) bool { return true }) + proxy := NewOAuthProxy(opts, func(string) bool { return true }) rw := httptest.NewRecorder() req, _ := http.NewRequest("GET", "/robots.txt", nil) proxy.ServeHTTP(rw, req) @@ -124,17 +124,17 @@ func TestBasicAuthPassword(t *testing.T) { opts.provider = &TestProvider{ ProviderData: &providers.ProviderData{ ProviderName: "Test Provider", - LoginUrl: &url.URL{ + LoginURL: &url.URL{ Scheme: "http", Host: provider_url.Host, Path: "/oauth/authorize", }, - RedeemUrl: &url.URL{ + RedeemURL: &url.URL{ Scheme: "http", Host: provider_url.Host, Path: "/oauth/token", }, - ProfileUrl: &url.URL{ + ProfileURL: &url.URL{ Scheme: "http", Host: provider_url.Host, Path: "/api/v1/profile", @@ -144,7 +144,7 @@ func TestBasicAuthPassword(t *testing.T) { EmailAddress: email_address, } - proxy := NewOauthProxy(opts, func(email string) bool { + proxy := NewOAuthProxy(opts, func(email string) bool { return email == email_address }) @@ -199,7 +199,7 @@ func (tp *TestProvider) ValidateSessionState(session *providers.SessionState) bo type PassAccessTokenTest struct { provider_server *httptest.Server - proxy *OauthProxy + proxy *OAuthProxy opts *Options } @@ -245,17 +245,17 @@ func NewPassAccessTokenTest(opts PassAccessTokenTestOptions) *PassAccessTokenTes t.opts.provider = &TestProvider{ ProviderData: &providers.ProviderData{ ProviderName: "Test Provider", - LoginUrl: &url.URL{ + LoginURL: &url.URL{ Scheme: "http", Host: provider_url.Host, Path: "/oauth/authorize", }, - RedeemUrl: &url.URL{ + RedeemURL: &url.URL{ Scheme: "http", Host: provider_url.Host, Path: "/oauth/token", }, - ProfileUrl: &url.URL{ + ProfileURL: &url.URL{ Scheme: "http", Host: provider_url.Host, Path: "/api/v1/profile", @@ -265,7 +265,7 @@ func NewPassAccessTokenTest(opts PassAccessTokenTestOptions) *PassAccessTokenTes EmailAddress: email_address, } - t.proxy = NewOauthProxy(t.opts, func(email string) bool { + t.proxy = NewOAuthProxy(t.opts, func(email string) bool { return email == email_address }) return t @@ -360,7 +360,7 @@ func TestDoNotForwardAccessTokenUpstream(t *testing.T) { type SignInPageTest struct { opts *Options - proxy *OauthProxy + proxy *OAuthProxy sign_in_regexp *regexp.Regexp } @@ -375,7 +375,7 @@ func NewSignInPageTest() *SignInPageTest { sip_test.opts.ClientSecret = "xyzzyplugh" sip_test.opts.Validate() - sip_test.proxy = NewOauthProxy(sip_test.opts, func(email string) bool { + sip_test.proxy = NewOAuthProxy(sip_test.opts, func(email string) bool { return true }) sip_test.sign_in_regexp = regexp.MustCompile(signInRedirectPattern) @@ -425,7 +425,7 @@ func TestSignInPageDirectAccessRedirectsToRoot(t *testing.T) { type ProcessCookieTest struct { opts *Options - proxy *OauthProxy + proxy *OAuthProxy rw *httptest.ResponseRecorder req *http.Request provider TestProvider @@ -449,7 +449,7 @@ func NewProcessCookieTest(opts ProcessCookieTestOpts) *ProcessCookieTest { pc_test.opts.CookieRefresh = time.Hour pc_test.opts.Validate() - pc_test.proxy = NewOauthProxy(pc_test.opts, func(email string) bool { + pc_test.proxy = NewOAuthProxy(pc_test.opts, func(email string) bool { return pc_test.validate_user }) pc_test.proxy.provider = &TestProvider{ diff --git a/options.go b/options.go index b4b8afa..945125a 100644 --- a/options.go +++ b/options.go @@ -16,7 +16,7 @@ type Options struct { ProxyPrefix string `flag:"proxy-prefix" cfg:"proxy-prefix"` HttpAddress string `flag:"http-address" cfg:"http_address"` HttpsAddress string `flag:"https-address" cfg:"https_address"` - RedirectUrl string `flag:"redirect-url" cfg:"redirect_url"` + RedirectURL string `flag:"redirect-url" cfg:"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"` TLSCertFile string `flag:"tls-cert" cfg:"tls_cert_file"` @@ -51,18 +51,18 @@ type Options struct { // These options allow for other providers besides Google, with // potential overrides. Provider string `flag:"provider" cfg:"provider"` - LoginUrl string `flag:"login-url" cfg:"login_url"` - RedeemUrl string `flag:"redeem-url" cfg:"redeem_url"` - ProfileUrl string `flag:"profile-url" cfg:"profile_url"` - ValidateUrl string `flag:"validate-url" cfg:"validate_url"` + LoginURL string `flag:"login-url" cfg:"login_url"` + RedeemURL string `flag:"redeem-url" cfg:"redeem_url"` + ProfileURL string `flag:"profile-url" cfg:"profile_url"` + ValidateURL string `flag:"validate-url" cfg:"validate_url"` Scope string `flag:"scope" cfg:"scope"` ApprovalPrompt string `flag:"approval-prompt" cfg:"approval_prompt"` RequestLogging bool `flag:"request-logging" cfg:"request_logging"` // internal values that are set after config validation - redirectUrl *url.URL - proxyUrls []*url.URL + redirectURL *url.URL + proxyURLs []*url.URL CompiledRegex []*regexp.Regexp provider providers.Provider } @@ -86,7 +86,7 @@ func NewOptions() *Options { } } -func parseUrl(to_parse string, urltype string, msgs []string) (*url.URL, []string) { +func parseURL(to_parse string, urltype string, msgs []string) (*url.URL, []string) { parsed, err := url.Parse(to_parse) if err != nil { return nil, append(msgs, fmt.Sprintf( @@ -113,19 +113,19 @@ func (o *Options) Validate() error { msgs = append(msgs, "missing setting for email validation: email-domain or authenticated-emails-file required.\n use email-domain=* to authorize all email addresses") } - o.redirectUrl, msgs = parseUrl(o.RedirectUrl, "redirect", msgs) + o.redirectURL, msgs = parseURL(o.RedirectURL, "redirect", msgs) for _, u := range o.Upstreams { - upstreamUrl, err := url.Parse(u) + upstreamURL, err := url.Parse(u) if err != nil { msgs = append(msgs, fmt.Sprintf( "error parsing upstream=%q %s", - upstreamUrl, err)) + upstreamURL, err)) } - if upstreamUrl.Path == "" { - upstreamUrl.Path = "/" + if upstreamURL.Path == "" { + upstreamURL.Path = "/" } - o.proxyUrls = append(o.proxyUrls, upstreamUrl) + o.proxyURLs = append(o.proxyURLs, upstreamURL) } for _, u := range o.SkipAuthRegex { @@ -189,10 +189,10 @@ func parseProviderInfo(o *Options, msgs []string) []string { ClientSecret: o.ClientSecret, ApprovalPrompt: o.ApprovalPrompt, } - p.LoginUrl, msgs = parseUrl(o.LoginUrl, "login", msgs) - p.RedeemUrl, msgs = parseUrl(o.RedeemUrl, "redeem", msgs) - p.ProfileUrl, msgs = parseUrl(o.ProfileUrl, "profile", msgs) - p.ValidateUrl, msgs = parseUrl(o.ValidateUrl, "validate", msgs) + p.LoginURL, msgs = parseURL(o.LoginURL, "login", msgs) + p.RedeemURL, msgs = parseURL(o.RedeemURL, "redeem", msgs) + p.ProfileURL, msgs = parseURL(o.ProfileURL, "profile", msgs) + p.ValidateURL, msgs = parseURL(o.ValidateURL, "validate", msgs) o.provider = providers.New(o.Provider, p) switch p := o.provider.(type) { diff --git a/options_test.go b/options_test.go index fcb4b58..2984465 100644 --- a/options_test.go +++ b/options_test.go @@ -73,16 +73,16 @@ func TestInitializedOptions(t *testing.T) { // Note that it's not worth testing nonparseable URLs, since url.Parse() // seems to parse damn near anything. -func TestRedirectUrl(t *testing.T) { +func TestRedirectURL(t *testing.T) { o := testOptions() - o.RedirectUrl = "https://myhost.com/oauth2/callback" + o.RedirectURL = "https://myhost.com/oauth2/callback" assert.Equal(t, nil, o.Validate()) expected := &url.URL{ Scheme: "https", Host: "myhost.com", Path: "/oauth2/callback"} - assert.Equal(t, expected, o.redirectUrl) + assert.Equal(t, expected, o.redirectURL) } -func TestProxyUrls(t *testing.T) { +func TestProxyURLs(t *testing.T) { o := testOptions() o.Upstreams = append(o.Upstreams, "http://127.0.0.1:8081") assert.Equal(t, nil, o.Validate()) @@ -91,7 +91,7 @@ func TestProxyUrls(t *testing.T) { // note the '/' was added &url.URL{Scheme: "http", Host: "127.0.0.1:8081", Path: "/"}, } - assert.Equal(t, expected, o.proxyUrls) + assert.Equal(t, expected, o.proxyURLs) } func TestCompiledRegex(t *testing.T) { @@ -125,10 +125,10 @@ func TestDefaultProviderApiSettings(t *testing.T) { assert.Equal(t, nil, o.Validate()) p := o.provider.Data() 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", - p.RedeemUrl.String()) - assert.Equal(t, "", p.ProfileUrl.String()) + p.RedeemURL.String()) + assert.Equal(t, "", p.ProfileURL.String()) assert.Equal(t, "profile email", p.Scope) } diff --git a/providers/github.go b/providers/github.go index db0b21a..cf0cfcb 100644 --- a/providers/github.go +++ b/providers/github.go @@ -17,22 +17,22 @@ type GitHubProvider struct { func NewGitHubProvider(p *ProviderData) *GitHubProvider { p.ProviderName = "GitHub" - if p.LoginUrl == nil || p.LoginUrl.String() == "" { - p.LoginUrl = &url.URL{ + if p.LoginURL == nil || p.LoginURL.String() == "" { + p.LoginURL = &url.URL{ Scheme: "https", Host: "github.com", Path: "/login/oauth/authorize", } } - if p.RedeemUrl == nil || p.RedeemUrl.String() == "" { - p.RedeemUrl = &url.URL{ + if p.RedeemURL == nil || p.RedeemURL.String() == "" { + p.RedeemURL = &url.URL{ Scheme: "https", Host: "github.com", Path: "/login/oauth/access_token", } } - if p.ValidateUrl == nil || p.ValidateUrl.String() == "" { - p.ValidateUrl = &url.URL{ + if p.ValidateURL == nil || p.ValidateURL.String() == "" { + p.ValidateURL = &url.URL{ Scheme: "https", Host: "api.github.com", Path: "/user/emails", diff --git a/providers/google.go b/providers/google.go index d71f313..539657b 100644 --- a/providers/google.go +++ b/providers/google.go @@ -21,7 +21,7 @@ import ( type GoogleProvider struct { *ProviderData - RedeemRefreshUrl *url.URL + RedeemRefreshURL *url.URL // GroupValidator is a function that determines if the passed email is in // the configured Google group. GroupValidator func(string) bool @@ -29,21 +29,21 @@ type GoogleProvider struct { func NewGoogleProvider(p *ProviderData) *GoogleProvider { p.ProviderName = "Google" - if p.LoginUrl.String() == "" { - p.LoginUrl = &url.URL{Scheme: "https", + if p.LoginURL.String() == "" { + p.LoginURL = &url.URL{Scheme: "https", Host: "accounts.google.com", Path: "/o/oauth2/auth", // to get a refresh token. see https://developers.google.com/identity/protocols/OAuth2WebServer#offline RawQuery: "access_type=offline", } } - if p.RedeemUrl.String() == "" { - p.RedeemUrl = &url.URL{Scheme: "https", + if p.RedeemURL.String() == "" { + p.RedeemURL = &url.URL{Scheme: "https", Host: "www.googleapis.com", Path: "/oauth2/v3/token"} } - if p.ValidateUrl.String() == "" { - p.ValidateUrl = &url.URL{Scheme: "https", + if p.ValidateURL.String() == "" { + p.ValidateURL = &url.URL{Scheme: "https", Host: "www.googleapis.com", Path: "/oauth2/v1/tokeninfo"} } @@ -96,20 +96,20 @@ func jwtDecodeSegment(seg string) ([]byte, error) { return base64.URLEncoding.DecodeString(seg) } -func (p *GoogleProvider) Redeem(redirectUrl, code string) (s *SessionState, err error) { +func (p *GoogleProvider) Redeem(redirectURL, code string) (s *SessionState, err error) { if code == "" { err = errors.New("missing code") return } params := url.Values{} - params.Add("redirect_uri", redirectUrl) + params.Add("redirect_uri", redirectURL) params.Add("client_id", p.ClientID) params.Add("client_secret", p.ClientSecret) params.Add("code", code) params.Add("grant_type", "authorization_code") var req *http.Request - req, err = http.NewRequest("POST", p.RedeemUrl.String(), bytes.NewBufferString(params.Encode())) + req, err = http.NewRequest("POST", p.RedeemURL.String(), bytes.NewBufferString(params.Encode())) if err != nil { return } @@ -127,7 +127,7 @@ func (p *GoogleProvider) Redeem(redirectUrl, code string) (s *SessionState, err } if resp.StatusCode != 200 { - err = fmt.Errorf("got %d from %q %s", resp.StatusCode, p.RedeemUrl.String(), body) + err = fmt.Errorf("got %d from %q %s", resp.StatusCode, p.RedeemURL.String(), body) return } @@ -281,7 +281,7 @@ func (p *GoogleProvider) redeemRefreshToken(refreshToken string) (token string, params.Add("refresh_token", refreshToken) params.Add("grant_type", "refresh_token") var req *http.Request - req, err = http.NewRequest("POST", p.RedeemUrl.String(), bytes.NewBufferString(params.Encode())) + req, err = http.NewRequest("POST", p.RedeemURL.String(), bytes.NewBufferString(params.Encode())) if err != nil { return } @@ -299,7 +299,7 @@ func (p *GoogleProvider) redeemRefreshToken(refreshToken string) (token string, } if resp.StatusCode != 200 { - err = fmt.Errorf("got %d from %q %s", resp.StatusCode, p.RedeemUrl.String(), body) + err = fmt.Errorf("got %d from %q %s", resp.StatusCode, p.RedeemURL.String(), body) return } diff --git a/providers/google_test.go b/providers/google_test.go index 8f0d29b..8f9b054 100644 --- a/providers/google_test.go +++ b/providers/google_test.go @@ -23,10 +23,10 @@ func newGoogleProvider() *GoogleProvider { return NewGoogleProvider( &ProviderData{ ProviderName: "", - LoginUrl: &url.URL{}, - RedeemUrl: &url.URL{}, - ProfileUrl: &url.URL{}, - ValidateUrl: &url.URL{}, + LoginURL: &url.URL{}, + RedeemURL: &url.URL{}, + ProfileURL: &url.URL{}, + ValidateURL: &url.URL{}, Scope: ""}) } @@ -35,31 +35,31 @@ func TestGoogleProviderDefaults(t *testing.T) { assert.NotEqual(t, nil, p) assert.Equal(t, "Google", p.Data().ProviderName) assert.Equal(t, "https://accounts.google.com/o/oauth2/auth?access_type=offline", - p.Data().LoginUrl.String()) + p.Data().LoginURL.String()) assert.Equal(t, "https://www.googleapis.com/oauth2/v3/token", - p.Data().RedeemUrl.String()) + p.Data().RedeemURL.String()) assert.Equal(t, "https://www.googleapis.com/oauth2/v1/tokeninfo", - p.Data().ValidateUrl.String()) - assert.Equal(t, "", p.Data().ProfileUrl.String()) + p.Data().ValidateURL.String()) + assert.Equal(t, "", p.Data().ProfileURL.String()) assert.Equal(t, "profile email", p.Data().Scope) } func TestGoogleProviderOverrides(t *testing.T) { p := NewGoogleProvider( &ProviderData{ - LoginUrl: &url.URL{ + LoginURL: &url.URL{ Scheme: "https", Host: "example.com", Path: "/oauth/auth"}, - RedeemUrl: &url.URL{ + RedeemURL: &url.URL{ Scheme: "https", Host: "example.com", Path: "/oauth/token"}, - ProfileUrl: &url.URL{ + ProfileURL: &url.URL{ Scheme: "https", Host: "example.com", Path: "/oauth/profile"}, - ValidateUrl: &url.URL{ + ValidateURL: &url.URL{ Scheme: "https", Host: "example.com", Path: "/oauth/tokeninfo"}, @@ -67,13 +67,13 @@ func TestGoogleProviderOverrides(t *testing.T) { assert.NotEqual(t, nil, p) assert.Equal(t, "Google", p.Data().ProviderName) assert.Equal(t, "https://example.com/oauth/auth", - p.Data().LoginUrl.String()) + p.Data().LoginURL.String()) assert.Equal(t, "https://example.com/oauth/token", - p.Data().RedeemUrl.String()) + p.Data().RedeemURL.String()) assert.Equal(t, "https://example.com/oauth/profile", - p.Data().ProfileUrl.String()) + p.Data().ProfileURL.String()) assert.Equal(t, "https://example.com/oauth/tokeninfo", - p.Data().ValidateUrl.String()) + p.Data().ValidateURL.String()) assert.Equal(t, "profile", p.Data().Scope) } @@ -94,7 +94,7 @@ func TestGoogleProviderGetEmailAddress(t *testing.T) { }) assert.Equal(t, nil, err) var server *httptest.Server - p.RedeemUrl, server = newRedeemServer(body) + p.RedeemURL, server = newRedeemServer(body) defer server.Close() session, err := p.Redeem("http://redirect/", "code1234") @@ -131,7 +131,7 @@ func TestGoogleProviderGetEmailAddressInvalidEncoding(t *testing.T) { }) assert.Equal(t, nil, err) var server *httptest.Server - p.RedeemUrl, server = newRedeemServer(body) + p.RedeemURL, server = newRedeemServer(body) defer server.Close() session, err := p.Redeem("http://redirect/", "code1234") @@ -150,7 +150,7 @@ func TestGoogleProviderGetEmailAddressInvalidJson(t *testing.T) { }) assert.Equal(t, nil, err) var server *httptest.Server - p.RedeemUrl, server = newRedeemServer(body) + p.RedeemURL, server = newRedeemServer(body) defer server.Close() session, err := p.Redeem("http://redirect/", "code1234") @@ -169,7 +169,7 @@ func TestGoogleProviderGetEmailAddressEmailMissing(t *testing.T) { }) assert.Equal(t, nil, err) var server *httptest.Server - p.RedeemUrl, server = newRedeemServer(body) + p.RedeemURL, server = newRedeemServer(body) defer server.Close() session, err := p.Redeem("http://redirect/", "code1234") diff --git a/providers/internal_util.go b/providers/internal_util.go index ff0cafa..436744c 100644 --- a/providers/internal_util.go +++ b/providers/internal_util.go @@ -11,10 +11,10 @@ import ( // validateToken returns true if token is valid func validateToken(p Provider, access_token string, header http.Header) bool { - if access_token == "" || p.Data().ValidateUrl == nil { + if access_token == "" || p.Data().ValidateURL == nil { return false } - endpoint := p.Data().ValidateUrl.String() + endpoint := p.Data().ValidateURL.String() if len(header) == 0 { params := url.Values{"access_token": {access_token}} endpoint = endpoint + "?" + params.Encode() diff --git a/providers/internal_util_test.go b/providers/internal_util_test.go index bace76d..ad42bf1 100644 --- a/providers/internal_util_test.go +++ b/providers/internal_util_test.go @@ -63,7 +63,7 @@ func NewValidateSessionStateTest() *ValidateSessionStateTest { backend_url, _ := url.Parse(vt_test.backend.URL) vt_test.provider = &ValidateSessionStateTestProvider{ ProviderData: &ProviderData{ - ValidateUrl: &url.URL{ + ValidateURL: &url.URL{ Scheme: "http", Host: backend_url.Host, Path: "/oauth/tokeninfo", @@ -99,10 +99,10 @@ func TestValidateSessionStateEmptyToken(t *testing.T) { assert.Equal(t, false, validateToken(vt_test.provider, "", nil)) } -func TestValidateSessionStateEmptyValidateUrl(t *testing.T) { +func TestValidateSessionStateEmptyValidateURL(t *testing.T) { vt_test := NewValidateSessionStateTest() defer vt_test.Close() - vt_test.provider.Data().ValidateUrl = nil + vt_test.provider.Data().ValidateURL = nil assert.Equal(t, false, validateToken(vt_test.provider, "foobar", nil)) } diff --git a/providers/linkedin.go b/providers/linkedin.go index 2151229..971734c 100644 --- a/providers/linkedin.go +++ b/providers/linkedin.go @@ -15,23 +15,23 @@ type LinkedInProvider struct { func NewLinkedInProvider(p *ProviderData) *LinkedInProvider { p.ProviderName = "LinkedIn" - if p.LoginUrl.String() == "" { - p.LoginUrl = &url.URL{Scheme: "https", + if p.LoginURL.String() == "" { + p.LoginURL = &url.URL{Scheme: "https", Host: "www.linkedin.com", Path: "/uas/oauth2/authorization"} } - if p.RedeemUrl.String() == "" { - p.RedeemUrl = &url.URL{Scheme: "https", + if p.RedeemURL.String() == "" { + p.RedeemURL = &url.URL{Scheme: "https", Host: "www.linkedin.com", Path: "/uas/oauth2/accessToken"} } - if p.ProfileUrl.String() == "" { - p.ProfileUrl = &url.URL{Scheme: "https", + if p.ProfileURL.String() == "" { + p.ProfileURL = &url.URL{Scheme: "https", Host: "www.linkedin.com", Path: "/v1/people/~/email-address"} } - if p.ValidateUrl.String() == "" { - p.ValidateUrl = p.ProfileUrl + if p.ValidateURL.String() == "" { + p.ValidateURL = p.ProfileURL } if p.Scope == "" { p.Scope = "r_emailaddress r_basicprofile" @@ -51,7 +51,7 @@ func (p *LinkedInProvider) GetEmailAddress(s *SessionState) (string, error) { if s.AccessToken == "" { return "", errors.New("missing access token") } - req, err := http.NewRequest("GET", p.ProfileUrl.String()+"?format=json", nil) + req, err := http.NewRequest("GET", p.ProfileURL.String()+"?format=json", nil) if err != nil { return "", err } diff --git a/providers/linkedin_test.go b/providers/linkedin_test.go index c75a4a8..f43c96b 100644 --- a/providers/linkedin_test.go +++ b/providers/linkedin_test.go @@ -12,15 +12,15 @@ func testLinkedInProvider(hostname string) *LinkedInProvider { p := NewLinkedInProvider( &ProviderData{ ProviderName: "", - LoginUrl: &url.URL{}, - RedeemUrl: &url.URL{}, - ProfileUrl: &url.URL{}, - ValidateUrl: &url.URL{}, + LoginURL: &url.URL{}, + RedeemURL: &url.URL{}, + ProfileURL: &url.URL{}, + ValidateURL: &url.URL{}, Scope: ""}) if hostname != "" { - updateUrl(p.Data().LoginUrl, hostname) - updateUrl(p.Data().RedeemUrl, hostname) - updateUrl(p.Data().ProfileUrl, hostname) + updateURL(p.Data().LoginURL, hostname) + updateURL(p.Data().RedeemURL, hostname) + updateURL(p.Data().ProfileURL, hostname) } return p } @@ -47,32 +47,32 @@ func TestLinkedInProviderDefaults(t *testing.T) { assert.NotEqual(t, nil, p) assert.Equal(t, "LinkedIn", p.Data().ProviderName) assert.Equal(t, "https://www.linkedin.com/uas/oauth2/authorization", - p.Data().LoginUrl.String()) + p.Data().LoginURL.String()) assert.Equal(t, "https://www.linkedin.com/uas/oauth2/accessToken", - p.Data().RedeemUrl.String()) + p.Data().RedeemURL.String()) assert.Equal(t, "https://www.linkedin.com/v1/people/~/email-address", - p.Data().ProfileUrl.String()) + p.Data().ProfileURL.String()) assert.Equal(t, "https://www.linkedin.com/v1/people/~/email-address", - p.Data().ValidateUrl.String()) + p.Data().ValidateURL.String()) assert.Equal(t, "r_emailaddress r_basicprofile", p.Data().Scope) } func TestLinkedInProviderOverrides(t *testing.T) { p := NewLinkedInProvider( &ProviderData{ - LoginUrl: &url.URL{ + LoginURL: &url.URL{ Scheme: "https", Host: "example.com", Path: "/oauth/auth"}, - RedeemUrl: &url.URL{ + RedeemURL: &url.URL{ Scheme: "https", Host: "example.com", Path: "/oauth/token"}, - ProfileUrl: &url.URL{ + ProfileURL: &url.URL{ Scheme: "https", Host: "example.com", Path: "/oauth/profile"}, - ValidateUrl: &url.URL{ + ValidateURL: &url.URL{ Scheme: "https", Host: "example.com", Path: "/oauth/tokeninfo"}, @@ -80,13 +80,13 @@ func TestLinkedInProviderOverrides(t *testing.T) { assert.NotEqual(t, nil, p) assert.Equal(t, "LinkedIn", p.Data().ProviderName) assert.Equal(t, "https://example.com/oauth/auth", - p.Data().LoginUrl.String()) + p.Data().LoginURL.String()) assert.Equal(t, "https://example.com/oauth/token", - p.Data().RedeemUrl.String()) + p.Data().RedeemURL.String()) assert.Equal(t, "https://example.com/oauth/profile", - p.Data().ProfileUrl.String()) + p.Data().ProfileURL.String()) assert.Equal(t, "https://example.com/oauth/tokeninfo", - p.Data().ValidateUrl.String()) + p.Data().ValidateURL.String()) assert.Equal(t, "profile", p.Data().Scope) } diff --git a/providers/myusa.go b/providers/myusa.go index c244ed0..ae76d34 100644 --- a/providers/myusa.go +++ b/providers/myusa.go @@ -16,23 +16,23 @@ func NewMyUsaProvider(p *ProviderData) *MyUsaProvider { const myUsaHost string = "alpha.my.usa.gov" p.ProviderName = "MyUSA" - if p.LoginUrl.String() == "" { - p.LoginUrl = &url.URL{Scheme: "https", + if p.LoginURL.String() == "" { + p.LoginURL = &url.URL{Scheme: "https", Host: myUsaHost, Path: "/oauth/authorize"} } - if p.RedeemUrl.String() == "" { - p.RedeemUrl = &url.URL{Scheme: "https", + if p.RedeemURL.String() == "" { + p.RedeemURL = &url.URL{Scheme: "https", Host: myUsaHost, Path: "/oauth/token"} } - if p.ProfileUrl.String() == "" { - p.ProfileUrl = &url.URL{Scheme: "https", + if p.ProfileURL.String() == "" { + p.ProfileURL = &url.URL{Scheme: "https", Host: myUsaHost, Path: "/api/v1/profile"} } - if p.ValidateUrl.String() == "" { - p.ValidateUrl = &url.URL{Scheme: "https", + if p.ValidateURL.String() == "" { + p.ValidateURL = &url.URL{Scheme: "https", Host: myUsaHost, Path: "/api/v1/tokeninfo"} } @@ -44,7 +44,7 @@ func NewMyUsaProvider(p *ProviderData) *MyUsaProvider { func (p *MyUsaProvider) GetEmailAddress(s *SessionState) (string, error) { req, err := http.NewRequest("GET", - p.ProfileUrl.String()+"?access_token="+s.AccessToken, nil) + p.ProfileURL.String()+"?access_token="+s.AccessToken, nil) if err != nil { log.Printf("failed building request %s", err) return "", err diff --git a/providers/myusa_test.go b/providers/myusa_test.go index b4bdb30..d058845 100644 --- a/providers/myusa_test.go +++ b/providers/myusa_test.go @@ -9,7 +9,7 @@ import ( "github.com/bmizerany/assert" ) -func updateUrl(url *url.URL, hostname string) { +func updateURL(url *url.URL, hostname string) { url.Scheme = "http" url.Host = hostname } @@ -18,16 +18,16 @@ func testMyUsaProvider(hostname string) *MyUsaProvider { p := NewMyUsaProvider( &ProviderData{ ProviderName: "", - LoginUrl: &url.URL{}, - RedeemUrl: &url.URL{}, - ProfileUrl: &url.URL{}, - ValidateUrl: &url.URL{}, + LoginURL: &url.URL{}, + RedeemURL: &url.URL{}, + ProfileURL: &url.URL{}, + ValidateURL: &url.URL{}, Scope: ""}) if hostname != "" { - updateUrl(p.Data().LoginUrl, hostname) - updateUrl(p.Data().RedeemUrl, hostname) - updateUrl(p.Data().ProfileUrl, hostname) - updateUrl(p.Data().ValidateUrl, hostname) + updateURL(p.Data().LoginURL, hostname) + updateURL(p.Data().RedeemURL, hostname) + updateURL(p.Data().ProfileURL, hostname) + updateURL(p.Data().ValidateURL, hostname) } return p } @@ -53,32 +53,32 @@ func TestMyUsaProviderDefaults(t *testing.T) { assert.NotEqual(t, nil, p) assert.Equal(t, "MyUSA", p.Data().ProviderName) assert.Equal(t, "https://alpha.my.usa.gov/oauth/authorize", - p.Data().LoginUrl.String()) + p.Data().LoginURL.String()) assert.Equal(t, "https://alpha.my.usa.gov/oauth/token", - p.Data().RedeemUrl.String()) + p.Data().RedeemURL.String()) assert.Equal(t, "https://alpha.my.usa.gov/api/v1/profile", - p.Data().ProfileUrl.String()) + p.Data().ProfileURL.String()) assert.Equal(t, "https://alpha.my.usa.gov/api/v1/tokeninfo", - p.Data().ValidateUrl.String()) + p.Data().ValidateURL.String()) assert.Equal(t, "profile.email", p.Data().Scope) } func TestMyUsaProviderOverrides(t *testing.T) { p := NewMyUsaProvider( &ProviderData{ - LoginUrl: &url.URL{ + LoginURL: &url.URL{ Scheme: "https", Host: "example.com", Path: "/oauth/auth"}, - RedeemUrl: &url.URL{ + RedeemURL: &url.URL{ Scheme: "https", Host: "example.com", Path: "/oauth/token"}, - ProfileUrl: &url.URL{ + ProfileURL: &url.URL{ Scheme: "https", Host: "example.com", Path: "/oauth/profile"}, - ValidateUrl: &url.URL{ + ValidateURL: &url.URL{ Scheme: "https", Host: "example.com", Path: "/oauth/tokeninfo"}, @@ -86,13 +86,13 @@ func TestMyUsaProviderOverrides(t *testing.T) { assert.NotEqual(t, nil, p) assert.Equal(t, "MyUSA", p.Data().ProviderName) assert.Equal(t, "https://example.com/oauth/auth", - p.Data().LoginUrl.String()) + p.Data().LoginURL.String()) assert.Equal(t, "https://example.com/oauth/token", - p.Data().RedeemUrl.String()) + p.Data().RedeemURL.String()) assert.Equal(t, "https://example.com/oauth/profile", - p.Data().ProfileUrl.String()) + p.Data().ProfileURL.String()) assert.Equal(t, "https://example.com/oauth/tokeninfo", - p.Data().ValidateUrl.String()) + p.Data().ValidateURL.String()) assert.Equal(t, "profile", p.Data().Scope) } diff --git a/providers/provider_data.go b/providers/provider_data.go index 6ddfed1..a13ed8e 100644 --- a/providers/provider_data.go +++ b/providers/provider_data.go @@ -8,10 +8,10 @@ type ProviderData struct { ProviderName string ClientID string ClientSecret string - LoginUrl *url.URL - RedeemUrl *url.URL - ProfileUrl *url.URL - ValidateUrl *url.URL + LoginURL *url.URL + RedeemURL *url.URL + ProfileURL *url.URL + ValidateURL *url.URL Scope string ApprovalPrompt string } diff --git a/providers/provider_default.go b/providers/provider_default.go index 1a2e7f7..77b3dfd 100644 --- a/providers/provider_default.go +++ b/providers/provider_default.go @@ -13,20 +13,20 @@ import ( "github.com/bitly/oauth2_proxy/cookie" ) -func (p *ProviderData) Redeem(redirectUrl, code string) (s *SessionState, err error) { +func (p *ProviderData) Redeem(redirectURL, code string) (s *SessionState, err error) { if code == "" { err = errors.New("missing code") return } params := url.Values{} - params.Add("redirect_uri", redirectUrl) + params.Add("redirect_uri", redirectURL) params.Add("client_id", p.ClientID) params.Add("client_secret", p.ClientSecret) params.Add("code", code) params.Add("grant_type", "authorization_code") var req *http.Request - req, err = http.NewRequest("POST", p.RedeemUrl.String(), bytes.NewBufferString(params.Encode())) + req, err = http.NewRequest("POST", p.RedeemURL.String(), bytes.NewBufferString(params.Encode())) if err != nil { return } @@ -45,7 +45,7 @@ func (p *ProviderData) Redeem(redirectUrl, code string) (s *SessionState, err er } if resp.StatusCode != 200 { - err = fmt.Errorf("got %d from %q %s", resp.StatusCode, p.RedeemUrl.String(), body) + err = fmt.Errorf("got %d from %q %s", resp.StatusCode, p.RedeemURL.String(), body) return } @@ -77,7 +77,7 @@ func (p *ProviderData) Redeem(redirectUrl, code string) (s *SessionState, err er // GetLoginURL with typical oauth parameters func (p *ProviderData) GetLoginURL(redirectURI, finalRedirect string) string { var a url.URL - a = *p.LoginUrl + a = *p.LoginURL params, _ := url.ParseQuery(a.RawQuery) params.Set("redirect_uri", redirectURI) params.Set("approval_prompt", p.ApprovalPrompt)