diff --git a/README.md b/README.md index 5f500ae..23e405a 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ OPTIONS: --secondary-group-prefix value Prefix for LDAP groups to map to secondary groups of SFTPGo users [$SFTPGO_PLUGIN_AUTH_SECONDARY_GROUP_PREFIX] --membership-group-prefix value Prefix for LDAP groups to map to membership groups of SFTPGo users [$SFTPGO_PLUGIN_AUTH_MEMBERSHIP_GROUP_PREFIX] --require-groups Require authenticated users to be members of at least one SFTPGo group (default: false) [$SFTPGO_PLUGIN_AUTH_REQUIRE_GROUPS] + --user-requirements value Requirements for SFTPGo users. 1 means users must be already defined in SFTPGo (default: 0) [$SFTPGO_PLUGIN_AUTH_USER_REQUIREMENTS] --starttls value STARTTLS is the preferred method of encrypting an LDAP connection. Use it instead of using the ldaps:// URL schema (default: 0) [$SFTPGO_PLUGIN_AUTH_STARTTLS] --users-base-dir value Users default base directory. Leave empty if already set in SFTPGo. If set it must be an absolute path [$SFTPGO_PLUGIN_AUTH_USERS_BASE_DIR] --cache-time value Defines the cache time, in seconds, for authenticated users. 0 means no cache (default: 0) [$SFTPGO_PLUGIN_AUTH_CACHE_TIME] diff --git a/authenticator/authenticator.go b/authenticator/authenticator.go index c38ab15..bf5fa4f 100644 --- a/authenticator/authenticator.go +++ b/authenticator/authenticator.go @@ -35,6 +35,7 @@ var ( func NewAuthenticator(dialURLs []string, baseDN, username, password string, startTLS int, skipTLSVerify bool, baseDir string, cacheTime int, searchQuery string, groupAttributes, caCertificates []string, primaryGroupPrefix, secondaryGroupPrefix, membershipGroupPrefix string, requiresGroup bool, + sftpgoUserRequirements int, ) (*LDAPAuthenticator, error) { rootCAs, err := loadCACerts(caCertificates) if err != nil { @@ -45,19 +46,20 @@ func NewAuthenticator(dialURLs []string, baseDN, username, password string, star InsecureSkipVerify: skipTLSVerify, } auth := &LDAPAuthenticator{ - DialURLs: dialURLs, - BaseDN: baseDN, - Username: username, - Password: password, - StartTLS: startTLS, - SearchQuery: searchQuery, - GroupAttributes: groupAttributes, - BaseDir: baseDir, - PrimaryGroupPrefix: strings.ToLower(primaryGroupPrefix), - SecondaryGroupPrefix: strings.ToLower(secondaryGroupPrefix), - MembershipGroupPrefix: strings.ToLower(membershipGroupPrefix), - RequireGroups: requiresGroup, - tlsConfig: tlsConfig, + DialURLs: dialURLs, + BaseDN: baseDN, + Username: username, + Password: password, + StartTLS: startTLS, + SearchQuery: searchQuery, + GroupAttributes: groupAttributes, + BaseDir: baseDir, + PrimaryGroupPrefix: strings.ToLower(primaryGroupPrefix), + SecondaryGroupPrefix: strings.ToLower(secondaryGroupPrefix), + MembershipGroupPrefix: strings.ToLower(membershipGroupPrefix), + RequireGroups: requiresGroup, + SFTPGoUserRequirements: sftpgoUserRequirements, + tlsConfig: tlsConfig, } if err := auth.validate(); err != nil { return nil, err diff --git a/authenticator/ldap.go b/authenticator/ldap.go index 39c3702..c52d3b2 100644 --- a/authenticator/ldap.go +++ b/authenticator/ldap.go @@ -33,23 +33,24 @@ import ( ) type LDAPAuthenticator struct { - DialURLs []string - BaseDN string - Username string - Password string - StartTLS int - SearchQuery string - GroupAttributes []string - PrimaryGroupPrefix string - SecondaryGroupPrefix string - MembershipGroupPrefix string - RequireGroups bool - BaseDir string - tlsConfig *tls.Config - monitorTicker *time.Ticker - cleanupDone chan bool - mu sync.RWMutex - activeURLs []string + DialURLs []string + BaseDN string + Username string + Password string + StartTLS int + SearchQuery string + GroupAttributes []string + PrimaryGroupPrefix string + SecondaryGroupPrefix string + MembershipGroupPrefix string + RequireGroups bool + SFTPGoUserRequirements int + BaseDir string + tlsConfig *tls.Config + monitorTicker *time.Ticker + cleanupDone chan bool + mu sync.RWMutex + activeURLs []string } func (a *LDAPAuthenticator) validate() error { @@ -208,10 +209,14 @@ func (a *LDAPAuthenticator) CheckUserAndPass(username, password, _, _ string, us if err := l.Bind(entry.DN, password); err != nil { return nil, err } + result, err := a.getUser(userAsJSON, entry.Attributes) + if err != nil { + return nil, err + } if cache != nil { cache.Add(username, password) } - return a.getUser(userAsJSON, entry.Attributes) + return result, nil } func (a *LDAPAuthenticator) CheckUserAndTLSCert(_, _, _, _ string, _ []byte) ([]byte, error) { @@ -327,6 +332,11 @@ func (a *LDAPAuthenticator) getUser(userAsJSON []byte, attributes []*ldap.EntryA if err := json.Unmarshal(userAsJSON, &user); err != nil { return nil, err } + if user.ID == 0 && a.isSFTPGoUserRequired() { + err := errors.New("LDAP users not defined in SFTPGo are not allowed") + logger.AppLogger.Debug("no SFTPGo user defined", "username", user.Username, "err", err) + return nil, err + } var groups []sdk.GroupMapping for _, attr := range attributes { @@ -358,7 +368,7 @@ func (a *LDAPAuthenticator) getUser(userAsJSON []byte, attributes []*ldap.EntryA } if a.RequireGroups && len(groups) == 0 { err := errors.New("users without group membership are not allowed") - logger.AppLogger.Debug("no group for found", "user", user.Username, "err", err) + logger.AppLogger.Debug("no group found", "username", user.Username, "err", err) return nil, err } @@ -386,7 +396,14 @@ func (a *LDAPAuthenticator) hasGroups() bool { (a.PrimaryGroupPrefix != "" || a.SecondaryGroupPrefix != "" || a.MembershipGroupPrefix != "") } +func (a *LDAPAuthenticator) isSFTPGoUserRequired() bool { + return a.SFTPGoUserRequirements == 1 +} + func (a *LDAPAuthenticator) isUserToUpdate(u *sdk.User, groups []sdk.GroupMapping) bool { + if a.isSFTPGoUserRequired() { + return false + } if u.ID == 0 { return true } diff --git a/authenticator/ldap_test.go b/authenticator/ldap_test.go index 9aec9c2..407a33b 100644 --- a/authenticator/ldap_test.go +++ b/authenticator/ldap_test.go @@ -79,7 +79,8 @@ var ( func TestLDAPAuthenticator(t *testing.T) { baseDir := filepath.Clean(os.TempDir()) auth, err := NewAuthenticator(ldapURL, baseDN, username, password, 0, false, baseDir, 2, searchQuery, - []string{groupAttribute}, nil, primaryGroupPrefix, secondaryGroupPrefix, membershipGroupPrefix, true) + []string{groupAttribute}, nil, primaryGroupPrefix, secondaryGroupPrefix, membershipGroupPrefix, + true, 0) require.NoError(t, err) require.Nil(t, auth.tlsConfig.RootCAs) defer func() { @@ -91,6 +92,12 @@ func TestLDAPAuthenticator(t *testing.T) { e, ok := err.(*ldap.Error) require.True(t, ok) require.Equal(t, uint16(49), e.ResultCode) + auth.SFTPGoUserRequirements = 1 + _, err = auth.CheckUserAndPass(user1, password, "", "", []byte(`{"username":"user1"}`)) + require.Error(t, err) + assert.Contains(t, err.Error(), "LDAP users not defined in SFTPGo are not allowed") + + auth.SFTPGoUserRequirements = 0 userJSON, err := auth.CheckUserAndPass(user1, password, "", "", []byte(`{"username":"user1"}`)) require.NoError(t, err) var user sdk.User @@ -158,7 +165,8 @@ func TestLDAPAuthenticator(t *testing.T) { func TestPreserveUserChanges(t *testing.T) { auth, err := NewAuthenticator(ldapURL, baseDN, username, password, 0, false, "", 0, searchQuery, - []string{groupAttribute}, nil, primaryGroupPrefix, secondaryGroupPrefix, membershipGroupPrefix, false) + []string{groupAttribute}, nil, primaryGroupPrefix, secondaryGroupPrefix, membershipGroupPrefix, + false, 0) require.NoError(t, err) userJSON, err := auth.CheckUserAndPass(user1, password, "", "", []byte(`{"username":"user1"}`)) require.NoError(t, err) @@ -184,7 +192,8 @@ func TestPreserveUserChanges(t *testing.T) { func TestLDAPS(t *testing.T) { auth, err := NewAuthenticator(ldapsURL, baseDN, username, password, 0, true, "", 0, searchQuery, - []string{groupAttribute}, nil, primaryGroupPrefix, secondaryGroupPrefix, membershipGroupPrefix, false) + []string{groupAttribute}, nil, primaryGroupPrefix, secondaryGroupPrefix, membershipGroupPrefix, + false, 0) require.NoError(t, err) l, err := auth.connect() require.NoError(t, err) @@ -194,7 +203,8 @@ func TestLDAPS(t *testing.T) { func TestLDAPConnectionErrors(t *testing.T) { auth, err := NewAuthenticator([]string{"ldap://localhost:3892"}, baseDN, username, password, 0, true, "", 0, searchQuery, - []string{groupAttribute}, nil, primaryGroupPrefix, secondaryGroupPrefix, membershipGroupPrefix, false) + []string{groupAttribute}, nil, primaryGroupPrefix, secondaryGroupPrefix, membershipGroupPrefix, + false, 0) require.NoError(t, err) _, err = auth.CheckUserAndPass(user1, password, "", "", nil) require.Error(t, err) @@ -207,7 +217,8 @@ func TestLDAPConnectionErrors(t *testing.T) { func TestStartTLS(t *testing.T) { // glauth does not support STARTTLS auth, err := NewAuthenticator(ldapURL, baseDN, username, password, 1, true, "", 0, searchQuery, - []string{groupAttribute}, nil, primaryGroupPrefix, secondaryGroupPrefix, membershipGroupPrefix, false) + []string{groupAttribute}, nil, primaryGroupPrefix, secondaryGroupPrefix, membershipGroupPrefix, + false, 0) require.NoError(t, err) _, err = auth.connect() require.Error(t, err) @@ -217,10 +228,10 @@ func TestStartTLS(t *testing.T) { } func TestValidation(t *testing.T) { - _, err := NewAuthenticator(nil, "", "", "", 0, false, "", 0, "", nil, nil, "", "", "", false) + _, err := NewAuthenticator(nil, "", "", "", 0, false, "", 0, "", nil, nil, "", "", "", false, 0) require.Error(t, err) assert.Contains(t, err.Error(), "dial URL is required") - _, err = NewAuthenticator([]string{"", ""}, "", "", "", 0, false, "", 0, "", nil, nil, "", "", "", false) + _, err = NewAuthenticator([]string{"", ""}, "", "", "", 0, false, "", 0, "", nil, nil, "", "", "", false, 0) require.Error(t, err) assert.Contains(t, err.Error(), "dial URL is required") a := LDAPAuthenticator{ @@ -291,10 +302,14 @@ func TestUserToUpdate(t *testing.T) { }, } a := LDAPAuthenticator{ - GroupAttributes: []string{"memberOf"}, - PrimaryGroupPrefix: "sftpgo_primary", + GroupAttributes: []string{"memberOf"}, + PrimaryGroupPrefix: "sftpgo_primary", + SFTPGoUserRequirements: 1, } res := a.isUserToUpdate(u, nil) + require.False(t, res) + a.SFTPGoUserRequirements = 0 + res = a.isUserToUpdate(u, nil) require.True(t, res) u.Password = password res = a.isUserToUpdate(u, nil) @@ -347,17 +362,17 @@ func TestGetCNFromDN(t *testing.T) { func TestLoadCACerts(t *testing.T) { caCrtPath := "testcacrt" _, err := NewAuthenticator(ldapURL, baseDN, username, password, 0, true, "", 0, - searchQuery, nil, []string{caCrtPath}, "", "", "", false) + searchQuery, nil, []string{caCrtPath}, "", "", "", false, 0) require.Error(t, err) assert.Contains(t, err.Error(), "is not an absolute path") caCrtPath = filepath.Join(os.TempDir(), caCrtPath) _, err = NewAuthenticator(ldapURL, baseDN, username, password, 0, true, "", 0, - searchQuery, nil, []string{caCrtPath}, "", "", "", false) + searchQuery, nil, []string{caCrtPath}, "", "", "", false, 0) require.ErrorIs(t, err, fs.ErrNotExist) err = os.WriteFile(caCrtPath, []byte(caCRT), 0600) require.NoError(t, err) auth, err := NewAuthenticator(ldapURL, baseDN, username, password, 0, true, "", 0, - searchQuery, nil, []string{caCrtPath}, "", "", "", false) + searchQuery, nil, []string{caCrtPath}, "", "", "", false, 0) require.NoError(t, err) require.NotNil(t, auth.tlsConfig.RootCAs) err = os.Remove(caCrtPath) @@ -366,7 +381,8 @@ func TestLoadCACerts(t *testing.T) { func TestLDAPMonitor(t *testing.T) { auth, err := NewAuthenticator(multipleLDAPURLs, baseDN, username, password, 0, false, "", 2, searchQuery, - []string{groupAttribute}, nil, primaryGroupPrefix, secondaryGroupPrefix, membershipGroupPrefix, true) + []string{groupAttribute}, nil, primaryGroupPrefix, secondaryGroupPrefix, membershipGroupPrefix, + true, 0) require.NoError(t, err) defer auth.Cleanup() diff --git a/cmd/cmd.go b/cmd/cmd.go index 5b66a1e..cfa654f 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -65,6 +65,7 @@ var ( secondaryGroupPrefix string membershipGroupPrefix string requireGroupMembership bool + sftpgoUserRequirements int rootCmd = &cli.App{ Name: "sftpgo-plugin-auth", @@ -139,6 +140,12 @@ var ( Destination: &requireGroupMembership, EnvVars: []string{envPrefix + "REQUIRE_GROUPS"}, }, + &cli.IntFlag{ + Name: "user-requirements", + Usage: "Requirements for SFTPGo users. 1 means users must be already defined in SFTPGo", + Destination: &sftpgoUserRequirements, + EnvVars: []string{envPrefix + "USER_REQUIREMENTS"}, + }, &cli.IntFlag{ Name: "starttls", Usage: "STARTTLS is the preferred method of encrypting an LDAP connection. Use it instead of using the ldaps:// URL schema", @@ -176,7 +183,7 @@ var ( a, err := authenticator.NewAuthenticator(ldapURL.Value(), ldapBaseDN, ldapUsername, ldapPassword, startTLS, skipTLSVerify == 1, usersBaseDir, cacheTime, ldapSearchQuery, ldapGroupAttributes.Value(), caCertificates.Value(), primaryGroupPrefix, secondaryGroupPrefix, membershipGroupPrefix, - requireGroupMembership) + requireGroupMembership, sftpgoUserRequirements) if err != nil { logger.AppLogger.Error("unable to create the authenticator", "err", err) return err diff --git a/go.mod b/go.mod index e224536..44cf498 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/go-ldap/ldap/v3 v3.4.8 github.com/hashicorp/go-hclog v1.6.3 github.com/hashicorp/go-plugin v1.6.1 - github.com/sftpgo/sdk v0.1.7 + github.com/sftpgo/sdk v0.1.8 github.com/stretchr/testify v1.9.0 github.com/urfave/cli/v2 v2.27.2 ) @@ -26,12 +26,12 @@ require ( github.com/oklog/run v1.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect + github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect golang.org/x/crypto v0.23.0 // indirect golang.org/x/net v0.25.0 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/text v0.15.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/text v0.16.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect google.golang.org/grpc v1.64.0 // indirect google.golang.org/protobuf v1.34.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index e5e7910..2f805ea 100644 --- a/go.sum +++ b/go.sum @@ -65,8 +65,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sftpgo/sdk v0.1.7 h1:lzOKBDnKb1PpSMlskqCPxBYKxVWz34uMBhT78r/13iA= -github.com/sftpgo/sdk v0.1.7/go.mod h1:ler/KG6kMLlsOs/8s6dVN3oom+z+NkbXBVWO//Cv/WA= +github.com/sftpgo/sdk v0.1.8 h1:HAywJl9jZnigFGztA/CWLieOW+R+HH6js6o6/qYvuSY= +github.com/sftpgo/sdk v0.1.8/go.mod h1:Isl0IEzS/Muvh8Fr4X+NWFsOS/fZQHRD4oPQpoY7C4g= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -79,8 +79,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI= github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM= -github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw= -github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -121,8 +121,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -135,15 +135,15 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= -golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8 h1:mxSlqyb8ZAHsYDCfiXN1EDdNTdvjUJSLY+OnAUtYNYA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8/go.mod h1:I7Y+G38R2bu5j1aLzfFmQfTcU/WnFuqDwLZAbvKTKpM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=