Skip to content

Commit

Permalink
Support wildcard patterns for URI allow/verify flags
Browse files Browse the repository at this point in the history
  • Loading branch information
csstaub committed Oct 11, 2018
1 parent 4eb1043 commit 9a5a678
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 18 deletions.
2 changes: 1 addition & 1 deletion .appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,4 @@ build_script:
- set CGO_ENABLED=1
- go build -o ghostunnel-%GIT_VERSION%-windows-%GOARCH%-with-pkcs11.exe -ldflags "-w -extldflags \"-static\" -extld=%EXTLD%" -i .
# Execute tests
- go test -v . ./auth
- go test -v . ./auth ./certloader ./proxy ./wildcard
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ unit:
go test -v -covermode=count -coverprofile=coverage-unit-test-auth.out ./auth
go test -v -covermode=count -coverprofile=coverage-unit-test-certloader.out ./certloader
go test -v -covermode=count -coverprofile=coverage-unit-test-proxy.out ./proxy
go test -v -covermode=count -coverprofile=coverage-unit-test-wildcard.out ./wildcard
.PHONY: unit

# Run integration tests
Expand Down
8 changes: 5 additions & 3 deletions auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import (
"errors"
"net"
"net/url"

"github.com/square/ghostunnel/wildcard"
)

// Logger is used by this package to log messages
Expand Down Expand Up @@ -53,7 +55,7 @@ type ACL struct {
// AllowURIs lists URI SANs that should be allowed access. If a principal
// has a valid certificate with at least one of these URI SANs, we grant
// access.
AllowedURIs []string
AllowedURIs []wildcard.Matcher
// Logger is used to log authorization decisions.
Logger Logger
}
Expand Down Expand Up @@ -181,10 +183,10 @@ func intersectsIP(left, right []net.IP) bool {
}

// Returns true if at least one item from left is also contained in right.
func intersectsURI(left []string, right []*url.URL) bool {
func intersectsURI(left []wildcard.Matcher, right []*url.URL) bool {
for _, l := range left {
for _, r := range right {
if r.String() == l {
if l.Matches(r.String()) {
return true
}
}
Expand Down
11 changes: 6 additions & 5 deletions auth/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"net/url"
"testing"

"github.com/square/ghostunnel/wildcard"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -55,7 +56,7 @@ func TestAuthorizeReject(t *testing.T) {
AllowedCNs: []string{"test"},
AllowedOUs: []string{"test"},
AllowedDNSs: []string{"test"},
AllowedURIs: []string{"test"},
AllowedURIs: []wildcard.Matcher{wildcard.MustCompile("test")},
}

assert.NotNil(t, testACL.VerifyPeerCertificateServer(nil, fakeChains), "should reject cert w/o matching CN/OU")
Expand Down Expand Up @@ -103,15 +104,15 @@ func TestAuthorizeAllowIP(t *testing.T) {

func TestAuthorizeAllowURI(t *testing.T) {
testACL := ACL{
AllowedURIs: []string{"scheme://valid/path"},
AllowedURIs: []wildcard.Matcher{wildcard.MustCompile("scheme://valid/path")},
}

assert.Nil(t, testACL.VerifyPeerCertificateServer(nil, fakeChains), "allow-uri-san should allow clients with matching URI SAN")
}

func TestAuthorizeRejectURI(t *testing.T) {
testACL := ACL{
AllowedURIs: []string{"schema://invalid/path"},
AllowedURIs: []wildcard.Matcher{wildcard.MustCompile("scheme://invalid/path")},
}

assert.NotNil(t, testACL.VerifyPeerCertificateServer(nil, fakeChains), "should reject cert w/o matching URI")
Expand Down Expand Up @@ -192,15 +193,15 @@ func TestVerifyRejectIP(t *testing.T) {

func TestVerifyAllowURI(t *testing.T) {
testACL := ACL{
AllowedURIs: []string{"scheme://valid/path"},
AllowedURIs: []wildcard.Matcher{wildcard.MustCompile("scheme://valid/path")},
}

assert.Nil(t, testACL.VerifyPeerCertificateClient(nil, fakeChains), "verify-uri-san should allow clients with matching URI SAN")
}

func TestVerifyRejectURI(t *testing.T) {
testACL := ACL{
AllowedURIs: []string{"scheme://invalid/path"},
AllowedURIs: []wildcard.Matcher{wildcard.MustCompile("scheme://invalid/path")},
}

assert.NotNil(t, testACL.VerifyPeerCertificateClient(nil, fakeChains), "should reject cert w/o matching URI")
Expand Down
17 changes: 15 additions & 2 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (
"github.com/square/ghostunnel/auth"
"github.com/square/ghostunnel/certloader"
"github.com/square/ghostunnel/proxy"
"github.com/square/ghostunnel/wildcard"
"github.com/square/go-sq-metrics"
"gopkg.in/alecthomas/kingpin.v2"

Expand Down Expand Up @@ -389,13 +390,19 @@ func serverListen(context *Context) error {
return err
}

allowedURIs, err := wildcard.CompileList(*serverAllowedURIs)
if err != nil {
logger.Printf("invalid URI pattern in --allow-uri flag (%s)", err)
return err
}

serverACL := auth.ACL{
AllowAll: *serverAllowAll,
AllowedCNs: *serverAllowedCNs,
AllowedOUs: *serverAllowedOUs,
AllowedDNSs: *serverAllowedDNSs,
AllowedIPs: *serverAllowedIPs,
AllowedURIs: *serverAllowedURIs,
AllowedURIs: allowedURIs,
Logger: logger,
}

Expand Down Expand Up @@ -578,12 +585,18 @@ func clientBackendDialer(cert certloader.Certificate, network, address, host str
config.ServerName = *clientServerName
}

allowedURIs, err := wildcard.CompileList(*clientAllowedURIs)
if err != nil {
logger.Printf("invalid URI pattern in --verify-uri flag (%s)", err)
return nil, err
}

clientACL := auth.ACL{
AllowedCNs: *clientAllowedCNs,
AllowedOUs: *clientAllowedOUs,
AllowedDNSs: *clientAllowedDNSs,
AllowedIPs: *clientAllowedIPs,
AllowedURIs: *clientAllowedURIs,
AllowedURIs: allowedURIs,
Logger: logger,
}

Expand Down
33 changes: 28 additions & 5 deletions wildcard/matcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,36 @@ type regexpMatcher struct {
pattern *regexp.Regexp
}

// New creates a new Matcher given a pattern, using '/' as the separator.
func New(pattern string) (Matcher, error) {
return NewWithSeparator(pattern, defaultSeparator)
// Compile creates a new Matcher given a pattern, using '/' as the separator.
func Compile(pattern string) (Matcher, error) {
return CompileWithSeparator(pattern, defaultSeparator)
}

// New creates a new Matcher given a pattern and separator rune.
func NewWithSeparator(pattern string, separator rune) (Matcher, error) {
// CompileList creates new Matchers given a list patterns, using '/' as the separator.
func CompileList(patterns []string) ([]Matcher, error) {
ms := []Matcher{}
for _, pattern := range patterns {
m, err := Compile(pattern)
if err != nil {
return nil, err
}
ms = append(ms, m)
}
return ms, nil
}

// MustCompile creates a new Matcher given a pattern, using '/' as the separator,
// and panics if the given pattern was invalid.
func MustCompile(pattern string) Matcher {
m, err := CompileWithSeparator(pattern, defaultSeparator)
if err != nil {
panic(err)
}
return m
}

// CompileWithSeparator creates a new Matcher given a pattern and separator rune.
func CompileWithSeparator(pattern string, separator rune) (Matcher, error) {
// Build regular expression from wildcard pattern
// - Wildcard '*' should match all chars except forward slash
// - Wildcard '**' should match all chars, including forward slash
Expand Down
4 changes: 2 additions & 2 deletions wildcard/matcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ package wildcard
import "testing"

func testMatches(t *testing.T, pattern string, matches []string, invalids []string) {
matcher, err := New(pattern)
matcher, err := Compile(pattern)
if err != nil {
t.Fatalf("bad pattern: '%s' (%s)", pattern, err)
}
Expand Down Expand Up @@ -233,7 +233,7 @@ func TestInvalidPatterns(t *testing.T) {
"test://**/asdf",
"**://foo/asdf",
} {
_, err := New(pattern)
_, err := Compile(pattern)
if err == nil {
t.Errorf("should reject invalid pattern '%s'", pattern)
}
Expand Down

0 comments on commit 9a5a678

Please sign in to comment.