Skip to content

Commit 9a5a678

Browse files
committed
Support wildcard patterns for URI allow/verify flags
1 parent 4eb1043 commit 9a5a678

File tree

7 files changed

+58
-18
lines changed

7 files changed

+58
-18
lines changed

.appveyor.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,4 @@ build_script:
4242
- set CGO_ENABLED=1
4343
- go build -o ghostunnel-%GIT_VERSION%-windows-%GOARCH%-with-pkcs11.exe -ldflags "-w -extldflags \"-static\" -extld=%EXTLD%" -i .
4444
# Execute tests
45-
- go test -v . ./auth
45+
- go test -v . ./auth ./certloader ./proxy ./wildcard

Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ unit:
2727
go test -v -covermode=count -coverprofile=coverage-unit-test-auth.out ./auth
2828
go test -v -covermode=count -coverprofile=coverage-unit-test-certloader.out ./certloader
2929
go test -v -covermode=count -coverprofile=coverage-unit-test-proxy.out ./proxy
30+
go test -v -covermode=count -coverprofile=coverage-unit-test-wildcard.out ./wildcard
3031
.PHONY: unit
3132

3233
# Run integration tests

auth/auth.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import (
2121
"errors"
2222
"net"
2323
"net/url"
24+
25+
"github.com/square/ghostunnel/wildcard"
2426
)
2527

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

