Skip to content

Commit d501795

Browse files
committed
ING-1363: Ensure client cert auth fails when disabled
1 parent 63f8a0c commit d501795

6 files changed

Lines changed: 126 additions & 6 deletions

File tree

gateway/auth/cbauthauthenticator.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
var (
1515
ErrInvalidCredentials = errors.New("invalid credentials")
1616
ErrInvalidCertificate = errors.New("invalid certificate")
17+
ErrCertAuthDisabled = errors.New("client cert auth disabled")
1718
)
1819

1920
type CbAuthAuthenticator struct {
@@ -101,6 +102,8 @@ func (a *CbAuthAuthenticator) ValidateConnStateForObo(ctx context.Context, connS
101102
if err != nil {
102103
if errors.Is(err, cbauthx.ErrInvalidAuth) {
103104
return "", "", ErrInvalidCertificate
105+
} else if errors.Is(err, cbauthx.ErrCertAuthDisabled) {
106+
return "", "", ErrCertAuthDisabled
104107
}
105108

106109
return "", "", fmt.Errorf("failed to check certificate with cbauth: %s", err.Error())

gateway/dataimpl/server_v1/authhandler.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ func (a AuthHandler) MaybeGetOboUserFromContext(ctx context.Context) (string, st
8888
if err != nil {
8989
if errors.Is(err, auth.ErrInvalidCertificate) {
9090
return "", "", a.ErrorHandler.NewInvalidCertificateStatus()
91+
} else if errors.Is(err, auth.ErrCertAuthDisabled) {
92+
return "", "", a.ErrorHandler.NewCertAuthDisabledStatus()
9193
}
9294

9395
a.Logger.Error("received an unexpected cert authentication error", zap.Error(err))

gateway/dataimpl/server_v1/errorhandler.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -937,6 +937,16 @@ func (e ErrorHandler) NewInvalidCertificateStatus() *status.Status {
937937
return st
938938
}
939939

940+
func (e ErrorHandler) NewCertAuthDisabledStatus() *status.Status {
941+
st := status.New(codes.Unauthenticated, "Client cert auth disabled on the cluster.")
942+
st = e.tryAttachStatusDetails(st, &epb.ResourceInfo{
943+
ResourceType: "user",
944+
ResourceName: "",
945+
Description: "",
946+
})
947+
return st
948+
}
949+
940950
func (e ErrorHandler) NewUnexpectedAuthTypeStatus() *status.Status {
941951
st := status.New(codes.InvalidArgument, "Unexpected auth type.")
942952
return st

gateway/test/mtls_test.go

Lines changed: 108 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ package test
33
import (
44
"context"
55
"crypto/tls"
6+
"net/http"
67
"time"
78

9+
"github.com/couchbase/gocbcorex/cbhttpx"
10+
"github.com/couchbase/gocbcorex/cbmgmtx"
811
"github.com/couchbase/goprotostellar/genproto/kv_v1"
912
"github.com/couchbase/stellar-gateway/testutils"
1013
"github.com/couchbase/stellar-gateway/utils/certificates"
@@ -18,6 +21,8 @@ func (s *GatewayOpsTestSuite) TestClientCertAuth() {
1821
testutils.SkipIfNoDinoCluster(s.T())
1922

2023
s.Run("KvService", s.KvService)
24+
25+
s.Run("ClientCertAuthDisabled", s.ClientCertConfiguration)
2126
}
2227

2328
func (s *GatewayOpsTestSuite) KvService() {
@@ -97,15 +102,115 @@ func (s *GatewayOpsTestSuite) KvService() {
97102
})
98103
}
99104

105+
func (s *GatewayOpsTestSuite) ClientCertConfiguration() {
106+
dino := testutils.StartDinoTesting(s.T(), false)
107+
username := "certConfig"
108+
conn := s.newClientCertConn(username)
109+
kvClient := kv_v1.NewKvServiceClient(conn)
110+
111+
getFn := func() (*kv_v1.GetResponse, error) {
112+
return kvClient.Get(context.Background(), &kv_v1.GetRequest{
113+
BucketName: s.bucketName,
114+
ScopeName: s.scopeName,
115+
CollectionName: s.collectionName,
116+
Key: s.testDocId(),
117+
})
118+
}
119+
120+
enableReq := &cbmgmtx.ConfigureClientCertAuthRequest{
121+
State: "enable",
122+
Prefixes: []cbmgmtx.Prefix{
123+
{
124+
Path: "san.email",
125+
Prefix: "",
126+
Delimiter: "@",
127+
},
128+
},
129+
}
130+
131+
dino.AddWriteUser(username)
132+
time.Sleep(time.Second * 5)
133+
134+
// Check that client cert auth is working as expected.
135+
s.Run("InitialSuccess", func() {
136+
resp, err := getFn()
137+
requireRpcSuccess(s.T(), resp, err)
138+
})
139+
140+
testConfig := testutils.GetTestConfig(s.T())
141+
mgmt := cbmgmtx.Management{
142+
Transport: http.DefaultTransport,
143+
UserAgent: "useragent",
144+
Endpoint: "http://" + testConfig.CbConnStr + ":8091",
145+
Auth: &cbhttpx.BasicAuth{
146+
Username: testConfig.CbUser,
147+
Password: testConfig.CbPass,
148+
},
149+
}
150+
151+
// Change the path that cbauth will try and get the name from and check
152+
// that the old cert fails
153+
err := mgmt.ConfigureClientCertAuth(context.Background(), &cbmgmtx.ConfigureClientCertAuthRequest{
154+
State: "enable",
155+
Prefixes: []cbmgmtx.Prefix{
156+
{
157+
Path: "subject.cn",
158+
Prefix: "",
159+
Delimiter: "",
160+
},
161+
},
162+
})
163+
time.Sleep(time.Second * 5)
164+
165+
// Check that client cert auth is working as expected.
166+
s.Run("IncorrectUsernamePath", func() {
167+
_, err := getFn()
168+
assertRpcStatus(s.T(), err, codes.PermissionDenied)
169+
assert.Contains(s.T(), err.Error(), "Your certificate is invalid")
170+
})
171+
172+
// Restore intial settings and check that the original cert works again.
173+
err = mgmt.ConfigureClientCertAuth(context.Background(), enableReq)
174+
assert.NoError(s.T(), err)
175+
time.Sleep(time.Second * 5)
176+
177+
s.Run("SuccessAfterSettingsReset", func() {
178+
resp, err := getFn()
179+
requireRpcSuccess(s.T(), resp, err)
180+
})
181+
182+
// Disable client cert auth on the cluster and make sure op fails.
183+
err = mgmt.ConfigureClientCertAuth(context.Background(), &cbmgmtx.ConfigureClientCertAuthRequest{
184+
State: "disable",
185+
Prefixes: []cbmgmtx.Prefix{
186+
{
187+
Path: "san.email",
188+
Prefix: "",
189+
Delimiter: "@",
190+
},
191+
},
192+
})
193+
assert.NoError(s.T(), err)
194+
time.Sleep(time.Second * 5)
195+
196+
s.Run("CertAuthDisabled", func() {
197+
_, err := getFn()
198+
assertRpcStatus(s.T(), err, codes.Unauthenticated)
199+
assert.Contains(s.T(), err.Error(), "Client cert auth disabled on the cluster")
200+
})
201+
202+
err = mgmt.ConfigureClientCertAuth(context.Background(), enableReq)
203+
assert.NoError(s.T(), err)
204+
}
205+
100206
func (s *GatewayOpsTestSuite) newClientCertConn(username string) *grpc.ClientConn {
101207
cert, err := certificates.GenerateSignedClientCert(s.caCert, s.caKey, username)
102208
assert.NoError(s.T(), err)
103209

104210
conn, err := grpc.NewClient(s.gwConnAddr,
105211
grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
106-
RootCAs: s.clientCaCertPool,
107-
Certificates: []tls.Certificate{*cert},
108-
InsecureSkipVerify: false,
212+
RootCAs: s.clientCaCertPool,
213+
Certificates: []tls.Certificate{*cert},
109214
})))
110215
if err != nil {
111216
s.T().Fatalf("failed to connect to test gateway: %s", err)

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ require (
1010
github.com/Azure/azure-sdk-for-go/sdk/keyvault/azsecrets v0.12.0
1111
github.com/aws/aws-sdk-go-v2/config v1.28.8
1212
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.34.9
13-
github.com/couchbase/gocbcorex v0.0.0-20251111022038-67fa47c27da2
13+
github.com/couchbase/gocbcorex v0.0.0-20251118081240-3f26da0f471e
1414
github.com/couchbase/goprotostellar v1.0.3-0.20251106001300-b09286f4d53d
1515
github.com/couchbaselabs/gocbconnstr v1.0.5
1616
github.com/couchbaselabs/gocbconnstr/v2 v2.0.0-20240607131231-fb385523de28

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
6767
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
6868
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
6969
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
70-
github.com/couchbase/gocbcorex v0.0.0-20251111022038-67fa47c27da2 h1:Cbw1gJs5V2z/SHPmiqVo7nlr7RWtMAusEoxIDpsPm+s=
71-
github.com/couchbase/gocbcorex v0.0.0-20251111022038-67fa47c27da2/go.mod h1:tlLBmDl/J9iUCImvGvzIr1sLhHm8+KWaSfkofmErCMQ=
70+
github.com/couchbase/gocbcorex v0.0.0-20251118081240-3f26da0f471e h1:3H82a+phltYGRicpdKogxt9mvDAe7kD66t9086vXh9k=
71+
github.com/couchbase/gocbcorex v0.0.0-20251118081240-3f26da0f471e/go.mod h1:tlLBmDl/J9iUCImvGvzIr1sLhHm8+KWaSfkofmErCMQ=
7272
github.com/couchbase/goprotostellar v1.0.3-0.20251106001300-b09286f4d53d h1:FZZcOTRLIaK3VGX0eVGmvCqc6teJ+BSuS3VYJMAjejs=
7373
github.com/couchbase/goprotostellar v1.0.3-0.20251106001300-b09286f4d53d/go.mod h1:X58ot5FRqlBTBkwG/oI4klunpu4MApjGktheqeRWQw0=
7474
github.com/couchbaselabs/gocbconnstr v1.0.5 h1:e0JokB5qbcz7rfnxEhNRTKz8q1svoRvDoZihsiwNigA=

0 commit comments

Comments
 (0)