mirror of
https://github.com/oauth2-proxy/oauth2-proxy.git
synced 2025-02-01 13:18:05 +02:00
Merge remote-tracking branch 'upstream/master' into helm-example
# Conflicts: # CHANGELOG.md
This commit is contained in:
commit
054979978f
@ -56,6 +56,7 @@
|
|||||||
## Changes since v5.1.1
|
## Changes since v5.1.1
|
||||||
|
|
||||||
- [#615](https://github.com/oauth2-proxy/oauth2-proxy/pull/615) Kubernetes example based on Kind cluster and Nginx ingress (@EvgeniGordeev)
|
- [#615](https://github.com/oauth2-proxy/oauth2-proxy/pull/615) Kubernetes example based on Kind cluster and Nginx ingress (@EvgeniGordeev)
|
||||||
|
- [#596](https://github.com/oauth2-proxy/oauth2-proxy/pull/596) Validate Bearer IDTokens in headers with correct provider/extra JWT Verifier (@NickMeves)
|
||||||
- [#620](https://github.com/oauth2-proxy/oauth2-proxy/pull/620) Add HealthCheck middleware (@JoelSpeed)
|
- [#620](https://github.com/oauth2-proxy/oauth2-proxy/pull/620) Add HealthCheck middleware (@JoelSpeed)
|
||||||
- [#597](https://github.com/oauth2-proxy/oauth2-proxy/pull/597) Don't log invalid redirect if redirect is empty (@JoelSpeed)
|
- [#597](https://github.com/oauth2-proxy/oauth2-proxy/pull/597) Don't log invalid redirect if redirect is empty (@JoelSpeed)
|
||||||
- [#604](https://github.com/oauth2-proxy/oauth2-proxy/pull/604) Add Keycloak local testing environment (@EvgeniGordeev)
|
- [#604](https://github.com/oauth2-proxy/oauth2-proxy/pull/604) Add Keycloak local testing environment (@EvgeniGordeev)
|
||||||
|
129
oauthproxy.go
129
oauthproxy.go
@ -88,35 +88,36 @@ type OAuthProxy struct {
|
|||||||
AuthOnlyPath string
|
AuthOnlyPath string
|
||||||
UserInfoPath string
|
UserInfoPath string
|
||||||
|
|
||||||
redirectURL *url.URL // the url to receive requests at
|
redirectURL *url.URL // the url to receive requests at
|
||||||
whitelistDomains []string
|
whitelistDomains []string
|
||||||
provider providers.Provider
|
provider providers.Provider
|
||||||
providerNameOverride string
|
providerNameOverride string
|
||||||
sessionStore sessionsapi.SessionStore
|
sessionStore sessionsapi.SessionStore
|
||||||
ProxyPrefix string
|
ProxyPrefix string
|
||||||
SignInMessage string
|
SignInMessage string
|
||||||
HtpasswdFile *HtpasswdFile
|
HtpasswdFile *HtpasswdFile
|
||||||
DisplayHtpasswdForm bool
|
DisplayHtpasswdForm bool
|
||||||
serveMux http.Handler
|
serveMux http.Handler
|
||||||
SetXAuthRequest bool
|
SetXAuthRequest bool
|
||||||
PassBasicAuth bool
|
PassBasicAuth bool
|
||||||
SetBasicAuth bool
|
SetBasicAuth bool
|
||||||
SkipProviderButton bool
|
SkipProviderButton bool
|
||||||
PassUserHeaders bool
|
PassUserHeaders bool
|
||||||
BasicAuthPassword string
|
BasicAuthPassword string
|
||||||
PassAccessToken bool
|
PassAccessToken bool
|
||||||
SetAuthorization bool
|
SetAuthorization bool
|
||||||
PassAuthorization bool
|
PassAuthorization bool
|
||||||
PreferEmailToUser bool
|
PreferEmailToUser bool
|
||||||
skipAuthRegex []string
|
skipAuthRegex []string
|
||||||
skipAuthPreflight bool
|
skipAuthPreflight bool
|
||||||
skipJwtBearerTokens bool
|
skipJwtBearerTokens bool
|
||||||
jwtBearerVerifiers []*oidc.IDTokenVerifier
|
mainJwtBearerVerifier *oidc.IDTokenVerifier
|
||||||
compiledRegex []*regexp.Regexp
|
extraJwtBearerVerifiers []*oidc.IDTokenVerifier
|
||||||
templates *template.Template
|
compiledRegex []*regexp.Regexp
|
||||||
realClientIPParser ipapi.RealClientIPParser
|
templates *template.Template
|
||||||
Banner string
|
realClientIPParser ipapi.RealClientIPParser
|
||||||
Footer string
|
Banner string
|
||||||
|
Footer string
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpstreamProxy represents an upstream server to proxy to
|
// UpstreamProxy represents an upstream server to proxy to
|
||||||
@ -317,32 +318,33 @@ func NewOAuthProxy(opts *options.Options, validator func(string) bool) *OAuthPro
|
|||||||
AuthOnlyPath: fmt.Sprintf("%s/auth", opts.ProxyPrefix),
|
AuthOnlyPath: fmt.Sprintf("%s/auth", opts.ProxyPrefix),
|
||||||
UserInfoPath: fmt.Sprintf("%s/userinfo", opts.ProxyPrefix),
|
UserInfoPath: fmt.Sprintf("%s/userinfo", opts.ProxyPrefix),
|
||||||
|
|
||||||
ProxyPrefix: opts.ProxyPrefix,
|
ProxyPrefix: opts.ProxyPrefix,
|
||||||
provider: opts.GetProvider(),
|
provider: opts.GetProvider(),
|
||||||
providerNameOverride: opts.ProviderName,
|
providerNameOverride: opts.ProviderName,
|
||||||
sessionStore: opts.GetSessionStore(),
|
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.GetJWTBearerVerifiers(),
|
mainJwtBearerVerifier: opts.GetOIDCVerifier(),
|
||||||
compiledRegex: opts.GetCompiledRegex(),
|
extraJwtBearerVerifiers: opts.GetJWTBearerVerifiers(),
|
||||||
realClientIPParser: opts.GetRealClientIPParser(),
|
compiledRegex: opts.GetCompiledRegex(),
|
||||||
SetXAuthRequest: opts.SetXAuthRequest,
|
realClientIPParser: opts.GetRealClientIPParser(),
|
||||||
PassBasicAuth: opts.PassBasicAuth,
|
SetXAuthRequest: opts.SetXAuthRequest,
|
||||||
SetBasicAuth: opts.SetBasicAuth,
|
PassBasicAuth: opts.PassBasicAuth,
|
||||||
PassUserHeaders: opts.PassUserHeaders,
|
SetBasicAuth: opts.SetBasicAuth,
|
||||||
BasicAuthPassword: opts.BasicAuthPassword,
|
PassUserHeaders: opts.PassUserHeaders,
|
||||||
PassAccessToken: opts.PassAccessToken,
|
BasicAuthPassword: opts.BasicAuthPassword,
|
||||||
SetAuthorization: opts.SetAuthorization,
|
PassAccessToken: opts.PassAccessToken,
|
||||||
PassAuthorization: opts.PassAuthorization,
|
SetAuthorization: opts.SetAuthorization,
|
||||||
PreferEmailToUser: opts.PreferEmailToUser,
|
PassAuthorization: opts.PassAuthorization,
|
||||||
SkipProviderButton: opts.SkipProviderButton,
|
PreferEmailToUser: opts.PreferEmailToUser,
|
||||||
templates: loadTemplates(opts.CustomTemplatesDir),
|
SkipProviderButton: opts.SkipProviderButton,
|
||||||
Banner: opts.Banner,
|
templates: loadTemplates(opts.CustomTemplatesDir),
|
||||||
Footer: opts.Footer,
|
Banner: opts.Banner,
|
||||||
|
Footer: opts.Footer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1139,15 +1141,24 @@ func (p *OAuthProxy) GetJwtSession(req *http.Request) (*sessionsapi.SessionState
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, verifier := range p.jwtBearerVerifiers {
|
// If we are using an oidc provider, go ahead and try that provider first with its Verifier
|
||||||
bearerToken, err := verifier.Verify(req.Context(), rawBearerToken)
|
// and Bearer Token -> Session converter
|
||||||
|
if p.mainJwtBearerVerifier != nil {
|
||||||
|
bearerToken, err := p.mainJwtBearerVerifier.Verify(req.Context(), rawBearerToken)
|
||||||
|
if err == nil {
|
||||||
|
return p.provider.CreateSessionStateFromBearerToken(req.Context(), rawBearerToken, bearerToken)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, attempt to verify against the extra JWT issuers and use a more generic
|
||||||
|
// Bearer Token -> Session converter
|
||||||
|
for _, verifier := range p.extraJwtBearerVerifiers {
|
||||||
|
bearerToken, err := verifier.Verify(req.Context(), rawBearerToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Printf("failed to verify bearer token: %v", err)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
return p.provider.CreateSessionStateFromBearerToken(req.Context(), rawBearerToken, bearerToken)
|
return (*providers.ProviderData)(nil).CreateSessionStateFromBearerToken(req.Context(), rawBearerToken, bearerToken)
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("unable to verify jwt token %s", req.Header.Get("Authorization"))
|
return nil, fmt.Errorf("unable to verify jwt token %s", req.Header.Get("Authorization"))
|
||||||
}
|
}
|
||||||
|
@ -1578,7 +1578,7 @@ func TestGetJwtSession(t *testing.T) {
|
|||||||
// Bearer
|
// Bearer
|
||||||
expires := time.Unix(1912151821, 0)
|
expires := time.Unix(1912151821, 0)
|
||||||
session, _ := test.proxy.GetJwtSession(test.req)
|
session, _ := test.proxy.GetJwtSession(test.req)
|
||||||
assert.Equal(t, session.User, "john@example.com")
|
assert.Equal(t, session.User, "1234567890")
|
||||||
assert.Equal(t, session.Email, "john@example.com")
|
assert.Equal(t, session.Email, "john@example.com")
|
||||||
assert.Equal(t, session.ExpiresOn, &expires)
|
assert.Equal(t, session.ExpiresOn, &expires)
|
||||||
assert.Equal(t, session.IDToken, goodJwt)
|
assert.Equal(t, session.IDToken, goodJwt)
|
||||||
@ -1590,12 +1590,12 @@ func TestGetJwtSession(t *testing.T) {
|
|||||||
|
|
||||||
// Check PassAuthorization, should overwrite Basic header
|
// Check PassAuthorization, should overwrite Basic header
|
||||||
assert.Equal(t, test.req.Header.Get("Authorization"), authHeader)
|
assert.Equal(t, test.req.Header.Get("Authorization"), authHeader)
|
||||||
assert.Equal(t, test.req.Header.Get("X-Forwarded-User"), "john@example.com")
|
assert.Equal(t, test.req.Header.Get("X-Forwarded-User"), "1234567890")
|
||||||
assert.Equal(t, test.req.Header.Get("X-Forwarded-Email"), "john@example.com")
|
assert.Equal(t, test.req.Header.Get("X-Forwarded-Email"), "john@example.com")
|
||||||
|
|
||||||
// SetAuthorization and SetXAuthRequest
|
// SetAuthorization and SetXAuthRequest
|
||||||
assert.Equal(t, test.rw.Header().Get("Authorization"), authHeader)
|
assert.Equal(t, test.rw.Header().Get("Authorization"), authHeader)
|
||||||
assert.Equal(t, test.rw.Header().Get("X-Auth-Request-User"), "john@example.com")
|
assert.Equal(t, test.rw.Header().Get("X-Auth-Request-User"), "1234567890")
|
||||||
assert.Equal(t, test.rw.Header().Get("X-Auth-Request-Email"), "john@example.com")
|
assert.Equal(t, test.rw.Header().Get("X-Auth-Request-Email"), "john@example.com")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,10 +178,6 @@ func Validate(o *options.Options) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if o.SkipJwtBearerTokens {
|
if o.SkipJwtBearerTokens {
|
||||||
// If we are using an oidc provider, go ahead and add that provider to the list
|
|
||||||
if o.GetOIDCVerifier() != nil {
|
|
||||||
o.SetJWTBearerVerifiers(append(o.GetJWTBearerVerifiers(), o.GetOIDCVerifier()))
|
|
||||||
}
|
|
||||||
// Configure extra issuers
|
// Configure extra issuers
|
||||||
if len(o.ExtraJwtIssuers) > 0 {
|
if len(o.ExtraJwtIssuers) > 0 {
|
||||||
var jwtIssuers []jwtIssuer
|
var jwtIssuers []jwtIssuer
|
||||||
|
@ -124,7 +124,6 @@ func newOIDCServer(body []byte) (*url.URL, *httptest.Server) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newSignedTestIDToken(tokenClaims idTokenClaims) (string, error) {
|
func newSignedTestIDToken(tokenClaims idTokenClaims) (string, error) {
|
||||||
|
|
||||||
key, _ := rsa.GenerateKey(rand.Reader, 2048)
|
key, _ := rsa.GenerateKey(rand.Reader, 2048)
|
||||||
standardClaims := jwt.NewWithClaims(jwt.SigningMethodRS256, tokenClaims)
|
standardClaims := jwt.NewWithClaims(jwt.SigningMethodRS256, tokenClaims)
|
||||||
return standardClaims.SignedString(key)
|
return standardClaims.SignedString(key)
|
||||||
|
@ -164,14 +164,13 @@ func (p *ProviderData) CreateSessionStateFromBearerToken(ctx context.Context, ra
|
|||||||
|
|
||||||
newSession := &sessions.SessionState{
|
newSession := &sessions.SessionState{
|
||||||
Email: claims.Email,
|
Email: claims.Email,
|
||||||
User: claims.Email,
|
User: claims.Subject,
|
||||||
PreferredUsername: claims.PreferredUsername,
|
PreferredUsername: claims.PreferredUsername,
|
||||||
|
AccessToken: rawIDToken,
|
||||||
|
IDToken: rawIDToken,
|
||||||
|
RefreshToken: "",
|
||||||
|
ExpiresOn: &idToken.Expiry,
|
||||||
}
|
}
|
||||||
|
|
||||||
newSession.AccessToken = rawIDToken
|
|
||||||
newSession.IDToken = rawIDToken
|
|
||||||
newSession.RefreshToken = ""
|
|
||||||
newSession.ExpiresOn = &idToken.Expiry
|
|
||||||
|
|
||||||
return newSession, nil
|
return newSession, nil
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,15 @@ package providers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/coreos/go-oidc"
|
||||||
|
"github.com/dgrijalva/jwt-go"
|
||||||
|
|
||||||
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/sessions"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
@ -47,3 +52,39 @@ func TestAcrValuesConfigured(t *testing.T) {
|
|||||||
result := p.GetLoginURL("https://my.test.app/oauth", "")
|
result := p.GetLoginURL("https://my.test.app/oauth", "")
|
||||||
assert.Contains(t, result, "acr_values=testValue")
|
assert.Contains(t, result, "acr_values=testValue")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCreateSessionStateFromBearerToken(t *testing.T) {
|
||||||
|
minimalIDToken := jwt.StandardClaims{
|
||||||
|
Audience: "asdf1234",
|
||||||
|
ExpiresAt: time.Now().Add(time.Duration(5) * time.Minute).Unix(),
|
||||||
|
Id: "id-some-id",
|
||||||
|
IssuedAt: time.Now().Unix(),
|
||||||
|
Issuer: "https://issuer.example.com",
|
||||||
|
NotBefore: 0,
|
||||||
|
Subject: "123456789",
|
||||||
|
}
|
||||||
|
// From oidc_test.go
|
||||||
|
verifier := oidc.NewVerifier(
|
||||||
|
"https://issuer.example.com",
|
||||||
|
fakeKeySetStub{},
|
||||||
|
&oidc.Config{ClientID: "asdf1234"},
|
||||||
|
)
|
||||||
|
|
||||||
|
key, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
rawIDToken, err := jwt.NewWithClaims(jwt.SigningMethodRS256, minimalIDToken).SignedString(key)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
// Pass to a dummy Verifier to get an oidc.IDToken from the rawIDToken for our actual test below
|
||||||
|
idToken, err := verifier.Verify(context.Background(), rawIDToken)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
session, err := (*ProviderData)(nil).CreateSessionStateFromBearerToken(context.Background(), rawIDToken, idToken)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, rawIDToken, session.AccessToken)
|
||||||
|
assert.Equal(t, rawIDToken, session.IDToken)
|
||||||
|
assert.Equal(t, "123456789", session.Email)
|
||||||
|
assert.Equal(t, "123456789", session.User)
|
||||||
|
assert.Empty(t, session.RefreshToken)
|
||||||
|
assert.Empty(t, session.PreferredUsername)
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user