mirror of
https://github.com/pomerium/pomerium.git
synced 2025-08-06 10:21:05 +02:00
authorize: add authN validation, additional tests (#761)
Signed-off-by: Bobby DeSimone <bobbydesimone@gmail.com>
This commit is contained in:
parent
9d7ef85687
commit
829280c73c
3 changed files with 160 additions and 3 deletions
|
@ -22,6 +22,7 @@ import (
|
||||||
"github.com/pomerium/pomerium/internal/log"
|
"github.com/pomerium/pomerium/internal/log"
|
||||||
"github.com/pomerium/pomerium/internal/telemetry/metrics"
|
"github.com/pomerium/pomerium/internal/telemetry/metrics"
|
||||||
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
"github.com/pomerium/pomerium/internal/telemetry/trace"
|
||||||
|
"github.com/pomerium/pomerium/internal/urlutil"
|
||||||
|
|
||||||
"gopkg.in/square/go-jose.v2"
|
"gopkg.in/square/go-jose.v2"
|
||||||
)
|
)
|
||||||
|
@ -90,6 +91,9 @@ func validateOptions(o config.Options) error {
|
||||||
if _, err := cryptutil.NewAEADCipherFromBase64(o.SharedKey); err != nil {
|
if _, err := cryptutil.NewAEADCipherFromBase64(o.SharedKey); err != nil {
|
||||||
return fmt.Errorf("bad shared_secret: %w", err)
|
return fmt.Errorf("bad shared_secret: %w", err)
|
||||||
}
|
}
|
||||||
|
if err := urlutil.ValidateURL(o.AuthenticateURL); err != nil {
|
||||||
|
return fmt.Errorf("invalid 'AUTHENTICATE_SERVICE_URL': %w", err)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,10 @@ func TestNew(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
o := config.Options{SharedKey: tt.SharedKey, Policies: tt.Policies}
|
o := config.Options{
|
||||||
|
AuthenticateURL: mustParseURL("https://authN.example.com"),
|
||||||
|
SharedKey: tt.SharedKey,
|
||||||
|
Policies: tt.Policies}
|
||||||
if tt.name == "empty options" {
|
if tt.name == "empty options" {
|
||||||
o = config.Options{}
|
o = config.Options{}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,12 +9,16 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
envoy_service_auth_v2 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v2"
|
envoy_service_auth_v2 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v2"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/google/go-cmp/cmp"
|
||||||
|
|
||||||
"github.com/pomerium/pomerium/authorize/evaluator"
|
"github.com/pomerium/pomerium/authorize/evaluator"
|
||||||
"github.com/pomerium/pomerium/config"
|
"github.com/pomerium/pomerium/config"
|
||||||
|
"github.com/pomerium/pomerium/internal/cryptutil"
|
||||||
|
"github.com/pomerium/pomerium/internal/encoding/jws"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"gopkg.in/square/go-jose.v2/jwt"
|
||||||
)
|
)
|
||||||
|
|
||||||
const certPEM = `
|
const certPEM = `
|
||||||
|
@ -148,3 +152,149 @@ func mustParseURL(str string) *url.URL {
|
||||||
}
|
}
|
||||||
return u
|
return u
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAuthorize_Check(t *testing.T) {
|
||||||
|
// golden policy
|
||||||
|
p := config.Policy{
|
||||||
|
From: "http://test.example.com",
|
||||||
|
To: "http://localhost",
|
||||||
|
AllowedUsers: []string{"bob@example.com"},
|
||||||
|
}
|
||||||
|
err := p.Validate()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
ps := []config.Policy{p}
|
||||||
|
|
||||||
|
type user struct {
|
||||||
|
// Standard claims (as specified in RFC 7519).
|
||||||
|
jwt.Claims
|
||||||
|
// Pomerium claims (not standard claims)
|
||||||
|
Email string `json:"email"`
|
||||||
|
Groups []string `json:"groups,omitempty"`
|
||||||
|
User string `json:"user,omitempty"`
|
||||||
|
ImpersonateEmail string `json:"impersonate_email,omitempty"`
|
||||||
|
ImpersonateGroups []string `json:"impersonate_groups,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
ctx context.Context
|
||||||
|
sk string
|
||||||
|
inUser string
|
||||||
|
inExpiry time.Time
|
||||||
|
inIssuer string
|
||||||
|
inAudience string
|
||||||
|
in *envoy_service_auth_v2.CheckRequest
|
||||||
|
want string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{"good",
|
||||||
|
context.TODO(),
|
||||||
|
cryptutil.NewBase64Key(),
|
||||||
|
"bob@example.com",
|
||||||
|
time.Now().Add(1 * time.Hour),
|
||||||
|
"authN.example.com",
|
||||||
|
"test.example.com",
|
||||||
|
nil,
|
||||||
|
"OK",
|
||||||
|
false},
|
||||||
|
{"bad user, alice",
|
||||||
|
context.TODO(),
|
||||||
|
cryptutil.NewBase64Key(),
|
||||||
|
"alice@example.com",
|
||||||
|
time.Now().Add(1 * time.Hour),
|
||||||
|
"authN.example.com",
|
||||||
|
"test.example.com",
|
||||||
|
nil,
|
||||||
|
"Access Denied",
|
||||||
|
false},
|
||||||
|
{"expired",
|
||||||
|
context.TODO(),
|
||||||
|
cryptutil.NewBase64Key(),
|
||||||
|
"bob@example.com",
|
||||||
|
time.Now().Add(-1 * time.Hour),
|
||||||
|
"authN.example.com",
|
||||||
|
"test.example.com",
|
||||||
|
nil,
|
||||||
|
"Access Denied",
|
||||||
|
false},
|
||||||
|
{"bad audience",
|
||||||
|
context.TODO(),
|
||||||
|
cryptutil.NewBase64Key(),
|
||||||
|
"bob@example.com",
|
||||||
|
time.Now().Add(1 * time.Hour),
|
||||||
|
"authN.example.com",
|
||||||
|
"bad.example.com",
|
||||||
|
nil,
|
||||||
|
"Access Denied",
|
||||||
|
false},
|
||||||
|
{"bad issuer",
|
||||||
|
context.TODO(),
|
||||||
|
cryptutil.NewBase64Key(),
|
||||||
|
"bob@example.com",
|
||||||
|
time.Now().Add(1 * time.Hour),
|
||||||
|
"bad.example.com",
|
||||||
|
"test.example.com",
|
||||||
|
nil,
|
||||||
|
"OK",
|
||||||
|
false},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
var sa user
|
||||||
|
sa.Expiry = jwt.NewNumericDate(tt.inExpiry)
|
||||||
|
sa.IssuedAt = jwt.NewNumericDate(time.Now())
|
||||||
|
sa.NotBefore = jwt.NewNumericDate(time.Now())
|
||||||
|
sa.Email = tt.inUser
|
||||||
|
sa.Subject = sa.Email
|
||||||
|
sa.Issuer = tt.inIssuer
|
||||||
|
sa.Audience = jwt.Audience{tt.inAudience}
|
||||||
|
|
||||||
|
sharedKey := tt.sk
|
||||||
|
|
||||||
|
encoder, err := jws.NewHS256Signer([]byte(sharedKey), tt.inIssuer)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
raw, err := encoder.Marshal(sa)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
opts := config.Options{
|
||||||
|
Policies: ps,
|
||||||
|
CookieName: "_pomerium",
|
||||||
|
AuthenticateURL: mustParseURL("https://authN.example.com"),
|
||||||
|
SharedKey: sharedKey}
|
||||||
|
a, err := New(opts)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
in := &envoy_service_auth_v2.CheckRequest{
|
||||||
|
Attributes: &envoy_service_auth_v2.AttributeContext{
|
||||||
|
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/json",
|
||||||
|
"cookie": "_pomerium=" + string(raw),
|
||||||
|
},
|
||||||
|
Host: "test.example.com",
|
||||||
|
Scheme: "http",
|
||||||
|
Body: "BODY",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
got, err := a.Check(tt.ctx, in)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("Authorize.Check() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(got.Status.GetMessage(), tt.want); diff != "" {
|
||||||
|
t.Errorf("Authorize.Check() = %v", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue