authorize: only redirect for HTML pages (#2264) (#2298)

* authorize: only redirect for HTML pages

* authorize: only redirect for HTML pages
This commit is contained in:
Caleb Doxsey 2021-06-16 12:15:30 -06:00 committed by GitHub
parent 45a9a1843c
commit 88e1458404
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 74 additions and 2 deletions

View file

@ -13,6 +13,7 @@ import (
envoy_service_auth_v3 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3"
envoy_type_v3 "github.com/envoyproxy/go-control-plane/envoy/type/v3"
"github.com/golang/protobuf/ptypes/wrappers"
"github.com/tniswong/go.rfcx/rfc7231"
"google.golang.org/genproto/googleapis/rpc/status"
"google.golang.org/grpc/codes"
@ -104,7 +105,7 @@ func (a *Authorize) deniedResponse(
}, nil
}
func (a *Authorize) redirectResponse(ctx context.Context, in *envoy_service_auth_v3.CheckRequest) (*envoy_service_auth_v3.CheckResponse, error) {
func (a *Authorize) requireLoginResponse(ctx context.Context, in *envoy_service_auth_v3.CheckRequest) (*envoy_service_auth_v3.CheckResponse, error) {
opts := a.currentOptions.Load()
state := a.state.Load()
authenticateURL, err := opts.GetAuthenticateURL()
@ -112,6 +113,10 @@ func (a *Authorize) redirectResponse(ctx context.Context, in *envoy_service_auth
return nil, err
}
if !shouldRedirect(in) {
return a.deniedResponse(ctx, in, http.StatusUnauthorized, http.StatusText(http.StatusUnauthorized), nil)
}
signinURL := authenticateURL.ResolveReference(&url.URL{
Path: "/.pomerium/sign_in",
})
@ -180,3 +185,22 @@ func (a *Authorize) userInfoEndpointURL(in *envoy_service_auth_v3.CheckRequest)
return urlutil.NewSignedURL(a.state.Load().sharedKey, debugEndpoint).Sign(), nil
}
func shouldRedirect(in *envoy_service_auth_v3.CheckRequest) bool {
requestHeaders := in.GetAttributes().GetRequest().GetHttp().GetHeaders()
if requestHeaders == nil {
return true
}
a, err := rfc7231.ParseAccept(requestHeaders["accept"])
if err != nil {
return true
}
mediaType, ok := a.MostAcceptable([]string{"text/html", "application/json", "text/plain"})
if !ok {
return true
}
return mediaType == "text/html"
}

View file

@ -179,3 +179,48 @@ func mustParseWeightedURLs(t *testing.T, urls ...string) []config.WeightedURL {
require.NoError(t, err)
return wu
}
func TestRequireLogin(t *testing.T) {
opt := config.NewDefaultOptions()
opt.AuthenticateURLString = "https://authenticate.example.com"
opt.DataBrokerURLString = "https://databroker.example.com"
opt.SharedKey = "E8wWIMnihUx+AUfRegAQDNs8eRb3UrB5G3zlJW9XJDM="
a, err := New(&config.Config{Options: opt})
require.NoError(t, err)
t.Run("accept empty", func(t *testing.T) {
res, err := a.requireLoginResponse(context.Background(), &envoy_service_auth_v3.CheckRequest{})
require.NoError(t, err)
assert.Equal(t, http.StatusFound, int(res.GetDeniedResponse().GetStatus().GetCode()))
})
t.Run("accept html", func(t *testing.T) {
res, err := a.requireLoginResponse(context.Background(), &envoy_service_auth_v3.CheckRequest{
Attributes: &envoy_service_auth_v3.AttributeContext{
Request: &envoy_service_auth_v3.AttributeContext_Request{
Http: &envoy_service_auth_v3.AttributeContext_HttpRequest{
Headers: map[string]string{
"accept": "*/*",
},
},
},
},
})
require.NoError(t, err)
assert.Equal(t, http.StatusFound, int(res.GetDeniedResponse().GetStatus().GetCode()))
})
t.Run("accept json", func(t *testing.T) {
res, err := a.requireLoginResponse(context.Background(), &envoy_service_auth_v3.CheckRequest{
Attributes: &envoy_service_auth_v3.AttributeContext{
Request: &envoy_service_auth_v3.AttributeContext_Request{
Http: &envoy_service_auth_v3.AttributeContext_HttpRequest{
Headers: map[string]string{
"accept": "application/json",
},
},
},
},
})
require.NoError(t, err)
assert.Equal(t, http.StatusUnauthorized, int(res.GetDeniedResponse().GetStatus().GetCode()))
})
}

View file

@ -75,7 +75,7 @@ func (a *Authorize) Check(ctx context.Context, in *envoy_service_auth_v3.CheckRe
if isForwardAuth && hreq.URL.Path == "/verify" {
return a.deniedResponse(ctx, in, http.StatusUnauthorized, "Unauthenticated", nil)
}
return a.redirectResponse(ctx, in)
return a.requireLoginResponse(ctx, in)
}
return a.deniedResponse(ctx, in, int32(reply.Status), reply.Message, nil)
}

1
go.mod
View file

@ -57,6 +57,7 @@ require (
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/viper v1.7.1
github.com/stretchr/testify v1.7.0
github.com/tniswong/go.rfcx v0.0.0-20181019234604-07783c52761f
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
github.com/yuin/gopher-lua v0.0.0-20200816102855-ee81675732da
go.opencensus.io v0.23.0

2
go.sum
View file

@ -622,6 +622,8 @@ github.com/tinylib/msgp v1.1.2 h1:gWmO7n0Ys2RBEb7GPYB9Ujq8Mk5p2U08lRnmMcGy6BQ=
github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tniswong/go.rfcx v0.0.0-20181019234604-07783c52761f h1:C43EMGXFtvYf/zunHR6ivZV7Z6ytg73t0GXwYyicXMQ=
github.com/tniswong/go.rfcx v0.0.0-20181019234604-07783c52761f/go.mod h1:N+sR0vLSCTtI6o06PMWsjMB4TVqqDttKNq4iC9wvxVY=
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y=
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE=
github.com/uber/jaeger-client-go v2.25.0+incompatible h1:IxcNZ7WRY1Y3G4poYlx24szfsn/3LvK9QHCq9oQw8+U=