diff --git a/pkg/authorization/resource.go b/pkg/authorization/resource.go index 40f21be5..c4d39198 100644 --- a/pkg/authorization/resource.go +++ b/pkg/authorization/resource.go @@ -33,6 +33,8 @@ type Resource struct { Methods []string `json:"methods" yaml:"methods"` // WhiteListed permits the prefix through WhiteListed bool `json:"white-listed" yaml:"white-listed"` + // NoRedirect overrides global no-redirect setting + NoRedirect bool // RequireAnyRole indicates that ANY of the roles are required, the default is all RequireAnyRole bool `json:"require-any-role" yaml:"require-any-role"` // Headers required to access this url @@ -116,6 +118,16 @@ func (r *Resource) Parse(resource string) (*Resource, error) { } r.WhiteListed = value + case "no-redirect": + value, err := strconv.ParseBool(keyPair[1]) + if err != nil { + return nil, errors.New( + "the value of no-redirect must be " + + "true|TRUE|T or it's false equivalent", + ) + } + + r.NoRedirect = value case "acr": r.Acr = strings.Split(keyPair[1], ",") default: diff --git a/pkg/keycloak/proxy/server.go b/pkg/keycloak/proxy/server.go index 29ce2e1a..acc695cf 100644 --- a/pkg/keycloak/proxy/server.go +++ b/pkg/keycloak/proxy/server.go @@ -345,18 +345,6 @@ func (r *OauthProxy) CreateReverseProxy() error { WithOAuthURI, ) - redToAuth := core.RedirectToAuthorization( - r.Log, - r.Config.NoRedirects, - r.Cm, - r.Config.SkipTokenVerification, - r.Config.NoProxy, - r.Config.BaseURI, - r.Config.OAuthURI, - r.Config.AllowedQueryParams, - r.Config.DefaultAllowedQueryParams, - ) - if r.Config.EnableHmac { engine.Use(gmiddleware.HmacMiddleware(r.Log, r.Config.EncryptionKey)) } @@ -438,7 +426,6 @@ func (r *OauthProxy) CreateReverseProxy() error { r.Config.EnableEncryptedToken, r.Config.ForceEncryptedCookie, r.Config.EncryptionKey, - redToAuth, newOAuth2Config, r.Store, r.Config.AccessTokenDuration, @@ -530,14 +517,33 @@ func (r *OauthProxy) CreateReverseProxy() error { r.Config.DefaultAllowedQueryParams, ) + redToAuthMiddleware := gmiddleware.NewRedirectToAuthorizationMiddleware( + r.Log, + r.Cm, + r.Config.SkipTokenVerification, + r.Config.NoProxy, + r.Config.BaseURI, + r.Config.OAuthURI, + r.Config.AllowedQueryParams, + r.Config.DefaultAllowedQueryParams, + ) + noredToAuthMiddleware := gmiddleware.NoRedirectToAuthorizationMiddleware(r.Log) + + var authFailMiddleware func(http.Handler) http.Handler + if r.Config.NoRedirects { + authFailMiddleware = noredToAuthMiddleware + } else { + authFailMiddleware = redToAuthMiddleware + } + // step: add the routing for oauth engine.With(gmiddleware.ProxyDenyMiddleware(r.Log)).Route(r.Config.BaseURI+r.Config.OAuthURI, func(eng chi.Router) { eng.MethodNotAllowed(handlers.MethodNotAllowHandlder) eng.HandleFunc(constant.AuthorizationURL, oauthAuthorizationHand) eng.Get(constant.CallbackURL, oauthCallbackHand) eng.Get(constant.ExpiredURL, handlers.ExpirationHandler(getIdentity, r.Config.CookieAccessName)) - eng.With(authMid).Get(constant.LogoutURL, logoutHand) - eng.With(authMid).Get( + eng.With(authMid, authFailMiddleware).Get(constant.LogoutURL, logoutHand) + eng.With(authMid, authFailMiddleware).Get( constant.TokenURL, handlers.TokenHandler(getIdentity, r.Config.CookieAccessName, accessError), ) @@ -644,47 +650,64 @@ func (r *OauthProxy) CreateReverseProxy() error { zap.String("resource", res.String()), ) + authFailMiddleware := redToAuthMiddleware + if res.NoRedirect || r.Config.NoRedirects { + authFailMiddleware = noredToAuthMiddleware + } + + admissionMiddleware := gmiddleware.AdmissionMiddleware( + r.Log, + res, + r.Config.MatchClaims, + accessForbidden, + ) + + identityMiddleware := gmiddleware.IdentityHeadersMiddleware( + r.Log, + r.Config.AddClaims, + r.Config.CookieAccessName, + r.Config.CookieRefreshName, + r.Config.NoProxy, + r.Config.EnableTokenHeader, + r.Config.EnableAuthorizationHeader, + r.Config.EnableAuthorizationCookies, + ) + middlewares := []func(http.Handler) http.Handler{ authMid, - gmiddleware.AdmissionMiddleware( + authFailMiddleware, + admissionMiddleware, + } + + if r.Config.EnableLoA && res.NoRedirect { + r.Log.Warn( + "disabling LoA for resource, no-redirect=true for resource", + zap.String("resource", res.URL)) + } + var loAMid func(http.Handler) http.Handler + if r.Config.EnableLoA && !res.NoRedirect { + loAMid = levelOfAuthenticationMiddleware( r.Log, + r.Config.SkipTokenVerification, + r.Config.Scopes, + r.Config.EnablePKCE, + r.Config.SignInPage, + r.Cm, + newOAuth2Config, + getRedirectionURL, + customSignInPage, res, - r.Config.MatchClaims, accessForbidden, - ), - } - - if r.Config.EnableLoA { + ) middlewares = append( middlewares, - levelOfAuthenticationMiddleware( - r.Log, - r.Config.SkipTokenVerification, - r.Config.Scopes, - r.Config.EnablePKCE, - r.Config.SignInPage, - r.Cm, - newOAuth2Config, - getRedirectionURL, - customSignInPage, - res, - accessForbidden, - ), + loAMid, ) } middlewares = append( middlewares, - gmiddleware.IdentityHeadersMiddleware( - r.Log, - r.Config.AddClaims, - r.Config.CookieAccessName, - r.Config.CookieRefreshName, - r.Config.NoProxy, - r.Config.EnableTokenHeader, - r.Config.EnableAuthorizationHeader, - r.Config.EnableAuthorizationCookies, - ), + identityMiddleware, ) if res.URL == constant.AllPath && !res.WhiteListed && enableDefaultDenyStrict { @@ -695,72 +718,57 @@ func (r *OauthProxy) CreateReverseProxy() error { } if r.Config.EnableUma || r.Config.EnableOpa { + enableUma := r.Config.EnableUma + if r.Config.EnableUma && res.NoRedirect { + enableUma = false + r.Log.Warn( + "disabling EnableUma for resource, no-redirect=true for resource", + zap.String("resource", res.URL)) + } + + authzMiddleware := authorizationMiddleware( + r.Log, + enableUma, + r.Config.EnableUmaMethodScope, + r.Config.CookieUMAName, + r.Config.NoProxy, + r.pat, + r.Provider, + r.IdpClient, + r.Config.OpenIDProviderTimeout, + r.Config.Realm, + r.Config.EnableEncryptedToken, + r.Config.ForceEncryptedCookie, + r.Config.EncryptionKey, + r.Cm, + r.Config.EnableOpa, + r.Config.OpaTimeout, + r.Config.OpaAuthzURL, + r.Config.DiscoveryURI, + r.Config.ClientID, + r.Config.SkipAccessTokenClientIDCheck, + r.Config.SkipAccessTokenIssuerCheck, + getIdentity, + accessForbidden, + ) + middlewares = []func(http.Handler) http.Handler{ authMid, - authorizationMiddleware( - r.Log, - r.Config.EnableUma, - r.Config.EnableUmaMethodScope, - r.Config.CookieUMAName, - r.Config.NoProxy, - r.pat, - r.Provider, - r.IdpClient, - r.Config.OpenIDProviderTimeout, - r.Config.Realm, - r.Config.EnableEncryptedToken, - r.Config.ForceEncryptedCookie, - r.Config.EncryptionKey, - r.Cm, - r.Config.EnableOpa, - r.Config.OpaTimeout, - r.Config.OpaAuthzURL, - r.Config.DiscoveryURI, - r.Config.ClientID, - r.Config.SkipAccessTokenClientIDCheck, - r.Config.SkipAccessTokenIssuerCheck, - getIdentity, - accessForbidden, - ), - gmiddleware.AdmissionMiddleware( - r.Log, - res, - r.Config.MatchClaims, - accessForbidden, - ), + authFailMiddleware, + authzMiddleware, + admissionMiddleware, } - if r.Config.EnableLoA { + if r.Config.EnableLoA && !res.NoRedirect { middlewares = append( middlewares, - levelOfAuthenticationMiddleware( - r.Log, - r.Config.SkipTokenVerification, - r.Config.Scopes, - r.Config.EnablePKCE, - r.Config.SignInPage, - r.Cm, - newOAuth2Config, - getRedirectionURL, - customSignInPage, - res, - accessForbidden, - ), + loAMid, ) } middlewares = append( middlewares, - gmiddleware.IdentityHeadersMiddleware( - r.Log, - r.Config.AddClaims, - r.Config.CookieAccessName, - r.Config.CookieRefreshName, - r.Config.NoProxy, - r.Config.EnableTokenHeader, - r.Config.EnableAuthorizationHeader, - r.Config.EnableAuthorizationCookies, - ), + identityMiddleware, ) } diff --git a/pkg/proxy/core/helpers.go b/pkg/proxy/core/helpers.go index bbef5dac..9776af67 100644 --- a/pkg/proxy/core/helpers.go +++ b/pkg/proxy/core/helpers.go @@ -2,15 +2,12 @@ package core import ( "context" - "fmt" "net/http" "github.com/gogatekeeper/gatekeeper/pkg/apperrors" "github.com/gogatekeeper/gatekeeper/pkg/constant" "github.com/gogatekeeper/gatekeeper/pkg/encryption" - "github.com/gogatekeeper/gatekeeper/pkg/proxy/cookie" "github.com/gogatekeeper/gatekeeper/pkg/proxy/models" - "github.com/gogatekeeper/gatekeeper/pkg/utils" "go.uber.org/zap" ) @@ -28,97 +25,7 @@ func RedirectToURL( ) http.Redirect(wrt, req, url, statusCode) - return revokeProxy(logger, req) -} - -// RedirectToAuthorization redirects the user to authorization handler -// -//nolint:cyclop -func RedirectToAuthorization( - logger *zap.Logger, - noRedirects bool, - cookManager *cookie.Manager, - skipTokenVerification bool, - noProxy bool, - baseURI string, - oAuthURI string, - allowedQueryParams map[string]string, - defaultAllowedQueryParams map[string]string, -) func(wrt http.ResponseWriter, req *http.Request) context.Context { - return func(wrt http.ResponseWriter, req *http.Request) context.Context { - if noRedirects { - wrt.WriteHeader(http.StatusUnauthorized) - return revokeProxy(logger, req) - } - - // step: add a state referrer to the authorization page - uuid := cookManager.DropStateParameterCookie(req, wrt) - authQuery := "?state=" + uuid - - if len(allowedQueryParams) > 0 { - query := "" - for key, val := range allowedQueryParams { - if param := req.URL.Query().Get(key); param != "" { - if val != "" { - if val != param { - wrt.WriteHeader(http.StatusForbidden) - return revokeProxy(logger, req) - } - } - query += fmt.Sprintf("&%s=%s", key, param) - } else { - if val, ok := defaultAllowedQueryParams[key]; ok { - query += fmt.Sprintf("&%s=%s", key, val) - } - } - } - authQuery += query - } - - // step: if verification is switched off, we can't authorization - if skipTokenVerification { - logger.Error( - "refusing to redirection to authorization endpoint, " + - "skip token verification switched on", - ) - - wrt.WriteHeader(http.StatusForbidden) - return revokeProxy(logger, req) - } - - url := utils.WithOAuthURI(baseURI, oAuthURI)(constant.AuthorizationURL + authQuery) - - if noProxy && !noRedirects { - xForwardedHost := req.Header.Get(constant.HeaderXForwardedHost) - xProto := req.Header.Get(constant.HeaderXForwardedProto) - - if xForwardedHost == "" || xProto == "" { - logger.Error(apperrors.ErrForwardAuthMissingHeaders.Error()) - - wrt.WriteHeader(http.StatusForbidden) - return revokeProxy(logger, req) - } - - url = fmt.Sprintf( - "%s://%s%s", - xProto, - xForwardedHost, - url, - ) - } - - logger.Debug("redirecting to url", zap.String("url", url)) - - RedirectToURL( - logger, - url, - wrt, - req, - http.StatusSeeOther, - ) - - return revokeProxy(logger, req) - } + return RevokeProxy(logger, req) } func EncryptToken( @@ -142,8 +49,8 @@ func EncryptToken( return encrypted, nil } -// revokeProxy is responsible for stopping middleware from proxying the request. -func revokeProxy(logger *zap.Logger, req *http.Request) context.Context { +// RevokeProxy is responsible for stopping middleware from proxying the request. +func RevokeProxy(logger *zap.Logger, req *http.Request) context.Context { var scope *models.RequestScope ctxVal := req.Context().Value(constant.ContextScopeName) diff --git a/pkg/proxy/core/template.go b/pkg/proxy/core/template.go index 034d32a4..5b7cb5f0 100644 --- a/pkg/proxy/core/template.go +++ b/pkg/proxy/core/template.go @@ -33,7 +33,7 @@ func AccessForbidden( } } - return revokeProxy(logger, req) + return RevokeProxy(logger, req) } } diff --git a/pkg/proxy/middleware/base.go b/pkg/proxy/middleware/base.go index 0ce23c4f..e72177f5 100644 --- a/pkg/proxy/middleware/base.go +++ b/pkg/proxy/middleware/base.go @@ -181,7 +181,7 @@ func ProxyDenyMiddleware(logger *zap.Logger) func(http.Handler) http.Handler { } } - scope.AccessDenied = true + scope.NoProxy = true // update the request context ctx := context.WithValue(req.Context(), constant.ContextScopeName, scope) @@ -311,7 +311,7 @@ func ProxyMiddleware( logger.Error(apperrors.ErrAssertionFailed.Error()) return } - if scope.AccessDenied { + if scope.AccessDenied || scope.NoProxy { return } } diff --git a/pkg/proxy/middleware/oauth.go b/pkg/proxy/middleware/oauth.go index f1858ae8..99f42de1 100644 --- a/pkg/proxy/middleware/oauth.go +++ b/pkg/proxy/middleware/oauth.go @@ -3,6 +3,7 @@ package middleware import ( "context" "errors" + "fmt" "net/http" "strings" "time" @@ -13,6 +14,7 @@ import ( "github.com/gogatekeeper/gatekeeper/pkg/constant" "github.com/gogatekeeper/gatekeeper/pkg/encryption" "github.com/gogatekeeper/gatekeeper/pkg/proxy/cookie" + "github.com/gogatekeeper/gatekeeper/pkg/proxy/core" "github.com/gogatekeeper/gatekeeper/pkg/proxy/models" "github.com/gogatekeeper/gatekeeper/pkg/proxy/session" "github.com/gogatekeeper/gatekeeper/pkg/storage" @@ -44,7 +46,6 @@ func AuthenticationMiddleware( enableEncryptedToken bool, forceEncryptedCookie bool, encryptionKey string, - redirectToAuthorization func(wrt http.ResponseWriter, req *http.Request) context.Context, newOAuth2Config func(redirectionURL string) *oauth2.Config, store storage.Storage, accessTokenDuration time.Duration, @@ -63,7 +64,8 @@ func AuthenticationMiddleware( user, err := getIdentity(req, cookieAccessName, "") if err != nil { scope.Logger.Error(err.Error()) - redirectToAuthorization(wrt, req) + core.RevokeProxy(logger, req) + next.ServeHTTP(wrt, req) return } @@ -91,7 +93,8 @@ func AuthenticationMiddleware( if user.IsExpired() { lLog.Error(apperrors.ErrSessionExpiredVerifyOff.Error()) - redirectToAuthorization(wrt, req) + core.RevokeProxy(logger, req) + next.ServeHTTP(wrt, req) return } } else { @@ -124,7 +127,8 @@ func AuthenticationMiddleware( if !enableRefreshTokens { lLog.Error(apperrors.ErrSessionExpiredRefreshOff.Error()) - redirectToAuthorization(wrt, req) + core.RevokeProxy(logger, req) + next.ServeHTTP(wrt, req) return } @@ -143,7 +147,8 @@ func AuthenticationMiddleware( apperrors.ErrRefreshTokenNotFound.Error(), zap.Error(err), ) - redirectToAuthorization(wrt, req) + core.RevokeProxy(logger, req) + next.ServeHTTP(wrt, req) return } @@ -199,7 +204,8 @@ func AuthenticationMiddleware( ) } - redirectToAuthorization(wrt, req) + core.RevokeProxy(logger, req) + next.ServeHTTP(wrt, req) return } @@ -306,7 +312,8 @@ func AuthenticationMiddleware( _, err := provider.UserInfo(oidcLibCtx, tokenSource) if err != nil { scope.Logger.Error(err.Error()) - redirectToAuthorization(wrt, req) + core.RevokeProxy(logger, req) + next.ServeHTTP(wrt, req) return } } @@ -316,3 +323,222 @@ func AuthenticationMiddleware( }) } } + +// RedirectToAuthorizationMiddleware redirects the user to authorization handler +// +//nolint:cyclop +func RedirectToAuthorizationMiddleware( + logger *zap.Logger, + noRedirects bool, + cookManager *cookie.Manager, + skipTokenVerification bool, + noProxy bool, + baseURI string, + oAuthURI string, + allowedQueryParams map[string]string, + defaultAllowedQueryParams map[string]string, +) func(http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(wrt http.ResponseWriter, req *http.Request) { + scope, assertOk := req.Context().Value(constant.ContextScopeName).(*models.RequestScope) + if !assertOk { + logger.Error(apperrors.ErrAssertionFailed.Error()) + return + } + + scope.Logger.Debug("redirecttoauthorization middleware") + + if scope.AccessDenied { + if noRedirects { + wrt.WriteHeader(http.StatusUnauthorized) + return + } + + // step: add a state referrer to the authorization page + uuid := cookManager.DropStateParameterCookie(req, wrt) + authQuery := "?state=" + uuid + + if len(allowedQueryParams) > 0 { + query := "" + for key, val := range allowedQueryParams { + if param := req.URL.Query().Get(key); param != "" { + if val != "" { + if val != param { + wrt.WriteHeader(http.StatusForbidden) + } + } + query += fmt.Sprintf("&%s=%s", key, param) + } else { + if val, ok := defaultAllowedQueryParams[key]; ok { + query += fmt.Sprintf("&%s=%s", key, val) + } + } + } + authQuery += query + } + + // step: if verification is switched off, we can't authorization + if skipTokenVerification { + logger.Error( + "refusing to redirection to authorization endpoint, " + + "skip token verification switched on", + ) + + wrt.WriteHeader(http.StatusForbidden) + return + } + + url := utils.WithOAuthURI(baseURI, oAuthURI)(constant.AuthorizationURL + authQuery) + + if noProxy && !noRedirects { + xForwardedHost := req.Header.Get(constant.HeaderXForwardedHost) + xProto := req.Header.Get(constant.HeaderXForwardedProto) + + if xForwardedHost == "" || xProto == "" { + logger.Error(apperrors.ErrForwardAuthMissingHeaders.Error()) + + wrt.WriteHeader(http.StatusForbidden) + return + } + + url = fmt.Sprintf( + "%s://%s%s", + xProto, + xForwardedHost, + url, + ) + } + + logger.Debug("redirecting to url", zap.String("url", url)) + + core.RedirectToURL( + logger, + url, + wrt, + req, + http.StatusSeeOther, + ) + } else { + next.ServeHTTP(wrt, req) + } + }) + } +} + +// RedirectToAuthorizationMiddleware redirects the user to authorization handler +// +//nolint:cyclop +func NewRedirectToAuthorizationMiddleware( + logger *zap.Logger, + cookManager *cookie.Manager, + skipTokenVerification bool, + noProxy bool, + baseURI string, + oAuthURI string, + allowedQueryParams map[string]string, + defaultAllowedQueryParams map[string]string, +) func(http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(wrt http.ResponseWriter, req *http.Request) { + scope, assertOk := req.Context().Value(constant.ContextScopeName).(*models.RequestScope) + if !assertOk { + logger.Error(apperrors.ErrAssertionFailed.Error()) + return + } + + scope.Logger.Debug("redirecttoauthorization middleware") + + if scope.AccessDenied { + // step: add a state referrer to the authorization page + uuid := cookManager.DropStateParameterCookie(req, wrt) + authQuery := "?state=" + uuid + + if len(allowedQueryParams) > 0 { + query := "" + for key, val := range allowedQueryParams { + if param := req.URL.Query().Get(key); param != "" { + if val != "" { + if val != param { + wrt.WriteHeader(http.StatusForbidden) + } + } + query += fmt.Sprintf("&%s=%s", key, param) + } else { + if val, ok := defaultAllowedQueryParams[key]; ok { + query += fmt.Sprintf("&%s=%s", key, val) + } + } + } + authQuery += query + } + + // step: if verification is switched off, we can't authorization + if skipTokenVerification { + logger.Error( + "refusing to redirection to authorization endpoint, " + + "skip token verification switched on", + ) + + wrt.WriteHeader(http.StatusForbidden) + return + } + + url := utils.WithOAuthURI(baseURI, oAuthURI)(constant.AuthorizationURL + authQuery) + + if noProxy { + xForwardedHost := req.Header.Get(constant.HeaderXForwardedHost) + xProto := req.Header.Get(constant.HeaderXForwardedProto) + + if xForwardedHost == "" || xProto == "" { + logger.Error(apperrors.ErrForwardAuthMissingHeaders.Error()) + + wrt.WriteHeader(http.StatusForbidden) + return + } + + url = fmt.Sprintf( + "%s://%s%s", + xProto, + xForwardedHost, + url, + ) + } + + logger.Debug("redirecting to url", zap.String("url", url)) + + core.RedirectToURL( + logger, + url, + wrt, + req, + http.StatusSeeOther, + ) + } else { + next.ServeHTTP(wrt, req) + } + }) + } +} + +// NoRedirectToAuthorizationMiddleware stops request after faild authentication, in no-redirects=true mode. +func NoRedirectToAuthorizationMiddleware( + logger *zap.Logger, +) func(http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(wrt http.ResponseWriter, req *http.Request) { + scope, assertOk := req.Context().Value(constant.ContextScopeName).(*models.RequestScope) + if !assertOk { + logger.Error(apperrors.ErrAssertionFailed.Error()) + return + } + + scope.Logger.Debug("noredirecttoauthorization middleware") + + if scope.AccessDenied { + wrt.WriteHeader(http.StatusUnauthorized) + return + } + next.ServeHTTP(wrt, req) + }) + } +} diff --git a/pkg/proxy/models/models.go b/pkg/proxy/models/models.go index c6be8ede..ce299c0f 100644 --- a/pkg/proxy/models/models.go +++ b/pkg/proxy/models/models.go @@ -4,8 +4,10 @@ import "go.uber.org/zap" // RequestScope is a request level context scope passed between middleware. type RequestScope struct { - // AccessDenied indicates the request should not be proxied on + // AccessDenied indicates the request should not be proxied because of authentication failure/other failure AccessDenied bool + // NoProxy indicates that request should not be proxied because it is endpoint which should not be proxied + NoProxy bool // Identity is the user Identity of the request Identity *UserContext // The parsed (unescaped) value of the request path diff --git a/pkg/testsuite/handlers_test.go b/pkg/testsuite/handlers_test.go index 984f0102..b42111d9 100644 --- a/pkg/testsuite/handlers_test.go +++ b/pkg/testsuite/handlers_test.go @@ -842,6 +842,21 @@ func TestServiceRedirect(t *testing.T) { Name: "TestRedirects", ProxySettings: func(conf *config.Config) { conf.NoRedirects = false + conf.Resources = []*authorization.Resource{ + { + URL: FakeAdminURL, + WhiteListed: false, + Methods: utils.AllHTTPMethods, + Roles: []string{}, + }, + { + URL: FakeTestURL, + NoRedirect: true, + WhiteListed: false, + Methods: utils.AllHTTPMethods, + Roles: []string{}, + }, + } }, ExecutionSettings: []fakeRequest{ { @@ -850,18 +865,42 @@ func TestServiceRedirect(t *testing.T) { ExpectedCode: http.StatusSeeOther, ExpectedLocation: "/oauth/authorize?state", }, + { + URI: FakeTestURL, + Redirects: false, + ExpectedCode: http.StatusUnauthorized, + }, }, }, { Name: "TestNoRedirects", ProxySettings: func(conf *config.Config) { conf.NoRedirects = true + conf.Resources = []*authorization.Resource{ + { + URL: FakeAdminURL, + WhiteListed: false, + Methods: utils.AllHTTPMethods, + Roles: []string{}, + }, + { + URL: FakeTestURL, + NoRedirect: false, + WhiteListed: false, + Methods: utils.AllHTTPMethods, + Roles: []string{}, + }, + } }, ExecutionSettings: []fakeRequest{ { URI: FakeAdminURL, ExpectedCode: http.StatusUnauthorized, }, + { + URI: FakeTestURL, + ExpectedCode: http.StatusUnauthorized, + }, }, }, } diff --git a/pkg/testsuite/middleware_test.go b/pkg/testsuite/middleware_test.go index 60e413b3..141ecb6b 100644 --- a/pkg/testsuite/middleware_test.go +++ b/pkg/testsuite/middleware_test.go @@ -2344,6 +2344,37 @@ func TestEnableUma(t *testing.T) { }, AuthServerSettings: &fakeAuthConfig{}, }, + { + Name: "TestUmaDisabledWhenPerResourceNoRedirect", + ProxySettings: func(conf *config.Config) { + conf.EnableUma = true + conf.EnableDefaultDeny = true + conf.ClientID = ValidUsername + conf.ClientSecret = ValidPassword + conf.PatRetryCount = 5 + conf.PatRetryInterval = 2 * time.Second + conf.Resources = []*authorization.Resource{ + { + URL: FakeTestURL, + Methods: utils.AllHTTPMethods, + NoRedirect: true, + }, + } + }, + ExecutionSettings: []fakeRequest{ + { + URI: FakeTestURL, + ExpectedProxy: false, + ExpectedCode: http.StatusUnauthorized, + ExpectedContent: func(body string, _ int) { + assert.Contains(t, body, "") + }, + }, + }, + AuthServerSettings: &fakeAuthConfig{ + ResourceSetHandlerFailure: true, + }, + }, { Name: "TestUmaTokenWithoutAuthzWithNoResourcesInAuthServer", ProxySettings: func(conf *config.Config) {