183185
// Returns true if at least one item from left is also contained in right.
184-
func intersectsURI(left []string, right []*url.URL) bool {
186+
func intersectsURI(left []wildcard.Matcher, right []*url.URL) bool {
185187
for _, l := range left {
186188
for _, r := range right {
187-
if r.String() == l {
189+
if l.Matches(r.String()) {
188190
return true
189191
}
190192
}

auth/auth_test.go

+6-5
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"net/url"
2424
"testing"
2525

26+
"github.com/square/ghostunnel/wildcard"
2627
"github.com/stretchr/testify/assert"
2728
)
2829

@@ -55,7 +56,7 @@ func TestAuthorizeReject(t *testing.T) {
5556
AllowedCNs: []string{"test"},
5657
AllowedOUs: []string{"test"},
5758
AllowedDNSs: []string{"test"},
58-
AllowedURIs: []string{"test"},
59+
AllowedURIs: []wildcard.Matcher{wildcard.MustCompile("test")},
5960
}
6061

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

104105
func TestAuthorizeAllowURI(t *testing.T) {
105106
testACL := ACL{
106-
AllowedURIs: []string{"scheme://valid/path"},
107+
AllowedURIs: []wildcard.Matcher{wildcard.MustCompile("scheme://valid/path")},
107108
}
108109

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

112113
func TestAuthorizeRejectURI(t *testing.T) {
113114
testACL := ACL{
114-
AllowedURIs: []string{"schema://invalid/path"},
115+
AllowedURIs: []wildcard.Matcher{wildcard.MustCompile("scheme://invalid/path")},
115116
}
116117

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

193194
func TestVerifyAllowURI(t *testing.T) {
194195
testACL := ACL{
195-
AllowedURIs: []string{"scheme://valid/path"},
196+
AllowedURIs: []wildcard.Matcher{wildcard.MustCompile("scheme://valid/path")},
196197
}
197198

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

201202
func TestVerifyRejectURI(t *testing.T) {
202203
testACL := ACL{
203-
AllowedURIs: []string{"scheme://invalid/path"},
204+
AllowedURIs: []wildcard.Matcher{wildcard.MustCompile("scheme://invalid/path")},
204205
}
205206

206207
assert.NotNil(t, testACL.VerifyPeerCertificateClient(nil, fakeChains), "should reject cert w/o matching URI")

main.go

+15-2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import (
3838
"github.com/square/ghostunnel/auth"
3939
"github.com/square/ghostunnel/certloader"
4040
"github.com/square/ghostunnel/proxy"
41+
"github.com/square/ghostunnel/wildcard"
4142
"github.com/square/go-sq-metrics"
4243
"gopkg.in/alecthomas/kingpin.v2"
4344

@@ -389,13 +390,19 @@ func serverListen(context *Context) error {
389390
return err
390391
}
391392

393+
allowedURIs, err := wildcard.CompileList(*serverAllowedURIs)
394+
if err != nil {
395+
logger.Printf("invalid URI pattern in --allow-uri flag (%s)", err)
396+
return err
397+
}
398+
392399
serverACL := auth.ACL{
393400
AllowAll: *serverAllowAll,
394401
AllowedCNs: *serverAllowedCNs,
395402
AllowedOUs: *serverAllowedOUs,
396403
AllowedDNSs: *serverAllowedDNSs,
397404
AllowedIPs: *serverAllowedIPs,
398-
AllowedURIs: *serverAllowedURIs,
405+
AllowedURIs: allowedURIs,
399406
Logger: logger,
400407
}
401408

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

588+
allowedURIs, err := wildcard.CompileList(*clientAllowedURIs)
589+
if err != nil {
590+
logger.Printf("invalid URI pattern in --verify-uri flag (%s)", err)
591+
return nil, err
592+
}
593+
581594
clientACL := auth.ACL{
582595
AllowedCNs: *clientAllowedCNs,
583596
AllowedOUs: *clientAllowedOUs,
584597
AllowedDNSs: *clientAllowedDNSs,
585598
AllowedIPs: *clientAllowedIPs,
586-
AllowedURIs: *clientAllowedURIs,
599+
AllowedURIs: allowedURIs,
587600
Logger: logger,
588601
}
589602

wildcard/matcher.go

+28-5
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,36 @@ type regexpMatcher struct {
6464
pattern *regexp.Regexp
6565
}
6666

67-
// New creates a new Matcher given a pattern, using '/' as the separator.
68-
func New(pattern string) (Matcher, error) {
69-
return NewWithSeparator(pattern, defaultSeparator)
67+
// Compile creates a new Matcher given a pattern, using '/' as the separator.
68+
func Compile(pattern string) (Matcher, error) {
69+
return CompileWithSeparator(pattern, defaultSeparator)
7070
}
7171

72-
// New creates a new Matcher given a pattern and separator rune.
73-
func NewWithSeparator(pattern string, separator rune) (Matcher, error) {
72+
// CompileList creates new Matchers given a list patterns, using '/' as the separator.
73+
func CompileList(patterns []string) ([]Matcher, error) {
74+
ms := []Matcher{}
75+
for _, pattern := range patterns {
76+
m, err := Compile(pattern)
77+
if err != nil {
78+
return nil, err
79+
}
80+
ms = append(ms, m)
81+
}
82+
return ms, nil
83+
}
84+
85+
// MustCompile creates a new Matcher given a pattern, using '/' as the separator,
86+
// and panics if the given pattern was invalid.
87+
func MustCompile(pattern string) Matcher {
88+
m, err := CompileWithSeparator(pattern, defaultSeparator)
89+
if err != nil {
90+
panic(err)
91+
}
92+
return m
93+
}
94+
95+
// CompileWithSeparator creates a new Matcher given a pattern and separator rune.
96+
func CompileWithSeparator(pattern string, separator rune) (Matcher, error) {
7497
// Build regular expression from wildcard pattern
7598
// - Wildcard '*' should match all chars except forward slash
7699
// - Wildcard '**' should match all chars, including forward slash

wildcard/matcher_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ package wildcard
1919
import "testing"
2020

2121
func testMatches(t *testing.T, pattern string, matches []string, invalids []string) {
22-
matcher, err := New(pattern)
22+
matcher, err := Compile(pattern)
2323
if err != nil {
2424
t.Fatalf("bad pattern: '%s' (%s)", pattern, err)
2525
}
@@ -233,7 +233,7 @@ func TestInvalidPatterns(t *testing.T) {
233233
"test://**/asdf",
234234
"**://foo/asdf",
235235
} {
236-
_, err := New(pattern)
236+
_, err := Compile(pattern)
237237
if err == nil {
238238
t.Errorf("should reject invalid pattern '%s'", pattern)
239239
}

0 commit comments

Comments
 (0)