Merge branch 'master' of github.com:outlook/oauth2_proxy into work
This commit is contained in:
commit
51ac937bcc
|
|
@ -4,7 +4,7 @@ oauth2_proxy
|
||||||
A reverse proxy and static file server that provides authentication using Providers (Google, GitHub, and others)
|
A reverse proxy and static file server that provides authentication using Providers (Google, GitHub, and others)
|
||||||
to validate accounts by email, domain or group.
|
to validate accounts by email, domain or group.
|
||||||
|
|
||||||
[](http://travis-ci.org/bitly/oauth2_proxy)
|
[](http://travis-ci.org/bitly/oauth2_proxy)
|
||||||
|
|
||||||
|
|
||||||

|

|
||||||
|
|
@ -161,7 +161,7 @@ To authorize by email domain use `--email-domain=yourcompany.com`. To authorize
|
||||||
|
|
||||||
`oauth2_proxy` can be configured via [config file](#config-file), [command line options](#command-line-options) or [environment variables](#environment-variables).
|
`oauth2_proxy` can be configured via [config file](#config-file), [command line options](#command-line-options) or [environment variables](#environment-variables).
|
||||||
|
|
||||||
To generate a strong cookie secret use `python -c 'import os,base64; print base64.b64encode(os.urandom(16))'`
|
To generate a strong cookie secret use `python -c 'import os,base64; print base64.urlsafe_b64encode(os.urandom(16))'`
|
||||||
|
|
||||||
### Config File
|
### Config File
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -491,7 +491,11 @@ func (p *OAuthProxy) SignIn(rw http.ResponseWriter, req *http.Request) {
|
||||||
p.SaveSession(rw, req, session)
|
p.SaveSession(rw, req, session)
|
||||||
http.Redirect(rw, req, redirect, 302)
|
http.Redirect(rw, req, redirect, 302)
|
||||||
} else {
|
} else {
|
||||||
p.SignInPage(rw, req, 200)
|
if p.SkipProviderButton {
|
||||||
|
p.OAuthStart(rw, req)
|
||||||
|
} else {
|
||||||
|
p.SignInPage(rw, req, http.StatusOK)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,6 @@ package main
|
||||||
import (
|
import (
|
||||||
"crypto"
|
"crypto"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"github.com/18F/hmacauth"
|
|
||||||
"github.com/bitly/oauth2_proxy/providers"
|
|
||||||
"github.com/bmizerany/assert"
|
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
|
@ -17,6 +14,10 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/18F/hmacauth"
|
||||||
|
"github.com/bitly/oauth2_proxy/providers"
|
||||||
|
"github.com/bmizerany/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
@ -359,26 +360,30 @@ func TestDoNotForwardAccessTokenUpstream(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type SignInPageTest struct {
|
type SignInPageTest struct {
|
||||||
opts *Options
|
opts *Options
|
||||||
proxy *OAuthProxy
|
proxy *OAuthProxy
|
||||||
sign_in_regexp *regexp.Regexp
|
sign_in_regexp *regexp.Regexp
|
||||||
|
sign_in_provider_regexp *regexp.Regexp
|
||||||
}
|
}
|
||||||
|
|
||||||
const signInRedirectPattern = `<input type="hidden" name="rd" value="(.*)">`
|
const signInRedirectPattern = `<input type="hidden" name="rd" value="(.*)">`
|
||||||
|
const signInSkipProvider = `>Found<`
|
||||||
|
|
||||||
func NewSignInPageTest() *SignInPageTest {
|
func NewSignInPageTest(skipProvider bool) *SignInPageTest {
|
||||||
var sip_test SignInPageTest
|
var sip_test SignInPageTest
|
||||||
|
|
||||||
sip_test.opts = NewOptions()
|
sip_test.opts = NewOptions()
|
||||||
sip_test.opts.CookieSecret = "foobar"
|
sip_test.opts.CookieSecret = "foobar"
|
||||||
sip_test.opts.ClientID = "bazquux"
|
sip_test.opts.ClientID = "bazquux"
|
||||||
sip_test.opts.ClientSecret = "xyzzyplugh"
|
sip_test.opts.ClientSecret = "xyzzyplugh"
|
||||||
|
sip_test.opts.SkipProviderButton = skipProvider
|
||||||
sip_test.opts.Validate()
|
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
|
return true
|
||||||
})
|
})
|
||||||
sip_test.sign_in_regexp = regexp.MustCompile(signInRedirectPattern)
|
sip_test.sign_in_regexp = regexp.MustCompile(signInRedirectPattern)
|
||||||
|
sip_test.sign_in_provider_regexp = regexp.MustCompile(signInSkipProvider)
|
||||||
|
|
||||||
return &sip_test
|
return &sip_test
|
||||||
}
|
}
|
||||||
|
|
@ -391,7 +396,7 @@ func (sip_test *SignInPageTest) GetEndpoint(endpoint string) (int, string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSignInPageIncludesTargetRedirect(t *testing.T) {
|
func TestSignInPageIncludesTargetRedirect(t *testing.T) {
|
||||||
sip_test := NewSignInPageTest()
|
sip_test := NewSignInPageTest(false)
|
||||||
const endpoint = "/some/random/endpoint"
|
const endpoint = "/some/random/endpoint"
|
||||||
|
|
||||||
code, body := sip_test.GetEndpoint(endpoint)
|
code, body := sip_test.GetEndpoint(endpoint)
|
||||||
|
|
@ -409,7 +414,7 @@ func TestSignInPageIncludesTargetRedirect(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSignInPageDirectAccessRedirectsToRoot(t *testing.T) {
|
func TestSignInPageDirectAccessRedirectsToRoot(t *testing.T) {
|
||||||
sip_test := NewSignInPageTest()
|
sip_test := NewSignInPageTest(false)
|
||||||
code, body := sip_test.GetEndpoint("/oauth2/sign_in")
|
code, body := sip_test.GetEndpoint("/oauth2/sign_in")
|
||||||
assert.Equal(t, 200, code)
|
assert.Equal(t, 200, code)
|
||||||
|
|
||||||
|
|
@ -423,6 +428,34 @@ func TestSignInPageDirectAccessRedirectsToRoot(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSignInPageSkipProvider(t *testing.T) {
|
||||||
|
sip_test := NewSignInPageTest(true)
|
||||||
|
const endpoint = "/some/random/endpoint"
|
||||||
|
|
||||||
|
code, body := sip_test.GetEndpoint(endpoint)
|
||||||
|
assert.Equal(t, 302, code)
|
||||||
|
|
||||||
|
match := sip_test.sign_in_provider_regexp.FindStringSubmatch(body)
|
||||||
|
if match == nil {
|
||||||
|
t.Fatal("Did not find pattern in body: " +
|
||||||
|
signInSkipProvider + "\nBody:\n" + body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSignInPageSkipProviderDirect(t *testing.T) {
|
||||||
|
sip_test := NewSignInPageTest(true)
|
||||||
|
const endpoint = "/sign_in"
|
||||||
|
|
||||||
|
code, body := sip_test.GetEndpoint(endpoint)
|
||||||
|
assert.Equal(t, 302, code)
|
||||||
|
|
||||||
|
match := sip_test.sign_in_provider_regexp.FindStringSubmatch(body)
|
||||||
|
if match == nil {
|
||||||
|
t.Fatal("Did not find pattern in body: " +
|
||||||
|
signInSkipProvider + "\nBody:\n" + body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type ProcessCookieTest struct {
|
type ProcessCookieTest struct {
|
||||||
opts *Options
|
opts *Options
|
||||||
proxy *OAuthProxy
|
proxy *OAuthProxy
|
||||||
|
|
|
||||||
20
options.go
20
options.go
|
|
@ -111,6 +111,7 @@ func NewOptions() *Options {
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
ApprovalPrompt: "",
|
ApprovalPrompt: "",
|
||||||
RequestLogging: true,
|
RequestLogging: true,
|
||||||
|
Provider: "google",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -125,9 +126,6 @@ func parseURL(to_parse string, urltype string, msgs []string) (*url.URL, []strin
|
||||||
|
|
||||||
func (o *Options) Validate() error {
|
func (o *Options) Validate() error {
|
||||||
msgs := make([]string, 0)
|
msgs := make([]string, 0)
|
||||||
if len(o.Upstreams) < 1 {
|
|
||||||
msgs = append(msgs, "missing setting: upstream")
|
|
||||||
}
|
|
||||||
if o.CookieSecret == "" {
|
if o.CookieSecret == "" {
|
||||||
msgs = append(msgs, "missing setting: cookie-secret")
|
msgs = append(msgs, "missing setting: cookie-secret")
|
||||||
}
|
}
|
||||||
|
|
@ -138,7 +136,8 @@ func (o *Options) Validate() error {
|
||||||
msgs = append(msgs, "missing setting: client-secret")
|
msgs = append(msgs, "missing setting: client-secret")
|
||||||
}
|
}
|
||||||
if o.AuthenticatedEmailsFile == "" && len(o.EmailDomains) == 0 && o.HtpasswdFile == "" {
|
if o.AuthenticatedEmailsFile == "" && len(o.EmailDomains) == 0 && o.HtpasswdFile == "" {
|
||||||
msgs = append(msgs, "missing setting for email validation: email-domain or authenticated-emails-file required.\n use email-domain=* to authorize all email addresses")
|
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)
|
||||||
|
|
@ -146,14 +145,13 @@ func (o *Options) Validate() error {
|
||||||
for _, u := range o.Upstreams {
|
for _, u := range o.Upstreams {
|
||||||
upstreamURL, err := url.Parse(u)
|
upstreamURL, err := url.Parse(u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msgs = append(msgs, fmt.Sprintf(
|
msgs = append(msgs, fmt.Sprintf("error parsing upstream: %s", err))
|
||||||
"error parsing upstream=%q %s",
|
} else {
|
||||||
upstreamURL, err))
|
if upstreamURL.Path == "" {
|
||||||
|
upstreamURL.Path = "/"
|
||||||
|
}
|
||||||
|
o.proxyURLs = append(o.proxyURLs, upstreamURL)
|
||||||
}
|
}
|
||||||
if upstreamURL.Path == "" {
|
|
||||||
upstreamURL.Path = "/"
|
|
||||||
}
|
|
||||||
o.proxyURLs = append(o.proxyURLs, upstreamURL)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, u := range o.SkipAuthRegex {
|
for _, u := range o.SkipAuthRegex {
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ func TestNewOptions(t *testing.T) {
|
||||||
assert.NotEqual(t, nil, err)
|
assert.NotEqual(t, nil, err)
|
||||||
|
|
||||||
expected := errorMsg([]string{
|
expected := errorMsg([]string{
|
||||||
"missing setting: upstream",
|
|
||||||
"missing setting: cookie-secret",
|
"missing setting: cookie-secret",
|
||||||
"missing setting: client-id",
|
"missing setting: client-id",
|
||||||
"missing setting: client-secret"})
|
"missing setting: client-secret"})
|
||||||
|
|
|
||||||
|
|
@ -206,7 +206,11 @@ func (p *AzureProvider) GetLoginURL(redirectURI, state string) string {
|
||||||
params.Add("state", state)
|
params.Add("state", state)
|
||||||
params.Set("prompt", p.ApprovalPrompt)
|
params.Set("prompt", p.ApprovalPrompt)
|
||||||
params.Set("nonce", "FIXME")
|
params.Set("nonce", "FIXME")
|
||||||
|
if p.ProtectedResource != nil && p.ProtectedResource.String() != "" {
|
||||||
|
params.Add("resource", p.ProtectedResource.String())
|
||||||
|
}
|
||||||
a.RawQuery = params.Encode()
|
a.RawQuery = params.Encode()
|
||||||
|
|
||||||
return a.String()
|
return a.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -351,3 +351,18 @@ func TestAzureRightPermittedGroups(t *testing.T) {
|
||||||
|
|
||||||
assert.Equal(t, true, result)
|
assert.Equal(t, true, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAzureLoginURLnoResource(t *testing.T) {
|
||||||
|
p := testAzureProvider("")
|
||||||
|
p.ProtectedResource = nil
|
||||||
|
|
||||||
|
result := p.GetLoginURL("http://redirect/url", "state")
|
||||||
|
assert.Equal(t, "?client_id=&nonce=FIXME&prompt=&redirect_uri=http%3A%2F%2Fredirect%2Furl&response_mode=form_post&response_type=id_token+code&scope=openid&state=state", result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAzureLoginURL(t *testing.T) {
|
||||||
|
p := testAzureProvider("")
|
||||||
|
|
||||||
|
result := p.GetLoginURL("http://redirect/url", "state")
|
||||||
|
assert.Equal(t, "?client_id=&nonce=FIXME&prompt=&redirect_uri=http%3A%2F%2Fredirect%2Furl&resource=https%3A%2F%2Fgraph.microsoft.com&response_mode=form_post&response_type=id_token+code&scope=openid&state=state", result)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ func validateToken(p Provider, access_token string, header http.Header) bool {
|
||||||
}
|
}
|
||||||
resp, err := api.RequestUnparsedResponse(endpoint, header)
|
resp, err := api.RequestUnparsedResponse(endpoint, header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("GET %s", endpoint)
|
log.Printf("GET %s", stripToken(endpoint))
|
||||||
log.Printf("token validation request failed: %s", err)
|
log.Printf("token validation request failed: %s", err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue