mirror of
https://github.com/pomerium/pomerium.git
synced 2025-06-24 13:38:17 +02:00
authorize: add authorization (#59)
* authorize: authorization module adds support for per-route access policy. In this release we support the most common forms of identity based access policy: `allowed_users`, `allowed_groups`, and `allowed_domains`. In future versions, the authorization module will also support context and device based authorization policy and decisions. See website documentation for more details. * docs: updated `env.example` to include a `POLICY` setting example. * docs: added `IDP_SERVICE_ACCOUNT` to `env.example` . * docs: removed `PROXY_ROOT_DOMAIN` settings which has been replaced by `POLICY`. * all: removed `ALLOWED_DOMAINS` settings which has been replaced by `POLICY`. Authorization is now handled by the authorization service and is defined in the policy configuration files. * proxy: `ROUTES` settings which has been replaced by `POLICY`. * internal/log: `http.Server` and `httputil.NewSingleHostReverseProxy` now uses pomerium's logging package instead of the standard library's built in one. Closes #54 Closes #41 Closes #61 Closes #58
This commit is contained in:
parent
1187be2bf3
commit
c13459bb88
65 changed files with 1683 additions and 879 deletions
|
@ -1,6 +1,7 @@
|
|||
package proxy // import "github.com/pomerium/pomerium/proxy"
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
|
@ -10,6 +11,8 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pomerium/pomerium/internal/policy"
|
||||
)
|
||||
|
||||
var fixedDate = time.Date(2009, 11, 17, 20, 34, 58, 651387237, time.UTC)
|
||||
|
@ -47,36 +50,9 @@ func TestOptionsFromEnvConfig(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func Test_urlParse(t *testing.T) {
|
||||
os.Clearenv()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
uri string
|
||||
want *url.URL
|
||||
wantErr bool
|
||||
}{
|
||||
{"good url without schema", "accounts.google.com", &url.URL{Scheme: "https", Host: "accounts.google.com"}, false},
|
||||
{"good url with schema", "https://accounts.google.com", &url.URL{Scheme: "https", Host: "accounts.google.com"}, false},
|
||||
{"bad url, malformed", "https://accounts.google.^", nil, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := urlParse(tt.uri)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("urlParse() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("urlParse() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewReverseProxy(t *testing.T) {
|
||||
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(200)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
hostname, _, _ := net.SplitHostPort(r.Host)
|
||||
w.Write([]byte(hostname))
|
||||
}))
|
||||
|
@ -101,7 +77,7 @@ func TestNewReverseProxy(t *testing.T) {
|
|||
|
||||
func TestNewReverseProxyHandler(t *testing.T) {
|
||||
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(200)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
hostname, _, _ := net.SplitHostPort(r.Host)
|
||||
w.Write([]byte(hostname))
|
||||
}))
|
||||
|
@ -111,10 +87,14 @@ func TestNewReverseProxyHandler(t *testing.T) {
|
|||
backendHostname, backendPort, _ := net.SplitHostPort(backendURL.Host)
|
||||
backendHost := net.JoinHostPort(backendHostname, backendPort)
|
||||
proxyURL, _ := url.Parse(backendURL.Scheme + "://" + backendHost + "/")
|
||||
|
||||
proxyHandler := NewReverseProxy(proxyURL)
|
||||
opts := defaultOptions
|
||||
handle, err := NewReverseProxyHandler(opts, proxyHandler, "from", "to")
|
||||
opts.SigningKey = "LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU0zbXBaSVdYQ1g5eUVneFU2czU3Q2J0YlVOREJTQ0VBdFFGNWZVV0hwY1FvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFaFBRditMQUNQVk5tQlRLMHhTVHpicEVQa1JyazFlVXQxQk9hMzJTRWZVUHpOaTRJV2VaLwpLS0lUdDJxMUlxcFYyS01TYlZEeXI5aWp2L1hoOThpeUV3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo="
|
||||
route, err := policy.FromConfig([]byte(`[{"from":"corp.example.com","to":"example.com","timeout":"1s"}]`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
handle, err := NewReverseProxyHandler(opts, proxyHandler, &route[0])
|
||||
if err != nil {
|
||||
t.Errorf("got %q", err)
|
||||
}
|
||||
|
@ -133,10 +113,14 @@ func TestNewReverseProxyHandler(t *testing.T) {
|
|||
}
|
||||
|
||||
func testOptions() *Options {
|
||||
authurl, _ := url.Parse("https://sso-auth.corp.beyondperimeter.com")
|
||||
authenticateService, _ := url.Parse("https://authenticate.corp.beyondperimeter.com")
|
||||
authorizeService, _ := url.Parse("https://authorize.corp.beyondperimeter.com")
|
||||
configBlob := `[{"from":"corp.example.com","to":"example.com"}]` //valid yaml
|
||||
policy := base64.URLEncoding.EncodeToString([]byte(configBlob))
|
||||
return &Options{
|
||||
Routes: map[string]string{"corp.example.com": "example.com"},
|
||||
AuthenticateURL: authurl,
|
||||
Policy: policy,
|
||||
AuthenticateURL: authenticateService,
|
||||
AuthorizeURL: authorizeService,
|
||||
SharedKey: "80ldlrU2d7w+wVpKNfevk6fmb8otEx6CqOfshj2LwhQ=",
|
||||
CookieSecret: "OromP1gurwGWjQPYb1nNgSxtbVB5NnLzX6z5WOKr0Yw=",
|
||||
CookieName: "pomerium",
|
||||
|
@ -151,7 +135,7 @@ func TestOptions_Validate(t *testing.T) {
|
|||
badToRoute.Routes = map[string]string{"^": "example.com"}
|
||||
badAuthURL := testOptions()
|
||||
badAuthURL.AuthenticateURL = nil
|
||||
authurl, _ := url.Parse("http://sso-auth.corp.beyondperimeter.com")
|
||||
authurl, _ := url.Parse("http://authenticate.corp.beyondperimeter.com")
|
||||
httpAuthURL := testOptions()
|
||||
httpAuthURL.AuthenticateURL = authurl
|
||||
emptyCookieSecret := testOptions()
|
||||
|
@ -193,6 +177,7 @@ func TestOptions_Validate(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
|
||||
good := testOptions()
|
||||
shortCookieLength := testOptions()
|
||||
shortCookieLength.CookieSecret = "gN3xnvfsAwfCXxnJorGLKUG4l2wC8sS8nfLMhcStPg=="
|
||||
|
@ -207,7 +192,7 @@ func TestNew(t *testing.T) {
|
|||
numMuxes int
|
||||
wantErr bool
|
||||
}{
|
||||
{"good - minimum options", good, nil, true, 1, false},
|
||||
{"good", good, nil, true, 1, false},
|
||||
{"empty options", &Options{}, nil, false, 0, true},
|
||||
{"nil options", nil, nil, false, 0, true},
|
||||
{"short secret/validate sanity check", shortCookieLength, nil, false, 0, true},
|
||||
|
@ -224,7 +209,7 @@ func TestNew(t *testing.T) {
|
|||
t.Errorf("New() expected valid proxy struct")
|
||||
}
|
||||
if got != nil && len(got.mux) != tt.numMuxes {
|
||||
t.Errorf("New() = num muxes %v, want %v", got, tt.numMuxes)
|
||||
t.Errorf("New() = num muxes \n%+v, want \n%+v", got, tt.numMuxes)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue