mirror of
https://github.com/pomerium/pomerium.git
synced 2025-08-03 16:59:22 +02:00
authorize: strip port from host header if necessary (#1175)
After #1153, envoy can handle routes for `example.com` and `example.com:443`. Authorize service should be updated to handle this case, too. Fixes #959
This commit is contained in:
parent
bc61206b78
commit
f7ebf54305
4 changed files with 81 additions and 25 deletions
|
@ -301,7 +301,7 @@ func getCheckRequestURL(req *envoy_service_auth_v2.CheckRequest) *url.URL {
|
|||
Scheme: h.GetScheme(),
|
||||
Host: h.GetHost(),
|
||||
}
|
||||
|
||||
u.Host = urlutil.GetDomainsForURL(u)[0]
|
||||
// envoy sends the query string as part of the path
|
||||
path := h.GetPath()
|
||||
if idx := strings.Index(path, "?"); idx != -1 {
|
||||
|
|
|
@ -267,6 +267,56 @@ func Test_handleForwardAuth(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func Test_getEvaluatorRequestWithPortInHostHeader(t *testing.T) {
|
||||
a := new(Authorize)
|
||||
encoder, _ := jws.NewHS256Signer([]byte{0, 0, 0, 0}, "")
|
||||
a.currentEncoder.Store(encoder)
|
||||
a.currentOptions.Store(&config.Options{
|
||||
Policies: []config.Policy{{
|
||||
Source: &config.StringURL{URL: &url.URL{Host: "example.com"}},
|
||||
SubPolicies: []config.SubPolicy{{
|
||||
Rego: []string{"allow = true"},
|
||||
}},
|
||||
}},
|
||||
})
|
||||
|
||||
actual := a.getEvaluatorRequestFromCheckRequest(&envoy_service_auth_v2.CheckRequest{
|
||||
Attributes: &envoy_service_auth_v2.AttributeContext{
|
||||
Source: &envoy_service_auth_v2.AttributeContext_Peer{
|
||||
Certificate: url.QueryEscape(certPEM),
|
||||
},
|
||||
Request: &envoy_service_auth_v2.AttributeContext_Request{
|
||||
Http: &envoy_service_auth_v2.AttributeContext_HttpRequest{
|
||||
Id: "id-1234",
|
||||
Method: "GET",
|
||||
Headers: map[string]string{
|
||||
"accept": "text/html",
|
||||
"x-forwarded-proto": "https",
|
||||
},
|
||||
Path: "/some/path?qs=1",
|
||||
Host: "example.com:80",
|
||||
Scheme: "http",
|
||||
Body: "BODY",
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil)
|
||||
expect := &evaluator.Request{
|
||||
Session: evaluator.RequestSession{},
|
||||
HTTP: evaluator.RequestHTTP{
|
||||
Method: "GET",
|
||||
URL: "https://example.com/some/path?qs=1",
|
||||
Headers: map[string]string{
|
||||
"Accept": "text/html",
|
||||
"X-Forwarded-Proto": "https",
|
||||
},
|
||||
ClientCertificate: certPEM,
|
||||
},
|
||||
CustomPolicies: []string{"allow = true"},
|
||||
}
|
||||
assert.Equal(t, expect, actual)
|
||||
}
|
||||
|
||||
func mustParseURL(str string) *url.URL {
|
||||
u, err := url.Parse(str)
|
||||
if err != nil {
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
|
||||
"github.com/pomerium/pomerium/config"
|
||||
"github.com/pomerium/pomerium/internal/log"
|
||||
"github.com/pomerium/pomerium/internal/urlutil"
|
||||
"github.com/pomerium/pomerium/pkg/cryptutil"
|
||||
)
|
||||
|
||||
|
@ -398,28 +399,28 @@ func buildDownstreamTLSContext(options *config.Options, domain string) *envoy_ex
|
|||
func getAllRouteableDomains(options *config.Options, addr string) []string {
|
||||
lookup := map[string]struct{}{}
|
||||
if config.IsAuthenticate(options.Services) && addr == options.Addr {
|
||||
for _, h := range getDomainsForURL(options.GetAuthenticateURL()) {
|
||||
for _, h := range urlutil.GetDomainsForURL(options.GetAuthenticateURL()) {
|
||||
lookup[h] = struct{}{}
|
||||
}
|
||||
}
|
||||
if config.IsAuthorize(options.Services) && addr == options.GRPCAddr {
|
||||
for _, h := range getDomainsForURL(options.GetAuthorizeURL()) {
|
||||
for _, h := range urlutil.GetDomainsForURL(options.GetAuthorizeURL()) {
|
||||
lookup[h] = struct{}{}
|
||||
}
|
||||
}
|
||||
if config.IsCache(options.Services) && addr == options.GRPCAddr {
|
||||
for _, h := range getDomainsForURL(options.GetDataBrokerURL()) {
|
||||
for _, h := range urlutil.GetDomainsForURL(options.GetDataBrokerURL()) {
|
||||
lookup[h] = struct{}{}
|
||||
}
|
||||
}
|
||||
if config.IsProxy(options.Services) && addr == options.Addr {
|
||||
for _, policy := range options.Policies {
|
||||
for _, h := range getDomainsForURL(policy.Source.URL) {
|
||||
for _, h := range urlutil.GetDomainsForURL(policy.Source.URL) {
|
||||
lookup[h] = struct{}{}
|
||||
}
|
||||
}
|
||||
if options.ForwardAuthURL != nil {
|
||||
for _, h := range getDomainsForURL(options.GetForwardAuthURL()) {
|
||||
for _, h := range urlutil.GetDomainsForURL(options.GetForwardAuthURL()) {
|
||||
lookup[h] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
@ -434,25 +435,6 @@ func getAllRouteableDomains(options *config.Options, addr string) []string {
|
|||
return domains
|
||||
}
|
||||
|
||||
func getDomainsForURL(u *url.URL) []string {
|
||||
var defaultPort string
|
||||
if u.Scheme == "http" {
|
||||
defaultPort = "80"
|
||||
} else {
|
||||
defaultPort = "443"
|
||||
}
|
||||
|
||||
// for hosts like 'example.com:1234' we only return one route
|
||||
if _, p, err := net.SplitHostPort(u.Host); err == nil {
|
||||
if p != defaultPort {
|
||||
return []string{u.Host}
|
||||
}
|
||||
}
|
||||
|
||||
// for everything else we return two routes: 'example.com' and 'example.com:443'
|
||||
return []string{u.Hostname(), net.JoinHostPort(u.Hostname(), defaultPort)}
|
||||
}
|
||||
|
||||
func hostMatchesDomain(u *url.URL, host string) bool {
|
||||
var defaultPort string
|
||||
if u.Scheme == "http" {
|
||||
|
|
|
@ -3,6 +3,7 @@ package urlutil
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
@ -77,3 +78,26 @@ func GetAbsoluteURL(r *http.Request) *url.URL {
|
|||
u.Host = r.Host
|
||||
return u
|
||||
}
|
||||
|
||||
// GetDomainsForURL returns the available domains for given url.
|
||||
//
|
||||
// For standard HTTP (80)/HTTPS (443) ports, it returns `example.com` and `example.com:<port>`.
|
||||
// Otherwise, return the URL.Host value.
|
||||
func GetDomainsForURL(u *url.URL) []string {
|
||||
var defaultPort string
|
||||
if u.Scheme == "http" {
|
||||
defaultPort = "80"
|
||||
} else {
|
||||
defaultPort = "443"
|
||||
}
|
||||
|
||||
// for hosts like 'example.com:1234' we only return one route
|
||||
if _, p, err := net.SplitHostPort(u.Host); err == nil {
|
||||
if p != defaultPort {
|
||||
return []string{u.Host}
|
||||
}
|
||||
}
|
||||
|
||||
// for everything else we return two routes: 'example.com' and 'example.com:443'
|
||||
return []string{u.Hostname(), net.JoinHostPort(u.Hostname(), defaultPort)}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue