Merge pull request #129 from jburnham/basic_auth_password
Add support for setting the basic auth password.
This commit is contained in:
commit
c086bddcbe
@ -116,6 +116,7 @@ Usage of oauth2_proxy:
|
|||||||
-login-url="": Authentication endpoint
|
-login-url="": Authentication endpoint
|
||||||
-pass-access-token=false: pass OAuth access_token to upstream via X-Forwarded-Access-Token header
|
-pass-access-token=false: pass OAuth access_token to upstream via X-Forwarded-Access-Token header
|
||||||
-pass-basic-auth=true: pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream
|
-pass-basic-auth=true: pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream
|
||||||
|
-basic-auth-password="": the password to set when passing the HTTP Basic Auth header
|
||||||
-pass-host-header=true: pass the request Host Header to upstream
|
-pass-host-header=true: pass the request Host Header to upstream
|
||||||
-profile-url="": Profile access endpoint
|
-profile-url="": Profile access endpoint
|
||||||
-provider="google": OAuth provider
|
-provider="google": OAuth provider
|
||||||
|
1
main.go
1
main.go
@ -31,6 +31,7 @@ func main() {
|
|||||||
flagSet.String("redirect-url", "", "the OAuth Redirect URL. ie: \"https://internalapp.yourcompany.com/oauth2/callback\"")
|
flagSet.String("redirect-url", "", "the OAuth Redirect URL. ie: \"https://internalapp.yourcompany.com/oauth2/callback\"")
|
||||||
flagSet.Var(&upstreams, "upstream", "the http url(s) of the upstream endpoint. If multiple, routing is based on path")
|
flagSet.Var(&upstreams, "upstream", "the http url(s) of the upstream endpoint. If multiple, routing is based on path")
|
||||||
flagSet.Bool("pass-basic-auth", true, "pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream")
|
flagSet.Bool("pass-basic-auth", true, "pass HTTP Basic Auth, X-Forwarded-User and X-Forwarded-Email information to upstream")
|
||||||
|
flagSet.String("basic-auth-password", "", "the password to set when passing the HTTP Basic Auth header")
|
||||||
flagSet.Bool("pass-access-token", false, "pass OAuth access_token to upstream via X-Forwarded-Access-Token header")
|
flagSet.Bool("pass-access-token", false, "pass OAuth access_token to upstream via X-Forwarded-Access-Token header")
|
||||||
flagSet.Bool("pass-host-header", true, "pass the request Host Header to upstream")
|
flagSet.Bool("pass-host-header", true, "pass the request Host Header to upstream")
|
||||||
flagSet.Var(&skipAuthRegex, "skip-auth-regex", "bypass authentication for requests path's that match (may be given multiple times)")
|
flagSet.Var(&skipAuthRegex, "skip-auth-regex", "bypass authentication for requests path's that match (may be given multiple times)")
|
||||||
|
@ -42,6 +42,7 @@ type OauthProxy struct {
|
|||||||
DisplayHtpasswdForm bool
|
DisplayHtpasswdForm bool
|
||||||
serveMux http.Handler
|
serveMux http.Handler
|
||||||
PassBasicAuth bool
|
PassBasicAuth bool
|
||||||
|
BasicAuthPassword string
|
||||||
PassAccessToken bool
|
PassAccessToken bool
|
||||||
CookieCipher *cookie.Cipher
|
CookieCipher *cookie.Cipher
|
||||||
skipAuthRegex []string
|
skipAuthRegex []string
|
||||||
@ -141,16 +142,17 @@ func NewOauthProxy(opts *Options, validator func(string) bool) *OauthProxy {
|
|||||||
OauthStartPath: fmt.Sprintf("%s/start", opts.ProxyPrefix),
|
OauthStartPath: fmt.Sprintf("%s/start", opts.ProxyPrefix),
|
||||||
OauthCallbackPath: fmt.Sprintf("%s/callback", opts.ProxyPrefix),
|
OauthCallbackPath: fmt.Sprintf("%s/callback", opts.ProxyPrefix),
|
||||||
|
|
||||||
ProxyPrefix: opts.ProxyPrefix,
|
ProxyPrefix: opts.ProxyPrefix,
|
||||||
provider: opts.provider,
|
provider: opts.provider,
|
||||||
serveMux: serveMux,
|
serveMux: serveMux,
|
||||||
redirectUrl: redirectUrl,
|
redirectUrl: redirectUrl,
|
||||||
skipAuthRegex: opts.SkipAuthRegex,
|
skipAuthRegex: opts.SkipAuthRegex,
|
||||||
compiledRegex: opts.CompiledRegex,
|
compiledRegex: opts.CompiledRegex,
|
||||||
PassBasicAuth: opts.PassBasicAuth,
|
PassBasicAuth: opts.PassBasicAuth,
|
||||||
PassAccessToken: opts.PassAccessToken,
|
BasicAuthPassword: opts.BasicAuthPassword,
|
||||||
CookieCipher: cipher,
|
PassAccessToken: opts.PassAccessToken,
|
||||||
templates: loadTemplates(opts.CustomTemplatesDir),
|
CookieCipher: cipher,
|
||||||
|
templates: loadTemplates(opts.CustomTemplatesDir),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -518,7 +520,7 @@ func (p *OauthProxy) Proxy(rw http.ResponseWriter, req *http.Request) {
|
|||||||
|
|
||||||
// At this point, the user is authenticated. proxy normally
|
// At this point, the user is authenticated. proxy normally
|
||||||
if p.PassBasicAuth {
|
if p.PassBasicAuth {
|
||||||
req.SetBasicAuth(session.User, "")
|
req.SetBasicAuth(session.User, p.BasicAuthPassword)
|
||||||
req.Header["X-Forwarded-User"] = []string{session.User}
|
req.Header["X-Forwarded-User"] = []string{session.User}
|
||||||
if session.Email != "" {
|
if session.Email != "" {
|
||||||
req.Header["X-Forwarded-Email"] = []string{session.Email}
|
req.Header["X-Forwarded-Email"] = []string{session.Email}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
"github.com/bitly/oauth2_proxy/providers"
|
"github.com/bitly/oauth2_proxy/providers"
|
||||||
"github.com/bmizerany/assert"
|
"github.com/bmizerany/assert"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@ -88,6 +89,101 @@ func TestRobotsTxt(t *testing.T) {
|
|||||||
assert.Equal(t, "User-agent: *\nDisallow: /", rw.Body.String())
|
assert.Equal(t, "User-agent: *\nDisallow: /", rw.Body.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBasicAuthPassword(t *testing.T) {
|
||||||
|
provider_server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log.Printf("%#v", r)
|
||||||
|
url := r.URL
|
||||||
|
payload := ""
|
||||||
|
switch url.Path {
|
||||||
|
case "/oauth/token":
|
||||||
|
payload = `{"access_token": "my_auth_token"}`
|
||||||
|
default:
|
||||||
|
payload = r.Header.Get("Authorization")
|
||||||
|
if payload == "" {
|
||||||
|
payload = "No Authorization header found."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.WriteHeader(200)
|
||||||
|
w.Write([]byte(payload))
|
||||||
|
}))
|
||||||
|
opts := NewOptions()
|
||||||
|
opts.Upstreams = append(opts.Upstreams, provider_server.URL)
|
||||||
|
// The CookieSecret must be 32 bytes in order to create the AES
|
||||||
|
// cipher.
|
||||||
|
opts.CookieSecret = "xyzzyplughxyzzyplughxyzzyplughxp"
|
||||||
|
opts.ClientID = "bazquux"
|
||||||
|
opts.ClientSecret = "foobar"
|
||||||
|
opts.CookieSecure = false
|
||||||
|
opts.PassBasicAuth = true
|
||||||
|
opts.BasicAuthPassword = "This is a secure password"
|
||||||
|
opts.Validate()
|
||||||
|
|
||||||
|
provider_url, _ := url.Parse(provider_server.URL)
|
||||||
|
const email_address = "michael.bland@gsa.gov"
|
||||||
|
const user_name = "michael.bland"
|
||||||
|
|
||||||
|
opts.provider = &TestProvider{
|
||||||
|
ProviderData: &providers.ProviderData{
|
||||||
|
ProviderName: "Test Provider",
|
||||||
|
LoginUrl: &url.URL{
|
||||||
|
Scheme: "http",
|
||||||
|
Host: provider_url.Host,
|
||||||
|
Path: "/oauth/authorize",
|
||||||
|
},
|
||||||
|
RedeemUrl: &url.URL{
|
||||||
|
Scheme: "http",
|
||||||
|
Host: provider_url.Host,
|
||||||
|
Path: "/oauth/token",
|
||||||
|
},
|
||||||
|
ProfileUrl: &url.URL{
|
||||||
|
Scheme: "http",
|
||||||
|
Host: provider_url.Host,
|
||||||
|
Path: "/api/v1/profile",
|
||||||
|
},
|
||||||
|
Scope: "profile.email",
|
||||||
|
},
|
||||||
|
EmailAddress: email_address,
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy := NewOauthProxy(opts, func(email string) bool {
|
||||||
|
return email == email_address
|
||||||
|
})
|
||||||
|
|
||||||
|
rw := httptest.NewRecorder()
|
||||||
|
req, _ := http.NewRequest("GET", "/oauth2/callback?code=callback_code",
|
||||||
|
strings.NewReader(""))
|
||||||
|
proxy.ServeHTTP(rw, req)
|
||||||
|
cookie := rw.HeaderMap["Set-Cookie"][0]
|
||||||
|
|
||||||
|
cookieName := proxy.CookieName
|
||||||
|
var value string
|
||||||
|
key_prefix := cookieName + "="
|
||||||
|
|
||||||
|
for _, field := range strings.Split(cookie, "; ") {
|
||||||
|
value = strings.TrimPrefix(field, key_prefix)
|
||||||
|
if value != field {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
value = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
req, _ = http.NewRequest("GET", "/", strings.NewReader(""))
|
||||||
|
req.AddCookie(&http.Cookie{
|
||||||
|
Name: cookieName,
|
||||||
|
Value: value,
|
||||||
|
Path: "/",
|
||||||
|
Expires: time.Now().Add(time.Duration(24)),
|
||||||
|
HttpOnly: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
rw = httptest.NewRecorder()
|
||||||
|
proxy.ServeHTTP(rw, req)
|
||||||
|
expectedHeader := "Basic " + base64.StdEncoding.EncodeToString([]byte(user_name+":"+opts.BasicAuthPassword))
|
||||||
|
assert.Equal(t, expectedHeader, rw.Body.String())
|
||||||
|
provider_server.Close()
|
||||||
|
}
|
||||||
|
|
||||||
type TestProvider struct {
|
type TestProvider struct {
|
||||||
*providers.ProviderData
|
*providers.ProviderData
|
||||||
EmailAddress string
|
EmailAddress string
|
||||||
|
11
options.go
11
options.go
@ -37,11 +37,12 @@ type Options struct {
|
|||||||
CookieSecure bool `flag:"cookie-secure" cfg:"cookie_secure"`
|
CookieSecure bool `flag:"cookie-secure" cfg:"cookie_secure"`
|
||||||
CookieHttpOnly bool `flag:"cookie-httponly" cfg:"cookie_httponly"`
|
CookieHttpOnly bool `flag:"cookie-httponly" cfg:"cookie_httponly"`
|
||||||
|
|
||||||
Upstreams []string `flag:"upstream" cfg:"upstreams"`
|
Upstreams []string `flag:"upstream" cfg:"upstreams"`
|
||||||
SkipAuthRegex []string `flag:"skip-auth-regex" cfg:"skip_auth_regex"`
|
SkipAuthRegex []string `flag:"skip-auth-regex" cfg:"skip_auth_regex"`
|
||||||
PassBasicAuth bool `flag:"pass-basic-auth" cfg:"pass_basic_auth"`
|
PassBasicAuth bool `flag:"pass-basic-auth" cfg:"pass_basic_auth"`
|
||||||
PassAccessToken bool `flag:"pass-access-token" cfg:"pass_access_token"`
|
BasicAuthPassword string `flag:"basic-auth-password" cfg:"basic_auth_password"`
|
||||||
PassHostHeader bool `flag:"pass-host-header" cfg:"pass_host_header"`
|
PassAccessToken bool `flag:"pass-access-token" cfg:"pass_access_token"`
|
||||||
|
PassHostHeader bool `flag:"pass-host-header" cfg:"pass_host_header"`
|
||||||
|
|
||||||
// These options allow for other providers besides Google, with
|
// These options allow for other providers besides Google, with
|
||||||
// potential overrides.
|
// potential overrides.
|
||||||
|
Loading…
Reference in New Issue
Block a user