Auth Method list pagination (#4165)
* wip * implement list pagination for auth methods * remove unused code * update tests to fix sorting * address PR comments * simplify query, add token tests * change test name * wip sql testing * add boolean column to indicate whether auth methods should be returned to unauthenticated users, remove secrets from api response * is_active_public not null * remove secrets and unwrapping * move not null to immediately after data migration * order public_id descending * fix(db): Fix auth method migrations (#4193) * wip * fix db tests * fix failing api tests * reverse order of create time and update time in test --------- Co-authored-by: Michael Gaffney <mike@gaffney.cc>
This commit is contained in:
1 parent
0fad770d8a
commit
8d50a0913f
34 files changed
+4340
-445
No files matched your search
@@ -216,13 +216,16 @@ func TestSelfReadingDifferentOutputFields(t *testing.T) {
|
||||
|
||||
conn := tc.DbConn()
|
||||
|
||||
s, err := authmethodsservice.NewService(tc.Context(),
|
||||
s, err := authmethodsservice.NewService(
|
||||
tc.Context(),
|
||||
tc.Kms(),
|
||||
tc.Controller().PasswordAuthRepoFn,
|
||||
tc.Controller().OidcRepoFn,
|
||||
tc.Controller().IamRepoFn,
|
||||
tc.Controller().AuthTokenRepoFn,
|
||||
tc.Controller().LdapRepoFn,
|
||||
tc.Controller().AuthMethodRepoFn,
|
||||
1000,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/db/timestamp"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
)
|
||||
|
||||
// AuthMethodListQueryResult describes the result from the
|
||||
// auth method list query used to list all auth method subtypes.
|
||||
type AuthMethodListQueryResult struct {
|
||||
// PublicId is a surrogate key suitable for use in a public API.
|
||||
PublicId string `gorm:"primary_key"`
|
||||
// The Scope Id of the scope this auth method belongs to, must be set.
|
||||
ScopeId string
|
||||
// Sets the primary subtype of the auth method.
|
||||
IsPrimaryAuthMethod bool
|
||||
// Optional name of the auth method.
|
||||
Name string
|
||||
// Optional description of the auth method.
|
||||
Description string
|
||||
// Create time of the auth method.
|
||||
CreateTime *timestamp.Timestamp
|
||||
// Update time of the auth method.
|
||||
UpdateTime *timestamp.Timestamp
|
||||
// Version of the auth method.
|
||||
Version uint32
|
||||
// Optionally set by ldap or oidc auth methods.
|
||||
State string
|
||||
Certs string
|
||||
// Optionally set by ldap auth method.
|
||||
StartTLS bool
|
||||
InsecureTLS bool
|
||||
DiscoverDn bool
|
||||
AnonGroupSearch bool
|
||||
UpnDomain string
|
||||
Urls string
|
||||
UserDn string
|
||||
UserAttr string
|
||||
UserFilter string
|
||||
EnableGroups bool
|
||||
UseTokenGroups bool
|
||||
GroupDn string
|
||||
GroupAttr string
|
||||
GroupFilter string
|
||||
ClientCertificateKeyHmac []byte
|
||||
ClientCertificateKeyId string
|
||||
ClientCertificateCert []byte
|
||||
BindDn string
|
||||
BindKeyId string
|
||||
AccountAttributeMap string
|
||||
DereferenceAliases string
|
||||
MaximumPageSize uint32
|
||||
// Optionally set by oidc auth method.
|
||||
DisableDiscoveredConfigValidation bool
|
||||
Issuer string
|
||||
ClientId string
|
||||
ClientSecretHmac string
|
||||
KeyId string
|
||||
MaxAge int
|
||||
Algs string
|
||||
ApiUrl string
|
||||
Auds string
|
||||
ClaimsScopes string
|
||||
AccountClaimMaps string
|
||||
Prompts string
|
||||
// Optionally set by password auth method.
|
||||
PasswordConfId string
|
||||
MinLoginNameLength uint32
|
||||
MinPasswordLength uint32
|
||||
// The subtype of the auth method.
|
||||
Subtype string
|
||||
}
|
||||
|
||||
func (am *AuthMethodListQueryResult) toAuthMethod(ctx context.Context) (AuthMethod, error) {
|
||||
const op = "auth.(*AuthMethodListQueryResult).toAuthMethod"
|
||||
|
||||
newFn, ok := subtypeRegistry.newFunc(globals.Subtype(am.Subtype))
|
||||
if !ok {
|
||||
return nil, errors.New(ctx,
|
||||
errors.InvalidParameter,
|
||||
op,
|
||||
fmt.Sprintf("%s is an unknown auth method subtype of %s", am.PublicId, am.Subtype),
|
||||
)
|
||||
}
|
||||
|
||||
return newFn(ctx, am)
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/db/timestamp"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -20,14 +21,17 @@ func TestDB_AuthMethodIDTrigger(t *testing.T) {
|
||||
create table if not exists test_auth_method (
|
||||
public_id wt_public_id primary key,
|
||||
scope_id wt_public_id not null references iam_scope(public_id),
|
||||
name wt_name
|
||||
name wt_name,
|
||||
create_time wt_timestamp,
|
||||
update_time wt_timestamp,
|
||||
state text
|
||||
);
|
||||
`
|
||||
insert = `
|
||||
insert into test_auth_method
|
||||
(public_id, scope_id)
|
||||
(public_id, scope_id, create_time, update_time, state)
|
||||
values
|
||||
(@public_id, @scoped_id);
|
||||
(@public_id, @scoped_id, @create_time, @update_time, @state);
|
||||
`
|
||||
addTriggers = `
|
||||
create trigger
|
||||
@@ -59,7 +63,17 @@ select count(*) from test_auth_method where public_id = @public_id
|
||||
org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
||||
|
||||
id := "l1Ocw0TpHn800CekIxIXlmQqRDgFDfYl"
|
||||
inserted, err := rw.Exec(ctx, insert, []any{sql.Named("public_id", id), sql.Named("scoped_id", org.GetPublicId())})
|
||||
inserted, err := rw.Exec(
|
||||
ctx,
|
||||
insert,
|
||||
[]any{
|
||||
sql.Named("public_id", id),
|
||||
sql.Named("scoped_id", org.GetPublicId()),
|
||||
sql.Named("create_time", timestamp.Now()),
|
||||
sql.Named("update_time", timestamp.Now()),
|
||||
sql.Named("state", "active-public"),
|
||||
},
|
||||
)
|
||||
require.NoError(err)
|
||||
require.Equal(1, inserted)
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package ldap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/auth"
|
||||
)
|
||||
|
||||
func init() {
|
||||
auth.RegisterAuthMethodSubtype("ldap", &authMethodHooks{})
|
||||
}
|
||||
|
||||
type authMethodHooks struct{}
|
||||
|
||||
// NewAuthMethod creates a new static auth method from the result
|
||||
func (authMethodHooks) NewAuthMethod(ctx context.Context, result *auth.AuthMethodListQueryResult) (auth.AuthMethod, error) {
|
||||
delimiter := "|"
|
||||
|
||||
am := AllocAuthMethod()
|
||||
am.PublicId = result.PublicId
|
||||
am.ScopeId = result.ScopeId
|
||||
am.IsPrimaryAuthMethod = result.IsPrimaryAuthMethod
|
||||
am.Name = result.Name
|
||||
am.Description = result.Description
|
||||
am.CreateTime = result.CreateTime
|
||||
am.UpdateTime = result.UpdateTime
|
||||
am.Version = result.Version
|
||||
am.OperationalState = result.State
|
||||
am.StartTls = result.StartTLS
|
||||
am.InsecureTls = result.InsecureTLS
|
||||
am.DiscoverDn = result.DiscoverDn
|
||||
am.AnonGroupSearch = result.AnonGroupSearch
|
||||
am.EnableGroups = result.EnableGroups
|
||||
am.UseTokenGroups = result.UseTokenGroups
|
||||
am.UpnDomain = result.UpnDomain
|
||||
if result.Urls != "" {
|
||||
am.Urls = strings.Split(result.Urls, delimiter)
|
||||
}
|
||||
if result.Certs != "" {
|
||||
am.Certificates = strings.Split(result.Certs, delimiter)
|
||||
}
|
||||
am.UserDn = result.UserDn
|
||||
am.UserAttr = result.UserAttr
|
||||
am.UserFilter = result.UserFilter
|
||||
am.GroupDn = result.GroupDn
|
||||
am.GroupAttr = result.GroupAttr
|
||||
am.GroupFilter = result.GroupFilter
|
||||
am.ClientCertificateKeyHmac = result.ClientCertificateKeyHmac
|
||||
am.ClientCertificate = string(result.ClientCertificateCert)
|
||||
am.BindDn = result.BindDn
|
||||
if result.AccountAttributeMap != "" {
|
||||
am.AccountAttributeMaps = strings.Split(result.AccountAttributeMap, delimiter)
|
||||
}
|
||||
am.DereferenceAliases = result.DereferenceAliases
|
||||
am.MaximumPageSize = result.MaximumPageSize
|
||||
|
||||
return &am, nil
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package oidc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/auth"
|
||||
)
|
||||
|
||||
func init() {
|
||||
auth.RegisterAuthMethodSubtype("oidc", &authMethodHooks{})
|
||||
}
|
||||
|
||||
type authMethodHooks struct{}
|
||||
|
||||
// NewAuthMethod creates a new oidc auth method from the result
|
||||
func (authMethodHooks) NewAuthMethod(ctx context.Context, result *auth.AuthMethodListQueryResult) (auth.AuthMethod, error) {
|
||||
delimiter := "|"
|
||||
|
||||
am := AllocAuthMethod()
|
||||
am.PublicId = result.PublicId
|
||||
am.ScopeId = result.ScopeId
|
||||
am.IsPrimaryAuthMethod = result.IsPrimaryAuthMethod
|
||||
am.Name = result.Name
|
||||
am.Description = result.Description
|
||||
am.CreateTime = result.CreateTime
|
||||
am.UpdateTime = result.UpdateTime
|
||||
am.Version = result.Version
|
||||
am.OperationalState = result.State
|
||||
am.DisableDiscoveredConfigValidation = result.DisableDiscoveredConfigValidation
|
||||
am.Issuer = result.Issuer
|
||||
am.ClientId = result.ClientId
|
||||
am.ClientSecretHmac = result.ClientSecretHmac
|
||||
am.KeyId = result.KeyId
|
||||
am.MaxAge = int32(result.MaxAge)
|
||||
am.ApiUrl = result.ApiUrl
|
||||
if result.Algs != "" {
|
||||
am.SigningAlgs = strings.Split(result.Algs, delimiter)
|
||||
}
|
||||
if result.Auds != "" {
|
||||
am.AudClaims = strings.Split(result.Auds, delimiter)
|
||||
}
|
||||
if result.Certs != "" {
|
||||
am.Certificates = strings.Split(result.Certs, delimiter)
|
||||
}
|
||||
if result.ClaimsScopes != "" {
|
||||
am.ClaimsScopes = strings.Split(result.ClaimsScopes, delimiter)
|
||||
}
|
||||
if result.AccountClaimMaps != "" {
|
||||
am.AccountClaimMaps = strings.Split(result.AccountClaimMaps, delimiter)
|
||||
}
|
||||
if result.Prompts != "" {
|
||||
am.Prompts = strings.Split(result.Prompts, delimiter)
|
||||
}
|
||||
|
||||
return &am, nil
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/pagination"
|
||||
)
|
||||
|
||||
// The option type is how options are passed as arugments
|
||||
type Option func(*Options) error
|
||||
|
||||
// Options is a struct that contains all the possible auth options
|
||||
type Options struct {
|
||||
WithLimit int
|
||||
WithStartPageAfterItem pagination.Item
|
||||
WithUnauthenticatedUser bool
|
||||
}
|
||||
|
||||
// getDefaultOptions returns a new Options struct
|
||||
func getDefaultOptions() *Options {
|
||||
return &Options{}
|
||||
}
|
||||
|
||||
// GetOpts loops over the options and provides
|
||||
// the configured options struct
|
||||
func GetOpts(opts ...Option) (*Options, error) {
|
||||
newOpts := getDefaultOptions()
|
||||
for _, opt := range opts {
|
||||
if err := opt(newOpts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return newOpts, nil
|
||||
}
|
||||
|
||||
// WithLimit provides an option to provide a limit.
|
||||
// If WithLimit <= 0, then default limits are used for results.
|
||||
func WithLimit(_ context.Context, l int) Option {
|
||||
return func(o *Options) error {
|
||||
o.WithLimit = l
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithStartPageAfterItem is used to paginate over the results.
|
||||
// The next page will start after the provided item.
|
||||
func WithStartPageAfterItem(_ context.Context, item pagination.Item) Option {
|
||||
return func(o *Options) error {
|
||||
o.WithStartPageAfterItem = item
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithUnauthenticatedUser provides an option for filtering results for
|
||||
// an unauthenticated users.
|
||||
func WithUnauthenticatedUser(_ context.Context, enabled bool) Option {
|
||||
return func(o *Options) error {
|
||||
o.WithUnauthenticatedUser = enabled
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/db/timestamp"
|
||||
"github.com/hashicorp/boundary/internal/pagination"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type fakeItem struct {
|
||||
pagination.Item
|
||||
publicId string
|
||||
createTime time.Time
|
||||
updateTime time.Time
|
||||
}
|
||||
|
||||
func (p *fakeItem) GetPublicId() string {
|
||||
return p.publicId
|
||||
}
|
||||
|
||||
func (p *fakeItem) GetUpdateTime() *timestamp.Timestamp {
|
||||
return timestamp.New(p.updateTime)
|
||||
}
|
||||
|
||||
func (p *fakeItem) GetCreateTime() *timestamp.Timestamp {
|
||||
return timestamp.New(p.createTime)
|
||||
}
|
||||
|
||||
// Test_GetOpts provides unit tests for GetOpts and all the options
|
||||
func Test_GetOpts(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("WithLimit", func(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
opts, err := GetOpts()
|
||||
require.NoError(t, err)
|
||||
testOpts := getDefaultOptions()
|
||||
testOpts.WithLimit = 0
|
||||
assert.Equal(t, opts, testOpts)
|
||||
|
||||
opts, err = GetOpts(WithLimit(ctx, -1))
|
||||
require.NoError(t, err)
|
||||
testOpts = getDefaultOptions()
|
||||
testOpts.WithLimit = -1
|
||||
assert.Equal(t, opts, testOpts)
|
||||
|
||||
opts, err = GetOpts(WithLimit(ctx, 1))
|
||||
require.NoError(t, err)
|
||||
testOpts = getDefaultOptions()
|
||||
testOpts.WithLimit = 1
|
||||
assert.Equal(t, opts, testOpts)
|
||||
})
|
||||
t.Run("WithReaderWriter", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := GetOpts()
|
||||
require.NoError(t, err)
|
||||
})
|
||||
})
|
||||
t.Run("WithStartPageAfterItem", func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
updateTime := time.Now()
|
||||
createTime := time.Now()
|
||||
opts, err := GetOpts(WithStartPageAfterItem(context.Background(), &fakeItem{nil, "s_1", createTime, updateTime}))
|
||||
require.NoError(t, err)
|
||||
assert.Equal(opts.WithStartPageAfterItem.GetPublicId(), "s_1")
|
||||
assert.Equal(opts.WithStartPageAfterItem.GetUpdateTime(), timestamp.New(updateTime))
|
||||
assert.Equal(opts.WithStartPageAfterItem.GetCreateTime(), timestamp.New(createTime))
|
||||
})
|
||||
t.Run("WithUnauthenticatedUser", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
opts, err := GetOpts(WithUnauthenticatedUser(ctx, true))
|
||||
require.NoError(t, err)
|
||||
assert.True(t, opts.WithUnauthenticatedUser)
|
||||
})
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package password
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/auth"
|
||||
)
|
||||
|
||||
func init() {
|
||||
auth.RegisterAuthMethodSubtype("password", &authMethodHooks{})
|
||||
}
|
||||
|
||||
type authMethodHooks struct{}
|
||||
|
||||
// NewAuthMethod creates a new static auth method from the result
|
||||
func (authMethodHooks) NewAuthMethod(ctx context.Context, result *auth.AuthMethodListQueryResult) (auth.AuthMethod, error) {
|
||||
am := allocAuthMethod()
|
||||
am.PublicId = result.PublicId
|
||||
am.ScopeId = result.ScopeId
|
||||
am.IsPrimaryAuthMethod = result.IsPrimaryAuthMethod
|
||||
am.CreateTime = result.CreateTime
|
||||
am.UpdateTime = result.UpdateTime
|
||||
am.Name = result.Name
|
||||
am.Description = result.Description
|
||||
am.Version = result.Version
|
||||
am.PasswordConfId = result.PasswordConfId
|
||||
am.MinLoginNameLength = result.MinLoginNameLength
|
||||
am.MinPasswordLength = result.MinPasswordLength
|
||||
|
||||
return &am, nil
|
||||
}
|
||||
@@ -0,0 +1,808 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package auth
|
||||
|
||||
const (
|
||||
estimateCountAuthMethodsQuery = `
|
||||
select sum(reltuples::bigint) as estimate from pg_class where oid in (
|
||||
'auth_password_method'::regclass,
|
||||
'auth_ldap_method'::regclass,
|
||||
'auth_oidc_method'::regclass
|
||||
)
|
||||
`
|
||||
|
||||
listDeletedIdsQuery = `
|
||||
select public_id
|
||||
from auth_password_method_deleted
|
||||
where delete_time >= @since
|
||||
union
|
||||
select public_id
|
||||
from auth_oidc_method_deleted
|
||||
where delete_time >= @since
|
||||
union
|
||||
select public_id
|
||||
from auth_ldap_method_deleted
|
||||
where delete_time >= @since
|
||||
`
|
||||
|
||||
listAuthMethodsTemplate = `
|
||||
with auth_methods as (
|
||||
select public_id
|
||||
from auth_method
|
||||
where %s -- search condition for scope IDs is constructed
|
||||
order by create_time desc, public_id desc
|
||||
limit %d
|
||||
),
|
||||
ldap as (
|
||||
select *
|
||||
from ldap_auth_method_with_value_obj
|
||||
where public_id in (select public_id from auth_methods)
|
||||
),
|
||||
oidc as (
|
||||
select *
|
||||
from oidc_auth_method_with_value_obj
|
||||
where public_id in (select public_id from auth_methods)
|
||||
),
|
||||
password as (
|
||||
select *
|
||||
from auth_password_method_with_is_primary
|
||||
where public_id in (select public_id from auth_methods)
|
||||
),
|
||||
final as (
|
||||
select public_id,
|
||||
scope_id,
|
||||
is_primary_auth_method,
|
||||
name,
|
||||
description,
|
||||
create_time,
|
||||
update_time,
|
||||
version,
|
||||
state,
|
||||
start_tls,
|
||||
insecure_tls,
|
||||
discover_dn,
|
||||
anon_group_search,
|
||||
upn_domain,
|
||||
enable_groups,
|
||||
use_token_groups,
|
||||
maximum_page_size,
|
||||
urls,
|
||||
certs,
|
||||
account_attribute_map,
|
||||
user_dn,
|
||||
user_attr,
|
||||
user_filter,
|
||||
group_dn,
|
||||
group_attr,
|
||||
group_filter,
|
||||
client_certificate_key,
|
||||
client_certificate_key_hmac,
|
||||
client_certificate_key_id,
|
||||
client_certificate_cert,
|
||||
bind_dn,
|
||||
bind_password,
|
||||
bind_password_hmac,
|
||||
bind_password_key_id,
|
||||
dereference_aliases,
|
||||
null as disable_discovered_config_validation, -- Add to make union uniform
|
||||
null as api_url,
|
||||
null as issuer,
|
||||
null as client_id,
|
||||
null as client_secret,
|
||||
null as client_secret_hmac,
|
||||
null as key_id,
|
||||
null as max_age,
|
||||
null as algs,
|
||||
null as auds,
|
||||
null as certs,
|
||||
null as claims_scopes,
|
||||
null as prompts,
|
||||
null as account_claim_maps,
|
||||
null as password_conf_id,
|
||||
null::integer as min_login_name_length,
|
||||
null::integer as min_password_length,
|
||||
'ldap' as subtype
|
||||
from ldap
|
||||
union
|
||||
select public_id,
|
||||
scope_id,
|
||||
is_primary_auth_method,
|
||||
name,
|
||||
description,
|
||||
create_time,
|
||||
update_time,
|
||||
version,
|
||||
state,
|
||||
null as start_tls, -- Add to make union uniform
|
||||
null as insecure_tls,
|
||||
null as discover_dn,
|
||||
null as anon_group_search,
|
||||
null as upn_domain,
|
||||
null as enable_groups,
|
||||
null as use_token_groups,
|
||||
null as maximum_page_size,
|
||||
null as urls,
|
||||
null as certs,
|
||||
null as account_attribute_map,
|
||||
null as user_dn,
|
||||
null as user_attr,
|
||||
null as user_filter,
|
||||
null as group_dn,
|
||||
null as group_attr,
|
||||
null as group_filter,
|
||||
null as client_certificate_key,
|
||||
null as client_certificate_key_hmac,
|
||||
null as client_certificate_key_id,
|
||||
null as client_certificate_cert,
|
||||
null as bind_dn,
|
||||
null as bind_password,
|
||||
null as bind_password_hmac,
|
||||
null as bind_password_key_id,
|
||||
null as dereference_aliases,
|
||||
disable_discovered_config_validation,
|
||||
api_url,
|
||||
issuer,
|
||||
client_id,
|
||||
client_secret,
|
||||
client_secret_hmac,
|
||||
key_id,
|
||||
max_age,
|
||||
algs,
|
||||
auds,
|
||||
certs,
|
||||
claims_scopes,
|
||||
prompts,
|
||||
account_claim_maps,
|
||||
null as password_conf_id,
|
||||
null::integer as min_login_name_length,
|
||||
null::integer as min_password_length,
|
||||
'oidc' as subtype
|
||||
from oidc
|
||||
union
|
||||
select public_id,
|
||||
scope_id,
|
||||
is_primary_auth_method,
|
||||
name,
|
||||
description,
|
||||
create_time,
|
||||
update_time,
|
||||
version,
|
||||
null as state, -- Add to make union uniform
|
||||
null as start_tls,
|
||||
null as insecure_tls,
|
||||
null as discover_dn,
|
||||
null as anon_group_search,
|
||||
null as upn_domain,
|
||||
null as enable_groups,
|
||||
null as use_token_groups,
|
||||
null as maximum_page_size,
|
||||
null as urls,
|
||||
null as certs,
|
||||
null as account_attribute_map,
|
||||
null as user_dn,
|
||||
null as user_attr,
|
||||
null as user_filter,
|
||||
null as group_dn,
|
||||
null as group_attr,
|
||||
null as group_filter,
|
||||
null as client_certificate_key,
|
||||
null as client_certificate_key_hmac,
|
||||
null as client_certificate_key_id,
|
||||
null as client_certificate_cert,
|
||||
null as bind_dn,
|
||||
null as bind_password,
|
||||
null as bind_password_hmac,
|
||||
null as bind_password_key_id,
|
||||
null as dereference_aliases,
|
||||
null as disable_discovered_config_validation,
|
||||
null as api_url,
|
||||
null as issuer,
|
||||
null as client_id,
|
||||
null as client_secret,
|
||||
null as client_secret_hmac,
|
||||
null as key_id,
|
||||
null as max_age,
|
||||
null as algs,
|
||||
null as auds,
|
||||
null as certs,
|
||||
null as claims_scopes,
|
||||
null as prompts,
|
||||
null as account_claim_maps,
|
||||
password_conf_id,
|
||||
min_login_name_length,
|
||||
min_password_length,
|
||||
'password' as subtype
|
||||
from password
|
||||
)
|
||||
select *
|
||||
from final
|
||||
order by create_time desc, public_id desc;
|
||||
`
|
||||
|
||||
listAuthMethodsPageTemplate = `
|
||||
with auth_methods as (
|
||||
select public_id
|
||||
from auth_method
|
||||
where (create_time, public_id) < (@last_item_create_time, @last_item_id)
|
||||
and %s -- search condition for scope IDs is constructed
|
||||
order by create_time desc, public_id desc
|
||||
limit %d
|
||||
),
|
||||
ldap as (
|
||||
select *
|
||||
from ldap_auth_method_with_value_obj
|
||||
where public_id in (select public_id from auth_methods)
|
||||
),
|
||||
oidc as (
|
||||
select *
|
||||
from oidc_auth_method_with_value_obj
|
||||
where public_id in (select public_id from auth_methods)
|
||||
),
|
||||
password as (
|
||||
select *
|
||||
from auth_password_method_with_is_primary
|
||||
where public_id in (select public_id from auth_methods)
|
||||
),
|
||||
final as (
|
||||
select public_id,
|
||||
scope_id,
|
||||
is_primary_auth_method,
|
||||
name,
|
||||
description,
|
||||
create_time,
|
||||
update_time,
|
||||
version,
|
||||
state,
|
||||
start_tls,
|
||||
insecure_tls,
|
||||
discover_dn,
|
||||
anon_group_search,
|
||||
upn_domain,
|
||||
enable_groups,
|
||||
use_token_groups,
|
||||
maximum_page_size,
|
||||
urls,
|
||||
certs,
|
||||
account_attribute_map,
|
||||
user_dn,
|
||||
user_attr,
|
||||
user_filter,
|
||||
group_dn,
|
||||
group_attr,
|
||||
group_filter,
|
||||
client_certificate_key,
|
||||
client_certificate_key_hmac,
|
||||
client_certificate_key_id,
|
||||
client_certificate_cert,
|
||||
bind_dn,
|
||||
bind_password,
|
||||
bind_password_hmac,
|
||||
bind_password_key_id,
|
||||
dereference_aliases,
|
||||
null as disable_discovered_config_validation, -- Add to make union uniform
|
||||
null as api_url,
|
||||
null as issuer,
|
||||
null as client_id,
|
||||
null as client_secret,
|
||||
null as client_secret_hmac,
|
||||
null as key_id,
|
||||
null as max_age,
|
||||
null as algs,
|
||||
null as auds,
|
||||
null as certs,
|
||||
null as claims_scopes,
|
||||
null as prompts,
|
||||
null as account_claim_maps,
|
||||
null as password_conf_id,
|
||||
null::integer as min_login_name_length,
|
||||
null::integer as min_password_length,
|
||||
'ldap' as subtype
|
||||
from ldap
|
||||
union
|
||||
select public_id,
|
||||
scope_id,
|
||||
is_primary_auth_method,
|
||||
name,
|
||||
description,
|
||||
create_time,
|
||||
update_time,
|
||||
version,
|
||||
state,
|
||||
null as start_tls, -- Add to make union uniform
|
||||
null as insecure_tls,
|
||||
null as discover_dn,
|
||||
null as anon_group_search,
|
||||
null as upn_domain,
|
||||
null as enable_groups,
|
||||
null as use_token_groups,
|
||||
null as maximum_page_size,
|
||||
null as urls,
|
||||
null as certs,
|
||||
null as account_attribute_map,
|
||||
null as user_dn,
|
||||
null as user_attr,
|
||||
null as user_filter,
|
||||
null as group_dn,
|
||||
null as group_attr,
|
||||
null as group_filter,
|
||||
null as client_certificate_key,
|
||||
null as client_certificate_key_hmac,
|
||||
null as client_certificate_key_id,
|
||||
null as client_certificate_cert,
|
||||
null as bind_dn,
|
||||
null as bind_password,
|
||||
null as bind_password_hmac,
|
||||
null as bind_password_key_id,
|
||||
null as dereference_aliases,
|
||||
disable_discovered_config_validation,
|
||||
api_url,
|
||||
issuer,
|
||||
client_id,
|
||||
client_secret,
|
||||
client_secret_hmac,
|
||||
key_id,
|
||||
max_age,
|
||||
algs,
|
||||
auds,
|
||||
certs,
|
||||
claims_scopes,
|
||||
prompts,
|
||||
account_claim_maps,
|
||||
null as password_conf_id,
|
||||
null::integer as min_login_name_length,
|
||||
null::integer as min_password_length,
|
||||
'oidc' as subtype
|
||||
from oidc
|
||||
union
|
||||
select public_id,
|
||||
scope_id,
|
||||
is_primary_auth_method,
|
||||
name,
|
||||
description,
|
||||
create_time,
|
||||
update_time,
|
||||
version,
|
||||
null as state, -- Add to make union uniform
|
||||
null as start_tls,
|
||||
null as insecure_tls,
|
||||
null as discover_dn,
|
||||
null as anon_group_search,
|
||||
null as upn_domain,
|
||||
null as enable_groups,
|
||||
null as use_token_groups,
|
||||
null as maximum_page_size,
|
||||
null as urls,
|
||||
null as certs,
|
||||
null as account_attribute_map,
|
||||
null as user_dn,
|
||||
null as user_attr,
|
||||
null as user_filter,
|
||||
null as group_dn,
|
||||
null as group_attr,
|
||||
null as group_filter,
|
||||
null as client_certificate_key,
|
||||
null as client_certificate_key_hmac,
|
||||
null as client_certificate_key_id,
|
||||
null as client_certificate_cert,
|
||||
null as bind_dn,
|
||||
null as bind_password,
|
||||
null as bind_password_hmac,
|
||||
null as bind_password_key_id,
|
||||
null as dereference_aliases,
|
||||
null as disable_discovered_config_validation,
|
||||
null as api_url,
|
||||
null as issuer,
|
||||
null as client_id,
|
||||
null as client_secret,
|
||||
null as client_secret_hmac,
|
||||
null as key_id,
|
||||
null as max_age,
|
||||
null as algs,
|
||||
null as auds,
|
||||
null as certs,
|
||||
null as claims_scopes,
|
||||
null as prompts,
|
||||
null as account_claim_maps,
|
||||
password_conf_id,
|
||||
min_login_name_length,
|
||||
min_password_length,
|
||||
'password' as subtype
|
||||
from password
|
||||
)
|
||||
select *
|
||||
from final
|
||||
order by create_time desc, public_id desc;
|
||||
`
|
||||
|
||||
listAuthMethodsRefreshTemplate = `
|
||||
with auth_methods as (
|
||||
select public_id
|
||||
from auth_method
|
||||
where update_time > @updated_after_time
|
||||
and %s -- search condition for scope IDs is constructed
|
||||
order by update_time desc, public_id desc
|
||||
limit %d
|
||||
),
|
||||
ldap as (
|
||||
select *
|
||||
from ldap_auth_method_with_value_obj
|
||||
where public_id in (select public_id from auth_methods)
|
||||
),
|
||||
oidc as (
|
||||
select *
|
||||
from oidc_auth_method_with_value_obj
|
||||
where public_id in (select public_id from auth_methods)
|
||||
),
|
||||
password as (
|
||||
select *
|
||||
from auth_password_method_with_is_primary
|
||||
where public_id in (select public_id from auth_methods)
|
||||
),
|
||||
final as (
|
||||
select public_id,
|
||||
scope_id,
|
||||
is_primary_auth_method,
|
||||
name,
|
||||
description,
|
||||
create_time,
|
||||
update_time,
|
||||
version,
|
||||
state,
|
||||
start_tls,
|
||||
insecure_tls,
|
||||
discover_dn,
|
||||
anon_group_search,
|
||||
upn_domain,
|
||||
enable_groups,
|
||||
use_token_groups,
|
||||
maximum_page_size,
|
||||
urls,
|
||||
certs,
|
||||
account_attribute_map,
|
||||
user_dn,
|
||||
user_attr,
|
||||
user_filter,
|
||||
group_dn,
|
||||
group_attr,
|
||||
group_filter,
|
||||
client_certificate_key,
|
||||
client_certificate_key_hmac,
|
||||
client_certificate_key_id,
|
||||
client_certificate_cert,
|
||||
bind_dn,
|
||||
bind_password,
|
||||
bind_password_hmac,
|
||||
bind_password_key_id,
|
||||
dereference_aliases,
|
||||
null as disable_discovered_config_validation, -- Add to make union uniform
|
||||
null as api_url,
|
||||
null as issuer,
|
||||
null as client_id,
|
||||
null as client_secret,
|
||||
null as client_secret_hmac,
|
||||
null as key_id,
|
||||
null as max_age,
|
||||
null as algs,
|
||||
null as auds,
|
||||
null as certs,
|
||||
null as claims_scopes,
|
||||
null as prompts,
|
||||
null as account_claim_maps,
|
||||
null as password_conf_id,
|
||||
null::integer as min_login_name_length,
|
||||
null::integer as min_password_length,
|
||||
'ldap' as subtype
|
||||
from ldap
|
||||
union
|
||||
select public_id,
|
||||
scope_id,
|
||||
is_primary_auth_method,
|
||||
name,
|
||||
description,
|
||||
create_time,
|
||||
update_time,
|
||||
version,
|
||||
state,
|
||||
null as start_tls, -- Add to make union uniform
|
||||
null as insecure_tls,
|
||||
null as discover_dn,
|
||||
null as anon_group_search,
|
||||
null as upn_domain,
|
||||
null as enable_groups,
|
||||
null as use_token_groups,
|
||||
null as maximum_page_size,
|
||||
null as urls,
|
||||
null as certs,
|
||||
null as account_attribute_map,
|
||||
null as user_dn,
|
||||
null as user_attr,
|
||||
null as user_filter,
|
||||
null as group_dn,
|
||||
null as group_attr,
|
||||
null as group_filter,
|
||||
null as client_certificate_key,
|
||||
null as client_certificate_key_hmac,
|
||||
null as client_certificate_key_id,
|
||||
null as client_certificate_cert,
|
||||
null as bind_dn,
|
||||
null as bind_password,
|
||||
null as bind_password_hmac,
|
||||
null as bind_password_key_id,
|
||||
null as dereference_aliases,
|
||||
disable_discovered_config_validation,
|
||||
api_url,
|
||||
issuer,
|
||||
client_id,
|
||||
client_secret,
|
||||
client_secret_hmac,
|
||||
key_id,
|
||||
max_age,
|
||||
algs,
|
||||
auds,
|
||||
certs,
|
||||
claims_scopes,
|
||||
prompts,
|
||||
account_claim_maps,
|
||||
null as password_conf_id,
|
||||
null::integer as min_login_name_length,
|
||||
null::integer as min_password_length,
|
||||
'oidc' as subtype
|
||||
from oidc
|
||||
union
|
||||
select public_id,
|
||||
scope_id,
|
||||
is_primary_auth_method,
|
||||
name,
|
||||
description,
|
||||
create_time,
|
||||
update_time,
|
||||
version,
|
||||
null as state, -- Add to make union uniform
|
||||
null as start_tls,
|
||||
null as insecure_tls,
|
||||
null as discover_dn,
|
||||
null as anon_group_search,
|
||||
null as upn_domain,
|
||||
null as enable_groups,
|
||||
null as use_token_groups,
|
||||
null as maximum_page_size,
|
||||
null as urls,
|
||||
null as certs,
|
||||
null as account_attribute_map,
|
||||
null as user_dn,
|
||||
null as user_attr,
|
||||
null as user_filter,
|
||||
null as group_dn,
|
||||
null as group_attr,
|
||||
null as group_filter,
|
||||
null as client_certificate_key,
|
||||
null as client_certificate_key_hmac,
|
||||
null as client_certificate_key_id,
|
||||
null as client_certificate_cert,
|
||||
null as bind_dn,
|
||||
null as bind_password,
|
||||
null as bind_password_hmac,
|
||||
null as bind_password_key_id,
|
||||
null as dereference_aliases,
|
||||
null as disable_discovered_config_validation,
|
||||
null as api_url,
|
||||
null as issuer,
|
||||
null as client_id,
|
||||
null as client_secret,
|
||||
null as client_secret_hmac,
|
||||
null as key_id,
|
||||
null as max_age,
|
||||
null as algs,
|
||||
null as auds,
|
||||
null as certs,
|
||||
null as claims_scopes,
|
||||
null as prompts,
|
||||
null as account_claim_maps,
|
||||
password_conf_id,
|
||||
min_login_name_length,
|
||||
min_password_length,
|
||||
'password' as subtype
|
||||
from password
|
||||
)
|
||||
select *
|
||||
from final
|
||||
order by update_time desc, public_id desc;
|
||||
`
|
||||
|
||||
listAuthMethodsRefreshPageTemplate = `
|
||||
with auth_methods as (
|
||||
select public_id
|
||||
from auth_method
|
||||
where update_time > @updated_after_time
|
||||
and (update_time, public_id) < (@last_item_update_time, @last_item_id)
|
||||
and %s -- search condition for scope IDs is constructed
|
||||
order by update_time desc, public_id desc
|
||||
limit %d
|
||||
),
|
||||
ldap as (
|
||||
select *
|
||||
from ldap_auth_method_with_value_obj
|
||||
where public_id in (select public_id from auth_methods)
|
||||
),
|
||||
oidc as (
|
||||
select *
|
||||
from oidc_auth_method_with_value_obj
|
||||
where public_id in (select public_id from auth_methods)
|
||||
),
|
||||
password as (
|
||||
select *
|
||||
from auth_password_method_with_is_primary
|
||||
where public_id in (select public_id from auth_methods)
|
||||
),
|
||||
final as (
|
||||
select public_id,
|
||||
scope_id,
|
||||
is_primary_auth_method,
|
||||
name,
|
||||
description,
|
||||
create_time,
|
||||
update_time,
|
||||
version,
|
||||
state,
|
||||
start_tls,
|
||||
insecure_tls,
|
||||
discover_dn,
|
||||
anon_group_search,
|
||||
upn_domain,
|
||||
enable_groups,
|
||||
use_token_groups,
|
||||
maximum_page_size,
|
||||
urls,
|
||||
certs,
|
||||
account_attribute_map,
|
||||
user_dn,
|
||||
user_attr,
|
||||
user_filter,
|
||||
group_dn,
|
||||
group_attr,
|
||||
group_filter,
|
||||
client_certificate_key,
|
||||
client_certificate_key_hmac,
|
||||
client_certificate_key_id,
|
||||
client_certificate_cert,
|
||||
bind_dn,
|
||||
bind_password,
|
||||
bind_password_hmac,
|
||||
bind_password_key_id,
|
||||
dereference_aliases,
|
||||
null as disable_discovered_config_validation, -- Add to make union uniform
|
||||
null as api_url,
|
||||
null as issuer,
|
||||
null as client_id,
|
||||
null as client_secret,
|
||||
null as client_secret_hmac,
|
||||
null as key_id,
|
||||
null as max_age,
|
||||
null as algs,
|
||||
null as auds,
|
||||
null as certs,
|
||||
null as claims_scopes,
|
||||
null as prompts,
|
||||
null as account_claim_maps,
|
||||
null as password_conf_id,
|
||||
null::integer as min_login_name_length,
|
||||
null::integer as min_password_length,
|
||||
'ldap' as subtype
|
||||
from ldap
|
||||
union
|
||||
select public_id,
|
||||
scope_id,
|
||||
is_primary_auth_method,
|
||||
name,
|
||||
description,
|
||||
create_time,
|
||||
update_time,
|
||||
version,
|
||||
state,
|
||||
null as start_tls, -- Add to make union uniform
|
||||
null as insecure_tls,
|
||||
null as discover_dn,
|
||||
null as anon_group_search,
|
||||
null as upn_domain,
|
||||
null as enable_groups,
|
||||
null as use_token_groups,
|
||||
null as maximum_page_size,
|
||||
null as urls,
|
||||
null as certs,
|
||||
null as account_attribute_map,
|
||||
null as user_dn,
|
||||
null as user_attr,
|
||||
null as user_filter,
|
||||
null as group_dn,
|
||||
null as group_attr,
|
||||
null as group_filter,
|
||||
null as client_certificate_key,
|
||||
null as client_certificate_key_hmac,
|
||||
null as client_certificate_key_id,
|
||||
null as client_certificate_cert,
|
||||
null as bind_dn,
|
||||
null as bind_password,
|
||||
null as bind_password_hmac,
|
||||
null as bind_password_key_id,
|
||||
null as dereference_aliases,
|
||||
disable_discovered_config_validation,
|
||||
api_url,
|
||||
issuer,
|
||||
client_id,
|
||||
client_secret,
|
||||
client_secret_hmac,
|
||||
key_id,
|
||||
max_age,
|
||||
algs,
|
||||
auds,
|
||||
certs,
|
||||
claims_scopes,
|
||||
prompts,
|
||||
account_claim_maps,
|
||||
null as password_conf_id,
|
||||
null::integer as min_login_name_length,
|
||||
null::integer as min_password_length,
|
||||
'oidc' as subtype
|
||||
from oidc
|
||||
union
|
||||
select public_id,
|
||||
scope_id,
|
||||
is_primary_auth_method,
|
||||
name,
|
||||
description,
|
||||
create_time,
|
||||
update_time,
|
||||
version,
|
||||
null as state, -- Add to make union uniform
|
||||
null as start_tls,
|
||||
null as insecure_tls,
|
||||
null as discover_dn,
|
||||
null as anon_group_search,
|
||||
null as upn_domain,
|
||||
null as enable_groups,
|
||||
null as use_token_groups,
|
||||
null as maximum_page_size,
|
||||
null as urls,
|
||||
null as certs,
|
||||
null as account_attribute_map,
|
||||
null as user_dn,
|
||||
null as user_attr,
|
||||
null as user_filter,
|
||||
null as group_dn,
|
||||
null as group_attr,
|
||||
null as group_filter,
|
||||
null as client_certificate_key,
|
||||
null as client_certificate_key_hmac,
|
||||
null as client_certificate_key_id,
|
||||
null as client_certificate_cert,
|
||||
null as bind_dn,
|
||||
null as bind_password,
|
||||
null as bind_password_hmac,
|
||||
null as bind_password_key_id,
|
||||
null as dereference_aliases,
|
||||
null as disable_discovered_config_validation,
|
||||
null as api_url,
|
||||
null as issuer,
|
||||
null as client_id,
|
||||
null as client_secret,
|
||||
null as client_secret_hmac,
|
||||
null as key_id,
|
||||
null as max_age,
|
||||
null as algs,
|
||||
null as auds,
|
||||
null as certs,
|
||||
null as claims_scopes,
|
||||
null as prompts,
|
||||
null as account_claim_maps,
|
||||
password_conf_id,
|
||||
min_login_name_length,
|
||||
min_password_length,
|
||||
'password' as subtype
|
||||
from password
|
||||
)
|
||||
select *
|
||||
from final
|
||||
order by update_time desc, public_id desc;
|
||||
`
|
||||
)
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
)
|
||||
|
||||
// newAuthMethodFunc is a function that creates an AuthMethod from the provided result.
|
||||
type newAuthMethodFunc func(context.Context, *AuthMethodListQueryResult) (AuthMethod, error)
|
||||
|
||||
// AuthMethodSubtypeHooks defines the interface expected to be implemented
|
||||
// by auth method subtype hooks.
|
||||
type AuthMethodSubtypeHooks interface {
|
||||
NewAuthMethod(context.Context, *AuthMethodListQueryResult) (AuthMethod, error)
|
||||
}
|
||||
|
||||
type registry struct {
|
||||
m map[globals.Subtype]AuthMethodSubtypeHooks
|
||||
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
func (r *registry) set(s globals.Subtype, subtype AuthMethodSubtypeHooks) {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
_, previouslySet := r.m[s]
|
||||
if previouslySet {
|
||||
panic(fmt.Sprintf("auth method subtype %s already registered", s))
|
||||
}
|
||||
|
||||
r.m[s] = subtype
|
||||
}
|
||||
|
||||
func (r *registry) get(s globals.Subtype) (AuthMethodSubtypeHooks, bool) {
|
||||
r.RLock()
|
||||
defer r.RUnlock()
|
||||
|
||||
subtype, ok := r.m[s]
|
||||
if ok {
|
||||
return subtype, ok
|
||||
}
|
||||
return nil, ok
|
||||
}
|
||||
|
||||
func (r *registry) newFunc(s globals.Subtype) (newAuthMethodFunc, bool) {
|
||||
subtype, ok := r.get(s)
|
||||
if !ok {
|
||||
return nil, ok
|
||||
}
|
||||
return subtype.NewAuthMethod, ok
|
||||
}
|
||||
|
||||
var subtypeRegistry = registry{
|
||||
m: make(map[globals.Subtype]AuthMethodSubtypeHooks),
|
||||
}
|
||||
|
||||
// RegisterAuthMethodSubtype registers repository hooks for a provided auth method sub type.
|
||||
// RegisterAuthMethodSubtype panics if the subtype has already been registered.
|
||||
func RegisterAuthMethodSubtype(s globals.Subtype, hooks AuthMethodSubtypeHooks) {
|
||||
subtypeRegistry.set(s, hooks)
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/db/timestamp"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/pagination"
|
||||
"github.com/hashicorp/boundary/internal/util"
|
||||
)
|
||||
|
||||
// AuthMethodRepository coordinates calls across different subtype services
|
||||
// to gather information about all auth methods.
|
||||
type AuthMethodRepository struct {
|
||||
reader db.Reader
|
||||
writer db.Writer
|
||||
kms *kms.Kms
|
||||
}
|
||||
|
||||
// NewAuthMethodRepository returns a new auth method repository.
|
||||
func NewAuthMethodRepository(ctx context.Context, reader db.Reader, writer db.Writer, kms *kms.Kms) (*AuthMethodRepository, error) {
|
||||
const op = "auth.NewAuthMethodRepository"
|
||||
switch {
|
||||
case util.IsNil(reader):
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing DB reader")
|
||||
case util.IsNil(writer):
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing DB writer")
|
||||
case util.IsNil(kms):
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing kms")
|
||||
}
|
||||
return &AuthMethodRepository{
|
||||
reader: reader,
|
||||
writer: writer,
|
||||
kms: kms,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// List lists auth methods across all subtypes.
|
||||
func (amr *AuthMethodRepository) List(ctx context.Context, scopeIds []string, afterItem pagination.Item, opt ...Option) ([]AuthMethod, time.Time, error) {
|
||||
const op = "auth.(*AuthMethodRepository).list"
|
||||
|
||||
opts, err := GetOpts(opt...)
|
||||
if err != nil {
|
||||
return nil, time.Time{}, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
|
||||
limit := opts.WithLimit
|
||||
|
||||
switch {
|
||||
case len(scopeIds) == 0:
|
||||
return nil, time.Time{}, errors.New(ctx, errors.InvalidParameter, op, "missing scope ids")
|
||||
case limit < 1:
|
||||
return nil, time.Time{}, errors.New(ctx, errors.InvalidParameter, op, "missing limit")
|
||||
}
|
||||
|
||||
whereClause := "scope_id in @scope_ids"
|
||||
args := []any{sql.Named("scope_ids", scopeIds)}
|
||||
|
||||
if opts.WithUnauthenticatedUser {
|
||||
whereClause += " and is_active_public_state = true"
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(listAuthMethodsTemplate, whereClause, limit)
|
||||
if afterItem != nil {
|
||||
query = fmt.Sprintf(listAuthMethodsPageTemplate, whereClause, limit)
|
||||
args = append(args,
|
||||
sql.Named("last_item_create_time", afterItem.GetCreateTime()),
|
||||
sql.Named("last_item_id", afterItem.GetPublicId()),
|
||||
)
|
||||
}
|
||||
|
||||
return amr.queryAuthMethods(ctx, query, args)
|
||||
}
|
||||
|
||||
// ListRefresh lists auth methods across all subtypes.
|
||||
func (amr *AuthMethodRepository) ListRefresh(ctx context.Context, scopeIds []string, updatedAfter time.Time, afterItem pagination.Item, opt ...Option) ([]AuthMethod, time.Time, error) {
|
||||
const op = "auth.(*AuthMethodRepository).list"
|
||||
|
||||
opts, err := GetOpts(opt...)
|
||||
if err != nil {
|
||||
return nil, time.Time{}, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
|
||||
limit := opts.WithLimit
|
||||
|
||||
switch {
|
||||
case len(scopeIds) == 0:
|
||||
return nil, time.Time{}, errors.New(ctx, errors.InvalidParameter, op, "missing scope ids")
|
||||
case updatedAfter.IsZero():
|
||||
return nil, time.Time{}, errors.New(ctx, errors.InvalidParameter, op, "missing updated after time")
|
||||
case limit < 1:
|
||||
return nil, time.Time{}, errors.New(ctx, errors.InvalidParameter, op, "missing limit")
|
||||
}
|
||||
|
||||
whereClause := "scope_id in @scope_ids"
|
||||
args := []any{sql.Named("scope_ids", scopeIds)}
|
||||
|
||||
if opts.WithUnauthenticatedUser {
|
||||
whereClause += " and is_active_public_state = true"
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(listAuthMethodsRefreshTemplate, whereClause, limit)
|
||||
args = append(args,
|
||||
sql.Named("updated_after_time", timestamp.New(updatedAfter)),
|
||||
)
|
||||
if afterItem != nil {
|
||||
query = fmt.Sprintf(listAuthMethodsRefreshPageTemplate, whereClause, limit)
|
||||
args = append(args,
|
||||
sql.Named("last_item_update_time", afterItem.GetUpdateTime()),
|
||||
sql.Named("last_item_id", afterItem.GetPublicId()),
|
||||
)
|
||||
}
|
||||
|
||||
return amr.queryAuthMethods(ctx, query, args)
|
||||
}
|
||||
|
||||
// EstimatedCount estimates the total number of auth methods.
|
||||
func (amr *AuthMethodRepository) EstimatedCount(ctx context.Context) (int, error) {
|
||||
const op = "auth.(*AuthMethodRepository).EstimatedCount"
|
||||
rows, err := amr.reader.Query(ctx, estimateCountAuthMethodsQuery, nil)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(ctx, err, op, errors.WithMsg("failed to query total auth methods"))
|
||||
}
|
||||
var count int
|
||||
for rows.Next() {
|
||||
if err := amr.reader.ScanRows(ctx, rows, &count); err != nil {
|
||||
return 0, errors.Wrap(ctx, err, op, errors.WithMsg("failed to query total auth methods"))
|
||||
}
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// ListDeletedIds lists the deleted IDs of all auth methods since the time specified.
|
||||
func (amr *AuthMethodRepository) ListDeletedIds(ctx context.Context, since time.Time) ([]string, time.Time, error) {
|
||||
const op = "auth.(*AuthMethodRepository).ListDeletedIds"
|
||||
var deletedAuthMethodIDs []string
|
||||
var transactionTimestamp time.Time
|
||||
if _, err := amr.writer.DoTx(ctx, db.StdRetryCnt, db.ExpBackoff{}, func(r db.Reader, w db.Writer) error {
|
||||
rows, err := amr.writer.Query(ctx, listDeletedIdsQuery, []any{sql.Named("since", since)})
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
}
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
if err := r.ScanRows(ctx, rows, &deletedAuthMethodIDs); err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
}
|
||||
}
|
||||
transactionTimestamp, err = r.Now(ctx)
|
||||
return err
|
||||
}); err != nil {
|
||||
return nil, time.Time{}, err
|
||||
}
|
||||
return deletedAuthMethodIDs, transactionTimestamp, nil
|
||||
}
|
||||
|
||||
func (amr *AuthMethodRepository) queryAuthMethods(ctx context.Context, query string, args []any) ([]AuthMethod, time.Time, error) {
|
||||
const op = "auth.(*AuthMethodRepository).queryAuthMethods"
|
||||
|
||||
var authmethods []AuthMethod
|
||||
var transactionTimestamp time.Time
|
||||
if _, err := amr.writer.DoTx(ctx, db.StdRetryCnt, db.ExpBackoff{}, func(r db.Reader, w db.Writer) error {
|
||||
rows, err := r.Query(ctx, query, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
var foundAuthMethods []*AuthMethodListQueryResult
|
||||
for rows.Next() {
|
||||
if err := r.ScanRows(ctx, rows, &foundAuthMethods); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, am := range foundAuthMethods {
|
||||
authmethod, err := am.toAuthMethod(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
authmethods = append(authmethods, authmethod)
|
||||
}
|
||||
transactionTimestamp, err = r.Now(ctx)
|
||||
return err
|
||||
}); err != nil {
|
||||
return nil, time.Time{}, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
|
||||
return authmethods, transactionTimestamp, nil
|
||||
}
|
||||
@@ -0,0 +1,390 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package auth_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"slices"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/hashicorp/boundary/internal/auth"
|
||||
"github.com/hashicorp/boundary/internal/auth/ldap"
|
||||
lstore "github.com/hashicorp/boundary/internal/auth/ldap/store"
|
||||
"github.com/hashicorp/boundary/internal/auth/oidc"
|
||||
ostore "github.com/hashicorp/boundary/internal/auth/oidc/store"
|
||||
"github.com/hashicorp/boundary/internal/auth/password"
|
||||
pstore "github.com/hashicorp/boundary/internal/auth/password/store"
|
||||
"github.com/hashicorp/boundary/internal/auth/store"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/db/timestamp"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
func TestAuthMethodRepository_List(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
rw := db.New(conn)
|
||||
wrapper := db.TestWrapper(t)
|
||||
testKms := kms.TestKms(t, conn, wrapper)
|
||||
org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
||||
databaseWrapper, err := testKms.GetWrapper(context.Background(), org.PublicId, kms.KeyPurposeDatabase)
|
||||
require.NoError(t, err)
|
||||
|
||||
ams := []auth.AuthMethod{
|
||||
// two ldap
|
||||
ldap.TestAuthMethod(t, conn, databaseWrapper, org.PublicId, []string{"ldaps://ldap1.alice.com"}, ldap.WithOperationalState(ctx, ldap.InactiveState)),
|
||||
ldap.TestAuthMethod(t, conn, databaseWrapper, org.PublicId, []string{"ldaps://ldap2.alice.com"}, ldap.WithOperationalState(ctx, ldap.InactiveState)),
|
||||
// two oidc
|
||||
oidc.TestAuthMethod(t, conn, databaseWrapper, org.PublicId, oidc.InactiveState, "alice_rp", "alices-dogs-name",
|
||||
oidc.WithIssuer(oidc.TestConvertToUrls(t, "https://alice-inactive.com")[0]), oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://api.com")[0])),
|
||||
oidc.TestAuthMethod(t, conn, databaseWrapper, org.PublicId, oidc.InactiveState, "bob_rp", "bobs-dogs-name",
|
||||
oidc.WithIssuer(oidc.TestConvertToUrls(t, "https://bob-inactive.com")[0]), oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://api.com")[0])),
|
||||
// two password
|
||||
password.TestAuthMethod(t, conn, org.GetPublicId()),
|
||||
password.TestAuthMethod(t, conn, org.GetPublicId()),
|
||||
}
|
||||
|
||||
// since we sort descending, we need to reverse the slice
|
||||
slices.Reverse(ams)
|
||||
|
||||
repo, err := auth.NewAuthMethodRepository(ctx, rw, rw, testKms)
|
||||
require.NoError(t, err)
|
||||
|
||||
cmpOpts := []cmp.Option{
|
||||
cmpopts.IgnoreUnexported(
|
||||
ldap.AuthMethod{},
|
||||
lstore.AuthMethod{},
|
||||
oidc.AuthMethod{},
|
||||
ostore.AuthMethod{},
|
||||
password.AuthMethod{},
|
||||
pstore.AuthMethod{},
|
||||
store.AuthMethod{},
|
||||
timestamp.Timestamp{},
|
||||
timestamppb.Timestamp{},
|
||||
),
|
||||
cmpopts.IgnoreFields(
|
||||
oidc.AuthMethod{}, "CtClientSecret", "ClientSecret",
|
||||
),
|
||||
}
|
||||
|
||||
t.Run("validation", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("missing scope ids", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, _, err := repo.List(ctx, nil, nil, auth.WithLimit(ctx, 1))
|
||||
require.ErrorContains(t, err, "missing scope ids")
|
||||
})
|
||||
t.Run("invalid limit", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, _, err := repo.List(ctx, []string{org.PublicId}, nil, auth.WithLimit(ctx, 0))
|
||||
require.ErrorContains(t, err, "missing limit")
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("success-without-after-item", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
resp, ttime, err := repo.List(ctx, []string{org.PublicId}, nil, auth.WithLimit(ctx, 10))
|
||||
require.NoError(t, err)
|
||||
// Transaction timestamp should be within ~10 seconds of now
|
||||
assert.True(t, time.Now().Before(ttime.Add(10*time.Second)))
|
||||
assert.True(t, time.Now().After(ttime.Add(-10*time.Second)))
|
||||
require.Empty(t, cmp.Diff(resp, ams, cmpOpts...))
|
||||
})
|
||||
t.Run("success-with-after-item", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
resp, ttime, err := repo.List(ctx, []string{org.PublicId}, ams[0], auth.WithLimit(ctx, 10))
|
||||
require.NoError(t, err)
|
||||
// Transaction timestamp should be within ~10 seconds of now
|
||||
assert.True(t, time.Now().Before(ttime.Add(10*time.Second)))
|
||||
assert.True(t, time.Now().After(ttime.Add(-10*time.Second)))
|
||||
require.Empty(t, cmp.Diff(resp, ams[1:], cmpOpts...))
|
||||
})
|
||||
t.Run("success-with-unauthenticated-user", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
resp, ttime, err := repo.List(ctx, []string{org.PublicId}, nil, auth.WithLimit(ctx, 10), auth.WithUnauthenticatedUser(ctx, true))
|
||||
require.NoError(t, err)
|
||||
// Transaction timestamp should be within ~10 seconds of now
|
||||
assert.True(t, time.Now().Before(ttime.Add(10*time.Second)))
|
||||
assert.True(t, time.Now().After(ttime.Add(-10*time.Second)))
|
||||
require.Empty(t, cmp.Diff(resp, ams[0:2], cmpOpts...))
|
||||
})
|
||||
}
|
||||
|
||||
func TestAuthMethodRepository_ListRefresh(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
rw := db.New(conn)
|
||||
wrapper := db.TestWrapper(t)
|
||||
testKms := kms.TestKms(t, conn, wrapper)
|
||||
org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
||||
databaseWrapper, err := testKms.GetWrapper(context.Background(), org.PublicId, kms.KeyPurposeDatabase)
|
||||
require.NoError(t, err)
|
||||
fiveDaysAgo := time.Now().AddDate(0, 0, -5)
|
||||
|
||||
ams := []auth.AuthMethod{
|
||||
// two ldap
|
||||
ldap.TestAuthMethod(t, conn, databaseWrapper, org.PublicId, []string{"ldaps://ldap1.alice.com"}, ldap.WithOperationalState(ctx, ldap.InactiveState)),
|
||||
ldap.TestAuthMethod(t, conn, databaseWrapper, org.PublicId, []string{"ldaps://ldap2.alice.com"}, ldap.WithOperationalState(ctx, ldap.InactiveState)),
|
||||
// two oidc
|
||||
oidc.TestAuthMethod(t, conn, databaseWrapper, org.PublicId, oidc.InactiveState, "alice_rp", "alices-dogs-name",
|
||||
oidc.WithIssuer(oidc.TestConvertToUrls(t, "https://alice-inactive.com")[0]), oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://api.com")[0])),
|
||||
oidc.TestAuthMethod(t, conn, databaseWrapper, org.PublicId, oidc.InactiveState, "bob_rp", "bobs-dogs-name",
|
||||
oidc.WithIssuer(oidc.TestConvertToUrls(t, "https://bob-inactive.com")[0]), oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://api.com")[0])),
|
||||
// two password
|
||||
password.TestAuthMethod(t, conn, org.GetPublicId()),
|
||||
password.TestAuthMethod(t, conn, org.GetPublicId()),
|
||||
}
|
||||
|
||||
// since we sort descending, we need to reverse the slice
|
||||
slices.Reverse(ams)
|
||||
|
||||
repo, err := auth.NewAuthMethodRepository(ctx, rw, rw, testKms)
|
||||
require.NoError(t, err)
|
||||
|
||||
cmpOpts := []cmp.Option{
|
||||
cmpopts.IgnoreUnexported(
|
||||
ldap.AuthMethod{},
|
||||
lstore.AuthMethod{},
|
||||
oidc.AuthMethod{},
|
||||
ostore.AuthMethod{},
|
||||
password.AuthMethod{},
|
||||
pstore.AuthMethod{},
|
||||
store.AuthMethod{},
|
||||
timestamp.Timestamp{},
|
||||
timestamppb.Timestamp{},
|
||||
),
|
||||
cmpopts.IgnoreFields(
|
||||
oidc.AuthMethod{}, "CtClientSecret", "ClientSecret",
|
||||
),
|
||||
}
|
||||
|
||||
t.Run("validation", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("missing updated after", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, _, err := repo.ListRefresh(ctx, []string{org.PublicId}, time.Time{}, nil, auth.WithLimit(ctx, 1))
|
||||
require.ErrorContains(t, err, "missing updated after time")
|
||||
})
|
||||
t.Run("missing scope ids", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, _, err := repo.ListRefresh(ctx, nil, fiveDaysAgo, nil, auth.WithLimit(ctx, 1))
|
||||
require.ErrorContains(t, err, "missing scope ids")
|
||||
})
|
||||
t.Run("invalid limit", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, _, err := repo.ListRefresh(ctx, []string{org.PublicId}, fiveDaysAgo, nil, auth.WithLimit(ctx, 0))
|
||||
require.ErrorContains(t, err, "missing limit")
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("success-without-after-item", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
resp, ttime, err := repo.ListRefresh(ctx, []string{org.PublicId}, fiveDaysAgo, nil, auth.WithLimit(ctx, 10))
|
||||
require.NoError(t, err)
|
||||
// Transaction timestamp should be within ~10 seconds of now
|
||||
assert.True(t, time.Now().Before(ttime.Add(10*time.Second)))
|
||||
assert.True(t, time.Now().After(ttime.Add(-10*time.Second)))
|
||||
require.Empty(t, cmp.Diff(resp, ams, cmpOpts...))
|
||||
})
|
||||
t.Run("success-with-after-item", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
resp, ttime, err := repo.ListRefresh(ctx, []string{org.PublicId}, fiveDaysAgo, ams[0], auth.WithLimit(ctx, 10))
|
||||
require.NoError(t, err)
|
||||
// Transaction timestamp should be within ~10 seconds of now
|
||||
assert.True(t, time.Now().Before(ttime.Add(10*time.Second)))
|
||||
assert.True(t, time.Now().After(ttime.Add(-10*time.Second)))
|
||||
require.Empty(t, cmp.Diff(resp, ams[1:], cmpOpts...))
|
||||
})
|
||||
t.Run("success-without-after-item-recent-updated-after", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
resp, ttime, err := repo.ListRefresh(ctx, []string{org.PublicId}, ams[len(ams)-1].GetUpdateTime().AsTime(), nil, auth.WithLimit(ctx, 10))
|
||||
require.NoError(t, err)
|
||||
// Transaction timestamp should be within ~10 seconds of now
|
||||
assert.True(t, time.Now().Before(ttime.Add(10*time.Second)))
|
||||
assert.True(t, time.Now().After(ttime.Add(-10*time.Second)))
|
||||
require.Empty(t, cmp.Diff(resp, ams[:len(ams)-1], cmpOpts...))
|
||||
})
|
||||
t.Run("success-with-after-item-recent-updated-after", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
resp, ttime, err := repo.ListRefresh(ctx, []string{org.PublicId}, ams[len(ams)-1].GetUpdateTime().AsTime(), ams[0], auth.WithLimit(ctx, 10))
|
||||
require.NoError(t, err)
|
||||
// Transaction timestamp should be within ~10 seconds of now
|
||||
assert.True(t, time.Now().Before(ttime.Add(10*time.Second)))
|
||||
assert.True(t, time.Now().After(ttime.Add(-10*time.Second)))
|
||||
require.Empty(t, cmp.Diff(resp, ams[1:len(ams)-1], cmpOpts...))
|
||||
})
|
||||
}
|
||||
|
||||
func TestAuthMethodRepository_EstimatedCount(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
rw := db.New(conn)
|
||||
wrapper := db.TestWrapper(t)
|
||||
testKms := kms.TestKms(t, conn, wrapper)
|
||||
org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
||||
databaseWrapper, err := testKms.GetWrapper(context.Background(), org.PublicId, kms.KeyPurposeDatabase)
|
||||
require.NoError(t, err)
|
||||
sqlDb, err := conn.SqlDB(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
ldapRepo, err := ldap.NewRepository(ctx, rw, rw, testKms)
|
||||
require.NoError(t, err)
|
||||
oidcRepo, err := oidc.NewRepository(ctx, rw, rw, testKms)
|
||||
require.NoError(t, err)
|
||||
passwordRepo, err := password.NewRepository(ctx, rw, rw, testKms)
|
||||
require.NoError(t, err)
|
||||
|
||||
repo, err := auth.NewAuthMethodRepository(ctx, rw, rw, testKms)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Check total entries at start, expect 0
|
||||
numItems, err := repo.EstimatedCount(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, numItems)
|
||||
|
||||
// Create auth methods
|
||||
am1 := ldap.TestAuthMethod(t, conn, databaseWrapper, org.PublicId, []string{"ldaps://ldap1.alice.com"}, ldap.WithOperationalState(ctx, ldap.InactiveState))
|
||||
am2 := oidc.TestAuthMethod(t, conn, databaseWrapper, org.PublicId, oidc.InactiveState, "alice_rp", "alices-dogs-name",
|
||||
oidc.WithIssuer(oidc.TestConvertToUrls(t, "https://alice-inactive.com")[0]), oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://api.com")[0]))
|
||||
am3 := password.TestAuthMethod(t, conn, org.GetPublicId())
|
||||
|
||||
// Run analyze to update postgres meta tables
|
||||
_, err = sqlDb.ExecContext(ctx, "analyze")
|
||||
require.NoError(t, err)
|
||||
|
||||
numItems, err = repo.EstimatedCount(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 3, numItems)
|
||||
|
||||
// Delete ldap auth method
|
||||
_, err = ldapRepo.DeleteAuthMethod(ctx, am1.GetPublicId())
|
||||
require.NoError(t, err)
|
||||
_, err = sqlDb.ExecContext(ctx, "analyze")
|
||||
require.NoError(t, err)
|
||||
|
||||
numItems, err = repo.EstimatedCount(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 2, numItems)
|
||||
|
||||
// Delete oidc auth method
|
||||
_, err = oidcRepo.DeleteAuthMethod(ctx, am2.GetPublicId())
|
||||
require.NoError(t, err)
|
||||
_, err = sqlDb.ExecContext(ctx, "analyze")
|
||||
require.NoError(t, err)
|
||||
|
||||
numItems, err = repo.EstimatedCount(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 1, numItems)
|
||||
|
||||
// Delete pw auth method
|
||||
_, err = passwordRepo.DeleteAuthMethod(ctx, org.GetPublicId(), am3.GetPublicId())
|
||||
require.NoError(t, err)
|
||||
_, err = sqlDb.ExecContext(ctx, "analyze")
|
||||
require.NoError(t, err)
|
||||
|
||||
numItems, err = repo.EstimatedCount(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, numItems)
|
||||
}
|
||||
|
||||
func TestRepository_ListDeletedStoreIds(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
rw := db.New(conn)
|
||||
wrapper := db.TestWrapper(t)
|
||||
testKms := kms.TestKms(t, conn, wrapper)
|
||||
org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
||||
databaseWrapper, err := testKms.GetWrapper(context.Background(), org.PublicId, kms.KeyPurposeDatabase)
|
||||
require.NoError(t, err)
|
||||
|
||||
ldapRepo, err := ldap.NewRepository(ctx, rw, rw, testKms)
|
||||
require.NoError(t, err)
|
||||
oidcRepo, err := oidc.NewRepository(ctx, rw, rw, testKms)
|
||||
require.NoError(t, err)
|
||||
passwordRepo, err := password.NewRepository(ctx, rw, rw, testKms)
|
||||
require.NoError(t, err)
|
||||
|
||||
repo, err := auth.NewAuthMethodRepository(ctx, rw, rw, testKms)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Check total entries at start, expect 0
|
||||
numItems, err := repo.EstimatedCount(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, numItems)
|
||||
|
||||
// Create auth methods
|
||||
am1 := ldap.TestAuthMethod(t, conn, databaseWrapper, org.PublicId, []string{"ldaps://ldap1.alice.com"}, ldap.WithOperationalState(ctx, ldap.InactiveState))
|
||||
am2 := oidc.TestAuthMethod(t, conn, databaseWrapper, org.PublicId, oidc.InactiveState, "alice_rp", "alices-dogs-name",
|
||||
oidc.WithIssuer(oidc.TestConvertToUrls(t, "https://alice-inactive.com")[0]), oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://api.com")[0]))
|
||||
am3 := password.TestAuthMethod(t, conn, org.GetPublicId())
|
||||
|
||||
// Expect no entries at the start
|
||||
deletedIds, ttime, err := repo.ListDeletedIds(ctx, time.Now().AddDate(-1, 0, 0))
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, deletedIds)
|
||||
// Transaction timestamp should be within ~10 seconds of now
|
||||
assert.True(t, time.Now().Before(ttime.Add(10*time.Second)))
|
||||
assert.True(t, time.Now().After(ttime.Add(-10*time.Second)))
|
||||
|
||||
_, err = ldapRepo.DeleteAuthMethod(ctx, am1.GetPublicId())
|
||||
require.NoError(t, err)
|
||||
|
||||
// Expect one entry
|
||||
deletedIds, ttime, err = repo.ListDeletedIds(ctx, time.Now().AddDate(-1, 0, 0))
|
||||
require.NoError(t, err)
|
||||
assert.Empty(
|
||||
t,
|
||||
cmp.Diff(
|
||||
[]string{am1.GetPublicId()},
|
||||
deletedIds,
|
||||
cmpopts.SortSlices(func(i, j string) bool { return i < j }),
|
||||
),
|
||||
)
|
||||
assert.True(t, time.Now().Before(ttime.Add(10*time.Second)))
|
||||
assert.True(t, time.Now().After(ttime.Add(-10*time.Second)))
|
||||
|
||||
// Try again with the time set to now, expect no entries
|
||||
deletedIds, ttime, err = repo.ListDeletedIds(ctx, time.Now())
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, deletedIds)
|
||||
assert.True(t, time.Now().Before(ttime.Add(10*time.Second)))
|
||||
assert.True(t, time.Now().After(ttime.Add(-10*time.Second)))
|
||||
|
||||
_, err = oidcRepo.DeleteAuthMethod(ctx, am2.GetPublicId())
|
||||
require.NoError(t, err)
|
||||
_, err = passwordRepo.DeleteAuthMethod(ctx, org.GetPublicId(), am3.GetPublicId())
|
||||
require.NoError(t, err)
|
||||
|
||||
// Expect three entries (with a buffer of -30 seconds, we'll pick up am1)
|
||||
deletedIds, ttime, err = repo.ListDeletedIds(ctx, time.Now().AddDate(-1, 0, 0))
|
||||
require.NoError(t, err)
|
||||
assert.Empty(
|
||||
t,
|
||||
cmp.Diff(
|
||||
[]string{am1.GetPublicId(), am2.GetPublicId(), am3.GetPublicId()},
|
||||
deletedIds,
|
||||
cmpopts.SortSlices(func(i, j string) bool { return i < j }),
|
||||
),
|
||||
)
|
||||
assert.True(t, time.Now().Before(ttime.Add(10*time.Second)))
|
||||
assert.True(t, time.Now().After(ttime.Add(-10*time.Second)))
|
||||
|
||||
// Try again with the time set to now, expect no entries
|
||||
deletedIds, ttime, err = repo.ListDeletedIds(ctx, time.Now())
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, deletedIds)
|
||||
assert.True(t, time.Now().Before(ttime.Add(10*time.Second)))
|
||||
assert.True(t, time.Now().After(ttime.Add(-10*time.Second)))
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
"github.com/hashicorp/boundary/internal/pagination"
|
||||
)
|
||||
|
||||
// ListAuthMethods lists up to page size auth methods, filtering out entries that
|
||||
// do not pass the filter item function. It will automatically request
|
||||
// more auth methods from the database, at page size chunks, to fill the page.
|
||||
// It returns a new list token used to continue pagination or refresh items.
|
||||
// Auth methods are ordered by create time descending (most recently created first).
|
||||
func ListAuthMethods(
|
||||
ctx context.Context,
|
||||
grantsHash []byte,
|
||||
pageSize int,
|
||||
filterItemFn pagination.ListFilterFunc[AuthMethod],
|
||||
repo *AuthMethodRepository,
|
||||
scopeIds []string,
|
||||
withUnauthenticatedUser bool,
|
||||
) (*pagination.ListResponse[AuthMethod], error) {
|
||||
const op = "auth.ListAuthMethods"
|
||||
|
||||
switch {
|
||||
case len(grantsHash) == 0:
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing grants hash")
|
||||
case pageSize < 1:
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "page size must be at least 1")
|
||||
case filterItemFn == nil:
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing filter item callback")
|
||||
case repo == nil:
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing repo")
|
||||
case len(scopeIds) == 0:
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing scope ids")
|
||||
}
|
||||
|
||||
listItemsFn := func(ctx context.Context, lastPageItem AuthMethod, limit int) ([]AuthMethod, time.Time, error) {
|
||||
opts := []Option{
|
||||
WithLimit(ctx, limit),
|
||||
}
|
||||
if withUnauthenticatedUser {
|
||||
opts = append(opts, WithUnauthenticatedUser(ctx, true))
|
||||
}
|
||||
return repo.List(ctx, scopeIds, lastPageItem, opts...)
|
||||
}
|
||||
|
||||
return pagination.List(ctx, grantsHash, pageSize, filterItemFn, listItemsFn, repo.EstimatedCount)
|
||||
}
|
||||
@@ -0,0 +1,711 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package auth_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"slices"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/auth"
|
||||
"github.com/hashicorp/boundary/internal/auth/ldap"
|
||||
lstore "github.com/hashicorp/boundary/internal/auth/ldap/store"
|
||||
"github.com/hashicorp/boundary/internal/auth/oidc"
|
||||
ostore "github.com/hashicorp/boundary/internal/auth/oidc/store"
|
||||
"github.com/hashicorp/boundary/internal/auth/password"
|
||||
pstore "github.com/hashicorp/boundary/internal/auth/password/store"
|
||||
"github.com/hashicorp/boundary/internal/auth/store"
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/db/timestamp"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/listtoken"
|
||||
"github.com/hashicorp/boundary/internal/types/resource"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
type fakeReader struct {
|
||||
db.Reader
|
||||
}
|
||||
type fakeWriter struct {
|
||||
db.Writer
|
||||
}
|
||||
|
||||
func TestNewAuthMethodService(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
wrapper := db.TestWrapper(t)
|
||||
testKms := kms.TestKms(t, conn, wrapper)
|
||||
t.Run("success", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
got, err := auth.NewAuthMethodRepository(ctx, &fakeReader{}, &fakeWriter{}, testKms)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, got)
|
||||
})
|
||||
t.Run("nil-reader", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := auth.NewAuthMethodRepository(ctx, nil, &fakeWriter{}, testKms)
|
||||
require.Error(t, err)
|
||||
})
|
||||
t.Run("nil-interface-reader", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := auth.NewAuthMethodRepository(ctx, (*fakeReader)(nil), &fakeWriter{}, testKms)
|
||||
require.Error(t, err)
|
||||
})
|
||||
t.Run("nil-writer", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := auth.NewAuthMethodRepository(ctx, &fakeReader{}, nil, testKms)
|
||||
require.Error(t, err)
|
||||
})
|
||||
t.Run("nil-interface-writer", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := auth.NewAuthMethodRepository(ctx, &fakeReader{}, (*fakeWriter)(nil), testKms)
|
||||
require.Error(t, err)
|
||||
})
|
||||
t.Run("nil-kms", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := auth.NewAuthMethodRepository(ctx, &fakeReader{}, &fakeWriter{}, nil)
|
||||
require.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStoreService_List(t *testing.T) {
|
||||
// Set database read timeout to avoid duplicates in response
|
||||
oldReadTimeout := globals.RefreshReadLookbackDuration
|
||||
globals.RefreshReadLookbackDuration = 0
|
||||
t.Cleanup(func() {
|
||||
globals.RefreshReadLookbackDuration = oldReadTimeout
|
||||
})
|
||||
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
rw := db.New(conn)
|
||||
wrapper := db.TestWrapper(t)
|
||||
testKms := kms.TestKms(t, conn, wrapper)
|
||||
org, _ := iam.TestScopes(t, iam.TestRepo(t, conn, wrapper))
|
||||
databaseWrapper, err := testKms.GetWrapper(context.Background(), org.PublicId, kms.KeyPurposeDatabase)
|
||||
require.NoError(t, err)
|
||||
sqlDb, err := conn.SqlDB(ctx)
|
||||
require.NoError(t, err)
|
||||
fiveDaysAgo := time.Now().AddDate(0, 0, -5)
|
||||
|
||||
ldapRepo, err := ldap.NewRepository(ctx, rw, rw, testKms)
|
||||
require.NoError(t, err)
|
||||
oidcRepo, err := oidc.NewRepository(ctx, rw, rw, testKms)
|
||||
require.NoError(t, err)
|
||||
passwordRepo, err := password.NewRepository(ctx, rw, rw, testKms)
|
||||
require.NoError(t, err)
|
||||
|
||||
ams := []auth.AuthMethod{
|
||||
// two ldap
|
||||
ldap.TestAuthMethod(t, conn, databaseWrapper, org.PublicId, []string{"ldaps://ldap1.alice.com"}, ldap.WithOperationalState(ctx, ldap.InactiveState)),
|
||||
ldap.TestAuthMethod(t, conn, databaseWrapper, org.PublicId, []string{"ldaps://ldap2.alice.com"}, ldap.WithOperationalState(ctx, ldap.InactiveState)),
|
||||
// two oidc
|
||||
oidc.TestAuthMethod(t, conn, databaseWrapper, org.PublicId, oidc.InactiveState, "alice_rp", "alices-dogs-name",
|
||||
oidc.WithIssuer(oidc.TestConvertToUrls(t, "https://alice-inactive.com")[0]), oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://api.com")[0])),
|
||||
oidc.TestAuthMethod(t, conn, databaseWrapper, org.PublicId, oidc.InactiveState, "bob_rp", "bobs-dogs-name",
|
||||
oidc.WithIssuer(oidc.TestConvertToUrls(t, "https://bob-inactive.com")[0]), oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://api.com")[0])),
|
||||
// two password
|
||||
password.TestAuthMethod(t, conn, org.GetPublicId()),
|
||||
password.TestAuthMethod(t, conn, org.GetPublicId()),
|
||||
}
|
||||
|
||||
// since we sort descending, we need to reverse the slice
|
||||
slices.Reverse(ams)
|
||||
|
||||
repo, err := auth.NewAuthMethodRepository(ctx, rw, rw, testKms)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Run analyze to update count estimate
|
||||
_, err = sqlDb.ExecContext(ctx, "analyze")
|
||||
require.NoError(t, err)
|
||||
|
||||
cmpOpts := []cmp.Option{
|
||||
cmpopts.IgnoreUnexported(
|
||||
ldap.AuthMethod{},
|
||||
lstore.AuthMethod{},
|
||||
oidc.AuthMethod{},
|
||||
ostore.AuthMethod{},
|
||||
password.AuthMethod{},
|
||||
pstore.AuthMethod{},
|
||||
store.AuthMethod{},
|
||||
timestamp.Timestamp{},
|
||||
timestamppb.Timestamp{},
|
||||
),
|
||||
cmpopts.IgnoreFields(
|
||||
oidc.AuthMethod{}, "CtClientSecret", "ClientSecret",
|
||||
),
|
||||
}
|
||||
|
||||
t.Run("List validation", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("missing grants hash", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
_, err := auth.ListAuthMethods(ctx, nil, 1, filterFunc, repo, []string{org.PublicId}, false)
|
||||
require.ErrorContains(t, err, "missing grants hash")
|
||||
})
|
||||
t.Run("zero page size", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
_, err := auth.ListAuthMethods(ctx, []byte("some hash"), 0, filterFunc, repo, []string{org.PublicId}, false)
|
||||
require.ErrorContains(t, err, "page size must be at least 1")
|
||||
})
|
||||
t.Run("negative page size", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
_, err := auth.ListAuthMethods(ctx, []byte("some hash"), -1, filterFunc, repo, []string{org.PublicId}, false)
|
||||
require.ErrorContains(t, err, "page size must be at least 1")
|
||||
})
|
||||
t.Run("nil filter func", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := auth.ListAuthMethods(ctx, []byte("some hash"), 1, nil, repo, []string{org.PublicId}, false)
|
||||
require.ErrorContains(t, err, "missing filter item callback")
|
||||
})
|
||||
t.Run("missing repo", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
_, err := auth.ListAuthMethods(ctx, []byte("some hash"), 1, filterFunc, nil, []string{org.PublicId}, false)
|
||||
require.ErrorContains(t, err, "missing repo")
|
||||
})
|
||||
t.Run("missing scope ids", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
_, err := auth.ListAuthMethods(ctx, []byte("some hash"), 1, filterFunc, repo, nil, false)
|
||||
require.ErrorContains(t, err, "missing scope ids")
|
||||
})
|
||||
})
|
||||
t.Run("ListPage validation", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("missing grants hash", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
tok, err := listtoken.NewPagination(ctx, fiveDaysAgo, resource.AuthMethod, []byte("some hash"), "some-id", fiveDaysAgo)
|
||||
require.NoError(t, err)
|
||||
_, err = auth.ListAuthMethodsPage(ctx, nil, 1, filterFunc, tok, repo, []string{org.PublicId}, false)
|
||||
require.ErrorContains(t, err, "missing grants hash")
|
||||
})
|
||||
t.Run("zero page size", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
tok, err := listtoken.NewPagination(ctx, fiveDaysAgo, resource.AuthMethod, []byte("some hash"), "some-id", fiveDaysAgo)
|
||||
require.NoError(t, err)
|
||||
_, err = auth.ListAuthMethodsPage(ctx, []byte("some hash"), 0, filterFunc, tok, repo, []string{org.PublicId}, false)
|
||||
require.ErrorContains(t, err, "page size must be at least 1")
|
||||
})
|
||||
t.Run("negative page size", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
tok, err := listtoken.NewPagination(ctx, fiveDaysAgo, resource.AuthMethod, []byte("some hash"), "some-id", fiveDaysAgo)
|
||||
require.NoError(t, err)
|
||||
_, err = auth.ListAuthMethodsPage(ctx, []byte("some hash"), -1, filterFunc, tok, repo, []string{org.PublicId}, false)
|
||||
require.ErrorContains(t, err, "page size must be at least 1")
|
||||
})
|
||||
t.Run("nil filter func", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
tok, err := listtoken.NewPagination(ctx, fiveDaysAgo, resource.AuthMethod, []byte("some hash"), "some-id", fiveDaysAgo)
|
||||
require.NoError(t, err)
|
||||
_, err = auth.ListAuthMethodsPage(ctx, []byte("some hash"), 1, nil, tok, repo, []string{org.PublicId}, false)
|
||||
require.ErrorContains(t, err, "missing filter item callback")
|
||||
})
|
||||
t.Run("nil token", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
_, err = auth.ListAuthMethodsPage(ctx, []byte("some hash"), 1, filterFunc, nil, repo, []string{org.PublicId}, false)
|
||||
require.ErrorContains(t, err, "missing token")
|
||||
})
|
||||
t.Run("wrong token type", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
tok, err := listtoken.NewStartRefresh(ctx, fiveDaysAgo, resource.AuthMethod, []byte("some hash"), fiveDaysAgo, fiveDaysAgo)
|
||||
require.NoError(t, err)
|
||||
_, err = auth.ListAuthMethodsPage(ctx, []byte("some hash"), 1, filterFunc, tok, repo, []string{org.PublicId}, false)
|
||||
require.ErrorContains(t, err, "token did not have a pagination token component")
|
||||
})
|
||||
t.Run("missing repo", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
tok, err := listtoken.NewPagination(ctx, fiveDaysAgo, resource.AuthMethod, []byte("some hash"), "some-id", fiveDaysAgo)
|
||||
require.NoError(t, err)
|
||||
_, err = auth.ListAuthMethodsPage(ctx, []byte("some hash"), 1, filterFunc, tok, nil, []string{org.PublicId}, false)
|
||||
require.ErrorContains(t, err, "missing repo")
|
||||
})
|
||||
t.Run("missing scope ids", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
tok, err := listtoken.NewPagination(ctx, fiveDaysAgo, resource.AuthMethod, []byte("some hash"), "some-id", fiveDaysAgo)
|
||||
require.NoError(t, err)
|
||||
_, err = auth.ListAuthMethodsPage(ctx, []byte("some hash"), 1, filterFunc, tok, repo, nil, false)
|
||||
require.ErrorContains(t, err, "missing scope ids")
|
||||
})
|
||||
t.Run("wrong token resource type", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
tok, err := listtoken.NewPagination(ctx, fiveDaysAgo, resource.Target, []byte("some hash"), "some-id", fiveDaysAgo)
|
||||
require.NoError(t, err)
|
||||
_, err = auth.ListAuthMethodsPage(ctx, []byte("some hash"), 1, filterFunc, tok, repo, []string{org.GetPublicId()}, false)
|
||||
require.ErrorContains(t, err, "token did not have an auth method resource type")
|
||||
})
|
||||
})
|
||||
t.Run("ListRefresh validation", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("missing grants hash", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
tok, err := listtoken.NewStartRefresh(ctx, fiveDaysAgo, resource.AuthMethod, []byte("some hash"), fiveDaysAgo, fiveDaysAgo)
|
||||
require.NoError(t, err)
|
||||
_, err = auth.ListAuthMethodsRefresh(ctx, nil, 1, filterFunc, tok, repo, []string{org.PublicId}, false)
|
||||
require.ErrorContains(t, err, "missing grants hash")
|
||||
})
|
||||
t.Run("zero page size", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
tok, err := listtoken.NewStartRefresh(ctx, fiveDaysAgo, resource.AuthMethod, []byte("some hash"), fiveDaysAgo, fiveDaysAgo)
|
||||
require.NoError(t, err)
|
||||
_, err = auth.ListAuthMethodsRefresh(ctx, []byte("some hash"), 0, filterFunc, tok, repo, []string{org.PublicId}, false)
|
||||
require.ErrorContains(t, err, "page size must be at least 1")
|
||||
})
|
||||
t.Run("negative page size", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
tok, err := listtoken.NewStartRefresh(ctx, fiveDaysAgo, resource.AuthMethod, []byte("some hash"), fiveDaysAgo, fiveDaysAgo)
|
||||
require.NoError(t, err)
|
||||
_, err = auth.ListAuthMethodsRefresh(ctx, []byte("some hash"), -1, filterFunc, tok, repo, []string{org.PublicId}, false)
|
||||
require.ErrorContains(t, err, "page size must be at least 1")
|
||||
})
|
||||
t.Run("nil filter func", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
tok, err := listtoken.NewStartRefresh(ctx, fiveDaysAgo, resource.AuthMethod, []byte("some hash"), fiveDaysAgo, fiveDaysAgo)
|
||||
require.NoError(t, err)
|
||||
_, err = auth.ListAuthMethodsRefresh(ctx, []byte("some hash"), 1, nil, tok, repo, []string{org.PublicId}, false)
|
||||
require.ErrorContains(t, err, "missing filter item callback")
|
||||
})
|
||||
t.Run("nil token", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
_, err = auth.ListAuthMethodsRefresh(ctx, []byte("some hash"), 1, filterFunc, nil, repo, []string{org.PublicId}, false)
|
||||
require.ErrorContains(t, err, "missing token")
|
||||
})
|
||||
t.Run("missing repo", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
tok, err := listtoken.NewStartRefresh(ctx, fiveDaysAgo, resource.AuthMethod, []byte("some hash"), fiveDaysAgo, fiveDaysAgo)
|
||||
require.NoError(t, err)
|
||||
_, err = auth.ListAuthMethodsRefresh(ctx, []byte("some hash"), 1, filterFunc, tok, nil, []string{org.PublicId}, false)
|
||||
require.ErrorContains(t, err, "missing repo")
|
||||
})
|
||||
t.Run("missing scope ids", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
tok, err := listtoken.NewStartRefresh(ctx, fiveDaysAgo, resource.AuthMethod, []byte("some hash"), fiveDaysAgo, fiveDaysAgo)
|
||||
require.NoError(t, err)
|
||||
_, err = auth.ListAuthMethodsRefresh(ctx, []byte("some hash"), 1, filterFunc, tok, repo, nil, false)
|
||||
require.ErrorContains(t, err, "missing scope ids")
|
||||
})
|
||||
t.Run("wrong token resource type", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
tok, err := listtoken.NewStartRefresh(ctx, fiveDaysAgo, resource.Target, []byte("some hash"), fiveDaysAgo, fiveDaysAgo)
|
||||
require.NoError(t, err)
|
||||
_, err = auth.ListAuthMethodsRefresh(ctx, []byte("some hash"), 1, filterFunc, tok, repo, []string{org.GetPublicId()}, false)
|
||||
require.ErrorContains(t, err, "token did not have an auth method resource type")
|
||||
})
|
||||
})
|
||||
t.Run("ListRefreshPage validation", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("missing grants hash", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
tok, err := listtoken.NewRefresh(ctx, fiveDaysAgo, resource.AuthMethod, []byte("some hash"), fiveDaysAgo, fiveDaysAgo, fiveDaysAgo, "some other id", fiveDaysAgo)
|
||||
require.NoError(t, err)
|
||||
_, err = auth.ListAuthMethodsRefreshPage(ctx, nil, 1, filterFunc, tok, repo, []string{org.PublicId}, false)
|
||||
require.ErrorContains(t, err, "missing grants hash")
|
||||
})
|
||||
t.Run("zero page size", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
tok, err := listtoken.NewRefresh(ctx, fiveDaysAgo, resource.AuthMethod, []byte("some hash"), fiveDaysAgo, fiveDaysAgo, fiveDaysAgo, "some other id", fiveDaysAgo)
|
||||
require.NoError(t, err)
|
||||
_, err = auth.ListAuthMethodsRefreshPage(ctx, []byte("some hash"), 0, filterFunc, tok, repo, []string{org.PublicId}, false)
|
||||
require.ErrorContains(t, err, "page size must be at least 1")
|
||||
})
|
||||
t.Run("negative page size", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
tok, err := listtoken.NewRefresh(ctx, fiveDaysAgo, resource.AuthMethod, []byte("some hash"), fiveDaysAgo, fiveDaysAgo, fiveDaysAgo, "some other id", fiveDaysAgo)
|
||||
require.NoError(t, err)
|
||||
_, err = auth.ListAuthMethodsRefreshPage(ctx, []byte("some hash"), -1, filterFunc, tok, repo, []string{org.PublicId}, false)
|
||||
require.ErrorContains(t, err, "page size must be at least 1")
|
||||
})
|
||||
t.Run("nil filter func", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
tok, err := listtoken.NewRefresh(ctx, fiveDaysAgo, resource.AuthMethod, []byte("some hash"), fiveDaysAgo, fiveDaysAgo, fiveDaysAgo, "some other id", fiveDaysAgo)
|
||||
require.NoError(t, err)
|
||||
_, err = auth.ListAuthMethodsRefreshPage(ctx, []byte("some hash"), 1, nil, tok, repo, []string{org.PublicId}, false)
|
||||
require.ErrorContains(t, err, "missing filter item callback")
|
||||
})
|
||||
t.Run("nil token", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
_, err = auth.ListAuthMethodsRefreshPage(ctx, []byte("some hash"), 1, filterFunc, nil, repo, []string{org.PublicId}, false)
|
||||
require.ErrorContains(t, err, "missing token")
|
||||
})
|
||||
t.Run("wrong token type", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
tok, err := listtoken.NewPagination(ctx, fiveDaysAgo, resource.AuthMethod, []byte("some hash"), "some-id", fiveDaysAgo)
|
||||
require.NoError(t, err)
|
||||
_, err = auth.ListAuthMethodsRefreshPage(ctx, []byte("some hash"), 1, filterFunc, tok, repo, []string{org.PublicId}, false)
|
||||
require.ErrorContains(t, err, "token did not have a refresh token component")
|
||||
})
|
||||
t.Run("missing repo", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
tok, err := listtoken.NewRefresh(ctx, fiveDaysAgo, resource.AuthMethod, []byte("some hash"), fiveDaysAgo, fiveDaysAgo, fiveDaysAgo, "some other id", fiveDaysAgo)
|
||||
require.NoError(t, err)
|
||||
_, err = auth.ListAuthMethodsRefreshPage(ctx, []byte("some hash"), 1, filterFunc, tok, nil, []string{org.PublicId}, false)
|
||||
require.ErrorContains(t, err, "missing repo")
|
||||
})
|
||||
t.Run("missing scope ids", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
tok, err := listtoken.NewRefresh(ctx, fiveDaysAgo, resource.AuthMethod, []byte("some hash"), fiveDaysAgo, fiveDaysAgo, fiveDaysAgo, "some other id", fiveDaysAgo)
|
||||
require.NoError(t, err)
|
||||
_, err = auth.ListAuthMethodsRefreshPage(ctx, []byte("some hash"), 1, filterFunc, tok, repo, nil, false)
|
||||
require.ErrorContains(t, err, "missing scope ids")
|
||||
})
|
||||
t.Run("wrong token resource type", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
filterFunc := func(_ context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
tok, err := listtoken.NewRefresh(ctx, fiveDaysAgo, resource.Target, []byte("some hash"), fiveDaysAgo, fiveDaysAgo, fiveDaysAgo, "some other id", fiveDaysAgo)
|
||||
require.NoError(t, err)
|
||||
_, err = auth.ListAuthMethodsRefreshPage(ctx, []byte("some hash"), 1, filterFunc, tok, repo, []string{org.GetPublicId()}, false)
|
||||
require.ErrorContains(t, err, "token did not have an auth method resource type")
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("simple pagination", func(t *testing.T) {
|
||||
filterFunc := func(context.Context, auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
resp, err := auth.ListAuthMethods(ctx, []byte("some hash"), 1, filterFunc, repo, []string{org.PublicId}, false)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp.ListToken)
|
||||
require.Equal(t, resp.ListToken.GrantsHash, []byte("some hash"))
|
||||
require.False(t, resp.CompleteListing)
|
||||
require.Len(t, resp.Items, 1)
|
||||
require.Equal(t, resp.EstimatedItemCount, 6)
|
||||
require.Empty(t, resp.DeletedIds)
|
||||
require.Empty(t, cmp.Diff(resp.Items[0], ams[0], cmpOpts...))
|
||||
|
||||
resp2, err := auth.ListAuthMethodsPage(ctx, []byte("some hash"), 1, filterFunc, resp.ListToken, repo, []string{org.PublicId}, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, resp2.ListToken.GrantsHash, []byte("some hash"))
|
||||
require.False(t, resp2.CompleteListing)
|
||||
require.Equal(t, resp2.EstimatedItemCount, 6)
|
||||
require.Empty(t, resp2.DeletedIds)
|
||||
require.Len(t, resp2.Items, 1)
|
||||
require.Empty(t, cmp.Diff(resp2.Items[0], ams[1], cmpOpts...))
|
||||
|
||||
resp3, err := auth.ListAuthMethodsPage(ctx, []byte("some hash"), 1, filterFunc, resp2.ListToken, repo, []string{org.PublicId}, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, resp3.ListToken.GrantsHash, []byte("some hash"))
|
||||
require.False(t, resp3.CompleteListing)
|
||||
require.Equal(t, resp3.EstimatedItemCount, 6)
|
||||
require.Empty(t, resp3.DeletedIds)
|
||||
require.Len(t, resp3.Items, 1)
|
||||
require.Empty(t, cmp.Diff(resp3.Items[0], ams[2], cmpOpts...))
|
||||
|
||||
resp4, err := auth.ListAuthMethodsPage(ctx, []byte("some hash"), 1, filterFunc, resp3.ListToken, repo, []string{org.PublicId}, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, resp4.ListToken.GrantsHash, []byte("some hash"))
|
||||
require.False(t, resp4.CompleteListing)
|
||||
require.Equal(t, resp4.EstimatedItemCount, 6)
|
||||
require.Empty(t, resp4.DeletedIds)
|
||||
require.Len(t, resp4.Items, 1)
|
||||
require.Empty(t, cmp.Diff(resp4.Items[0], ams[3], cmpOpts...))
|
||||
|
||||
// get the rest
|
||||
resp5, err := auth.ListAuthMethodsPage(ctx, []byte("some hash"), 2, filterFunc, resp4.ListToken, repo, []string{org.PublicId}, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, resp5.ListToken.GrantsHash, []byte("some hash"))
|
||||
require.True(t, resp5.CompleteListing)
|
||||
require.Equal(t, resp5.EstimatedItemCount, 6)
|
||||
require.Empty(t, resp5.DeletedIds)
|
||||
require.Len(t, resp5.Items, 2)
|
||||
require.Empty(t, cmp.Diff(resp5.Items, ams[4:], cmpOpts...))
|
||||
|
||||
// Finished initial pagination phase, request refresh
|
||||
// Expect no results.
|
||||
resp6, err := auth.ListAuthMethodsRefresh(ctx, []byte("some hash"), 1, filterFunc, resp5.ListToken, repo, []string{org.PublicId}, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, resp6.ListToken.GrantsHash, []byte("some hash"))
|
||||
require.True(t, resp6.CompleteListing)
|
||||
require.Equal(t, resp6.EstimatedItemCount, 6)
|
||||
require.Empty(t, resp6.DeletedIds)
|
||||
require.Empty(t, resp6.Items)
|
||||
|
||||
// Create some new auth methods
|
||||
am1 := ldap.TestAuthMethod(t, conn, databaseWrapper, org.PublicId, []string{"ldaps://ldap1.alice.com"}, ldap.WithOperationalState(ctx, ldap.InactiveState))
|
||||
am2 := oidc.TestAuthMethod(t, conn, databaseWrapper, org.PublicId, oidc.InactiveState, "charlene_rp", "charlenes-dogs-name",
|
||||
oidc.WithIssuer(oidc.TestConvertToUrls(t, "https://charlene-inactive.com")[0]), oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://api.com")[0]))
|
||||
am3 := password.TestAuthMethod(t, conn, org.GetPublicId())
|
||||
t.Cleanup(func() {
|
||||
_, err := ldapRepo.DeleteAuthMethod(ctx, am1.PublicId)
|
||||
require.NoError(t, err)
|
||||
_, err = oidcRepo.DeleteAuthMethod(ctx, am2.PublicId)
|
||||
require.NoError(t, err)
|
||||
_, err = passwordRepo.DeleteAuthMethod(ctx, org.PublicId, am3.PublicId)
|
||||
require.NoError(t, err)
|
||||
// Run analyze to update count estimate
|
||||
_, err = sqlDb.ExecContext(ctx, "analyze")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
// Run analyze to update count estimate
|
||||
_, err = sqlDb.ExecContext(ctx, "analyze")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Refresh again, should get am3
|
||||
resp7, err := auth.ListAuthMethodsRefresh(ctx, []byte("some hash"), 1, filterFunc, resp6.ListToken, repo, []string{org.PublicId}, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, resp7.ListToken.GrantsHash, []byte("some hash"))
|
||||
require.False(t, resp7.CompleteListing)
|
||||
require.Equal(t, resp7.EstimatedItemCount, 9)
|
||||
require.Empty(t, resp7.DeletedIds)
|
||||
require.Len(t, resp7.Items, 1)
|
||||
require.Empty(t, cmp.Diff(resp7.Items[0], am3, cmpOpts...))
|
||||
|
||||
// Refresh again, should get am2
|
||||
resp8, err := auth.ListAuthMethodsRefreshPage(ctx, []byte("some hash"), 1, filterFunc, resp7.ListToken, repo, []string{org.PublicId}, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, resp8.ListToken.GrantsHash, []byte("some hash"))
|
||||
require.False(t, resp8.CompleteListing)
|
||||
require.Equal(t, resp8.EstimatedItemCount, 9)
|
||||
require.Empty(t, resp8.DeletedIds)
|
||||
require.Len(t, resp8.Items, 1)
|
||||
require.Empty(t, cmp.Diff(resp8.Items[0], am2, cmpOpts...))
|
||||
|
||||
// Refresh again, should get am1
|
||||
resp9, err := auth.ListAuthMethodsRefreshPage(ctx, []byte("some hash"), 1, filterFunc, resp8.ListToken, repo, []string{org.PublicId}, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, resp9.ListToken.GrantsHash, []byte("some hash"))
|
||||
require.True(t, resp9.CompleteListing)
|
||||
require.Equal(t, resp9.EstimatedItemCount, 9)
|
||||
require.Empty(t, resp9.DeletedIds)
|
||||
require.Len(t, resp9.Items, 1)
|
||||
require.Empty(t, cmp.Diff(resp9.Items[0], am1, cmpOpts...))
|
||||
|
||||
// Refresh again, should get no results
|
||||
resp10, err := auth.ListAuthMethodsRefresh(ctx, []byte("some hash"), 1, filterFunc, resp9.ListToken, repo, []string{org.PublicId}, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, resp10.ListToken.GrantsHash, []byte("some hash"))
|
||||
require.True(t, resp10.CompleteListing)
|
||||
require.Equal(t, resp10.EstimatedItemCount, 9)
|
||||
require.Empty(t, resp10.DeletedIds)
|
||||
require.Empty(t, resp10.Items)
|
||||
})
|
||||
|
||||
t.Run("simple pagination with aggressive filtering", func(t *testing.T) {
|
||||
filterFunc := func(ctx context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return am.GetPublicId() == ams[1].GetPublicId() ||
|
||||
am.GetPublicId() == ams[len(ams)-1].GetPublicId(), nil
|
||||
}
|
||||
resp, err := auth.ListAuthMethods(ctx, []byte("some hash"), 1, filterFunc, repo, []string{org.PublicId}, false)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp.ListToken)
|
||||
require.Equal(t, resp.ListToken.GrantsHash, []byte("some hash"))
|
||||
require.False(t, resp.CompleteListing)
|
||||
require.Equal(t, resp.EstimatedItemCount, 6)
|
||||
require.Empty(t, resp.DeletedIds)
|
||||
require.Len(t, resp.Items, 1)
|
||||
require.Empty(t, cmp.Diff(resp.Items[0], ams[1], cmpOpts...))
|
||||
|
||||
resp2, err := auth.ListAuthMethodsPage(ctx, []byte("some hash"), 2, filterFunc, resp.ListToken, repo, []string{org.PublicId}, false)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp2.ListToken)
|
||||
require.Equal(t, resp2.ListToken.GrantsHash, []byte("some hash"))
|
||||
require.True(t, resp2.CompleteListing)
|
||||
require.Equal(t, resp2.EstimatedItemCount, 6)
|
||||
require.Empty(t, resp2.DeletedIds)
|
||||
require.Len(t, resp2.Items, 1)
|
||||
require.Empty(t, cmp.Diff(resp2.Items[0], ams[len(ams)-1], cmpOpts...))
|
||||
|
||||
// request a refresh, nothing should be returned
|
||||
resp3, err := auth.ListAuthMethodsRefresh(ctx, []byte("some hash"), 1, filterFunc, resp.ListToken, repo, []string{org.PublicId}, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, resp3.ListToken.GrantsHash, []byte("some hash"))
|
||||
require.True(t, resp3.CompleteListing)
|
||||
require.Equal(t, resp3.EstimatedItemCount, 6)
|
||||
require.Empty(t, resp3.DeletedIds)
|
||||
require.Empty(t, resp3.Items)
|
||||
|
||||
// Create some new auth methods
|
||||
am1 := ldap.TestAuthMethod(t, conn, databaseWrapper, org.PublicId, []string{"ldaps://ldap1.alice.com"}, ldap.WithOperationalState(ctx, ldap.InactiveState))
|
||||
am2 := oidc.TestAuthMethod(t, conn, databaseWrapper, org.PublicId, oidc.InactiveState, "charlene_rp", "charlenes-dogs-name",
|
||||
oidc.WithIssuer(oidc.TestConvertToUrls(t, "https://charlene-inactive.com")[0]), oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://api.com")[0]))
|
||||
am3 := password.TestAuthMethod(t, conn, org.GetPublicId())
|
||||
t.Cleanup(func() {
|
||||
_, err := ldapRepo.DeleteAuthMethod(ctx, am1.PublicId)
|
||||
require.NoError(t, err)
|
||||
_, err = oidcRepo.DeleteAuthMethod(ctx, am2.PublicId)
|
||||
require.NoError(t, err)
|
||||
_, err = passwordRepo.DeleteAuthMethod(ctx, org.PublicId, am3.PublicId)
|
||||
require.NoError(t, err)
|
||||
// Run analyze to update count estimate
|
||||
_, err = sqlDb.ExecContext(ctx, "analyze")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
// Run analyze to update count estimate
|
||||
_, err = sqlDb.ExecContext(ctx, "analyze")
|
||||
require.NoError(t, err)
|
||||
|
||||
filterFunc = func(ctx context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return am.GetPublicId() == am1.GetPublicId() ||
|
||||
am.GetPublicId() == am3.GetPublicId(), nil
|
||||
}
|
||||
// Refresh again, should get am3
|
||||
resp4, err := auth.ListAuthMethodsRefresh(ctx, []byte("some hash"), 1, filterFunc, resp3.ListToken, repo, []string{org.PublicId}, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, resp4.ListToken.GrantsHash, []byte("some hash"))
|
||||
require.False(t, resp4.CompleteListing)
|
||||
require.Equal(t, resp4.EstimatedItemCount, 9)
|
||||
require.Empty(t, resp4.DeletedIds)
|
||||
require.Len(t, resp4.Items, 1)
|
||||
require.Empty(t, cmp.Diff(resp4.Items[0], am3, cmpOpts...))
|
||||
|
||||
// Refresh again, should get am1
|
||||
resp5, err := auth.ListAuthMethodsRefreshPage(ctx, []byte("some hash"), 1, filterFunc, resp4.ListToken, repo, []string{org.PublicId}, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, resp5.ListToken.GrantsHash, []byte("some hash"))
|
||||
require.True(t, resp5.CompleteListing)
|
||||
require.Equal(t, resp5.EstimatedItemCount, 9)
|
||||
require.Empty(t, resp5.DeletedIds)
|
||||
require.Len(t, resp5.Items, 1)
|
||||
require.Empty(t, cmp.Diff(resp5.Items[0], am1, cmpOpts...))
|
||||
})
|
||||
|
||||
t.Run("simple pagination with deletion", func(t *testing.T) {
|
||||
filterFunc := func(ctx context.Context, am auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
// delete passwords
|
||||
deletedAmId1 := ams[0].GetPublicId()
|
||||
_, err := passwordRepo.DeleteAuthMethod(ctx, org.GetPublicId(), deletedAmId1)
|
||||
require.NoError(t, err)
|
||||
ams = ams[1:]
|
||||
deletedAmId2 := ams[0].GetPublicId()
|
||||
_, err = passwordRepo.DeleteAuthMethod(ctx, org.GetPublicId(), deletedAmId2)
|
||||
require.NoError(t, err)
|
||||
ams = ams[1:]
|
||||
|
||||
// Run analyze to update count estimate
|
||||
_, err = sqlDb.ExecContext(ctx, "analyze")
|
||||
require.NoError(t, err)
|
||||
|
||||
resp, err := auth.ListAuthMethods(ctx, []byte("some hash"), 1, filterFunc, repo, []string{org.PublicId}, false)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp.ListToken)
|
||||
require.Equal(t, resp.ListToken.GrantsHash, []byte("some hash"))
|
||||
require.False(t, resp.CompleteListing)
|
||||
require.Equal(t, resp.EstimatedItemCount, 4)
|
||||
require.Empty(t, resp.DeletedIds)
|
||||
require.Len(t, resp.Items, 1)
|
||||
require.Empty(t, cmp.Diff(resp.Items[0], ams[0], cmpOpts...))
|
||||
|
||||
// request remaining results
|
||||
resp2, err := auth.ListAuthMethodsPage(ctx, []byte("some hash"), 3, filterFunc, resp.ListToken, repo, []string{org.PublicId}, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, resp2.ListToken.GrantsHash, []byte("some hash"))
|
||||
require.True(t, resp2.CompleteListing)
|
||||
require.Equal(t, resp2.EstimatedItemCount, 4)
|
||||
require.Empty(t, resp2.DeletedIds)
|
||||
require.Len(t, resp2.Items, 3)
|
||||
require.Empty(t, cmp.Diff(resp2.Items, ams[1:], cmpOpts...))
|
||||
|
||||
// delete oidcs
|
||||
deletedAmId3 := ams[0].GetPublicId()
|
||||
_, err = oidcRepo.DeleteAuthMethod(ctx, deletedAmId3)
|
||||
require.NoError(t, err)
|
||||
ams = ams[1:]
|
||||
deletedAmId4 := ams[0].GetPublicId()
|
||||
_, err = oidcRepo.DeleteAuthMethod(ctx, deletedAmId4)
|
||||
require.NoError(t, err)
|
||||
ams = ams[1:]
|
||||
|
||||
// Run analyze to update count estimate
|
||||
_, err = sqlDb.ExecContext(ctx, "analyze")
|
||||
require.NoError(t, err)
|
||||
|
||||
resp3, err := auth.ListAuthMethodsRefresh(ctx, []byte("some hash"), 1, filterFunc, resp2.ListToken, repo, []string{org.PublicId}, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, resp3.ListToken.GrantsHash, []byte("some hash"))
|
||||
require.True(t, resp3.CompleteListing)
|
||||
require.Equal(t, resp3.EstimatedItemCount, 2)
|
||||
assert.Empty(t, cmp.Diff(resp3.DeletedIds, []string{deletedAmId3, deletedAmId4}, cmpopts.SortSlices(func(a, b string) bool { return a < b })))
|
||||
require.Empty(t, resp3.Items)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
"github.com/hashicorp/boundary/internal/listtoken"
|
||||
"github.com/hashicorp/boundary/internal/pagination"
|
||||
"github.com/hashicorp/boundary/internal/types/resource"
|
||||
)
|
||||
|
||||
// ListAuthMethodsPage lists up to page size auth methods, filtering out entries that
|
||||
// do not pass the filter item function. It will automatically request
|
||||
// more auth methods from the database, at page size chunks, to fill the page.
|
||||
// It will start its paging based on the information in the token.
|
||||
// It returns a new list token used to continue pagination or refresh items.
|
||||
// Auth methods are ordered by create time descending (most recently created first).
|
||||
func ListAuthMethodsPage(
|
||||
ctx context.Context,
|
||||
grantsHash []byte,
|
||||
pageSize int,
|
||||
filterItemFn pagination.ListFilterFunc[AuthMethod],
|
||||
tok *listtoken.Token,
|
||||
repo *AuthMethodRepository,
|
||||
scopeIds []string,
|
||||
withUnauthenticatedUser bool,
|
||||
) (*pagination.ListResponse[AuthMethod], error) {
|
||||
const op = "auth.ListAuthMethodsPage"
|
||||
|
||||
switch {
|
||||
case len(grantsHash) == 0:
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing grants hash")
|
||||
case pageSize < 1:
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "page size must be at least 1")
|
||||
case filterItemFn == nil:
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing filter item callback")
|
||||
case tok == nil:
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing token")
|
||||
case repo == nil:
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing repo")
|
||||
case len(scopeIds) == 0:
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing scope ids")
|
||||
case tok.ResourceType != resource.AuthMethod:
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "token did not have an auth method resource type")
|
||||
}
|
||||
if _, ok := tok.Subtype.(*listtoken.PaginationToken); !ok {
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "token did not have a pagination token component")
|
||||
}
|
||||
|
||||
listItemsFn := func(ctx context.Context, lastPageItem AuthMethod, limit int) ([]AuthMethod, time.Time, error) {
|
||||
opts := []Option{
|
||||
WithLimit(ctx, limit),
|
||||
}
|
||||
if withUnauthenticatedUser {
|
||||
opts = append(opts, WithUnauthenticatedUser(ctx, true))
|
||||
}
|
||||
|
||||
if lastPageItem != nil {
|
||||
return repo.List(ctx, scopeIds, lastPageItem, opts...)
|
||||
}
|
||||
lastItem, err := tok.LastItem(ctx)
|
||||
if err != nil {
|
||||
return nil, time.Time{}, err
|
||||
}
|
||||
return repo.List(ctx, scopeIds, lastItem, opts...)
|
||||
}
|
||||
|
||||
return pagination.ListPage(ctx, grantsHash, pageSize, filterItemFn, listItemsFn, repo.EstimatedCount, tok)
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
"github.com/hashicorp/boundary/internal/listtoken"
|
||||
"github.com/hashicorp/boundary/internal/pagination"
|
||||
"github.com/hashicorp/boundary/internal/types/resource"
|
||||
)
|
||||
|
||||
// ListAuthMethodsRefresh lists up to page size auth methods, filtering out entries that
|
||||
// do not pass the filter item function. It will automatically request
|
||||
// more auth methods from the database, at page size chunks, to fill the page.
|
||||
// It will start its paging based on the information in the token.
|
||||
// It returns a new list token used to continue pagination or refresh items.
|
||||
// Auth methods are ordered by update time descending (most recently updated first).
|
||||
// Auth methods may contain items that were already returned during the initial
|
||||
// pagination phase. It also returns a list of any auth methods deleted since the
|
||||
// start of the initial pagination phase or last response.
|
||||
func ListAuthMethodsRefresh(
|
||||
ctx context.Context,
|
||||
grantsHash []byte,
|
||||
pageSize int,
|
||||
filterItemFn pagination.ListFilterFunc[AuthMethod],
|
||||
tok *listtoken.Token,
|
||||
repo *AuthMethodRepository,
|
||||
scopeIds []string,
|
||||
withUnauthenticatedUser bool,
|
||||
) (*pagination.ListResponse[AuthMethod], error) {
|
||||
const op = "auth.ListAuthMethodsRefresh"
|
||||
|
||||
switch {
|
||||
case len(grantsHash) == 0:
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing grants hash")
|
||||
case pageSize < 1:
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "page size must be at least 1")
|
||||
case filterItemFn == nil:
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing filter item callback")
|
||||
case tok == nil:
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing token")
|
||||
case repo == nil:
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing repo")
|
||||
case len(scopeIds) == 0:
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing scope ids")
|
||||
case tok.ResourceType != resource.AuthMethod:
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "token did not have an auth method resource type")
|
||||
}
|
||||
rt, ok := tok.Subtype.(*listtoken.StartRefreshToken)
|
||||
if !ok {
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "token did not have a start-refresh token component")
|
||||
}
|
||||
|
||||
listItemsFn := func(ctx context.Context, lastPageItem AuthMethod, limit int) ([]AuthMethod, time.Time, error) {
|
||||
opts := []Option{
|
||||
WithLimit(ctx, limit),
|
||||
}
|
||||
if withUnauthenticatedUser {
|
||||
opts = append(opts, WithUnauthenticatedUser(ctx, true))
|
||||
}
|
||||
// Add the database read timeout to account for any creations missed due to concurrent
|
||||
// transactions in the initial pagination phase.
|
||||
return repo.ListRefresh(ctx, scopeIds, rt.PreviousPhaseUpperBound.Add(-globals.RefreshReadLookbackDuration), lastPageItem, opts...)
|
||||
}
|
||||
listDeletedIDsFn := func(ctx context.Context, since time.Time) ([]string, time.Time, error) {
|
||||
// Add the database read timeout to account for any deletions missed due to concurrent
|
||||
// transactions in previous requests.
|
||||
since = since.Add(-globals.RefreshReadLookbackDuration)
|
||||
return repo.ListDeletedIds(ctx, since)
|
||||
}
|
||||
|
||||
return pagination.ListRefresh(ctx, grantsHash, pageSize, filterItemFn, listItemsFn, repo.EstimatedCount, listDeletedIDsFn, tok)
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
"github.com/hashicorp/boundary/internal/listtoken"
|
||||
"github.com/hashicorp/boundary/internal/pagination"
|
||||
"github.com/hashicorp/boundary/internal/types/resource"
|
||||
)
|
||||
|
||||
// ListAuthMethodsRefreshPage lists up to page size auth methods, filtering out entries that
|
||||
// do not pass the filter item function. It will automatically request
|
||||
// more auth methods from the database, at page size chunks, to fill the page.
|
||||
// It will start its paging based on the information in the token.
|
||||
// It returns a new list token used to continue pagination or refresh items.
|
||||
// Auth methods are ordered by update time descending (most recently updated first).
|
||||
// Auth methods may contain items that were already returned during the initial
|
||||
// pagination phase. It also returns a list of any auth methods deleted since the
|
||||
// last response.
|
||||
func ListAuthMethodsRefreshPage(
|
||||
ctx context.Context,
|
||||
grantsHash []byte,
|
||||
pageSize int,
|
||||
filterItemFn pagination.ListFilterFunc[AuthMethod],
|
||||
tok *listtoken.Token,
|
||||
repo *AuthMethodRepository,
|
||||
scopeIds []string,
|
||||
withUnauthenticatedUser bool,
|
||||
) (*pagination.ListResponse[AuthMethod], error) {
|
||||
const op = "auth.ListAuthMethodsRefreshPage"
|
||||
|
||||
switch {
|
||||
case len(grantsHash) == 0:
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing grants hash")
|
||||
case pageSize < 1:
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "page size must be at least 1")
|
||||
case filterItemFn == nil:
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing filter item callback")
|
||||
case tok == nil:
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing token")
|
||||
case repo == nil:
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing repo")
|
||||
case len(scopeIds) == 0:
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "missing scope ids")
|
||||
case tok.ResourceType != resource.AuthMethod:
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "token did not have an auth method resource type")
|
||||
}
|
||||
rt, ok := tok.Subtype.(*listtoken.RefreshToken)
|
||||
if !ok {
|
||||
return nil, errors.New(ctx, errors.InvalidParameter, op, "token did not have a refresh token component")
|
||||
}
|
||||
|
||||
listItemsFn := func(ctx context.Context, lastPageItem AuthMethod, limit int) ([]AuthMethod, time.Time, error) {
|
||||
// Add the database read timeout to account for any creations missed due to concurrent
|
||||
// transactions in the initial pagination phase.
|
||||
opts := []Option{
|
||||
WithLimit(ctx, limit),
|
||||
}
|
||||
if withUnauthenticatedUser {
|
||||
opts = append(opts, WithUnauthenticatedUser(ctx, true))
|
||||
}
|
||||
|
||||
since := rt.PhaseLowerBound.Add(-globals.RefreshReadLookbackDuration)
|
||||
if lastPageItem != nil {
|
||||
return repo.ListRefresh(ctx, scopeIds, since, lastPageItem, opts...)
|
||||
}
|
||||
lastItem, err := tok.LastItem(ctx)
|
||||
if err != nil {
|
||||
return nil, time.Time{}, err
|
||||
}
|
||||
return repo.ListRefresh(ctx, scopeIds, since, lastItem, opts...)
|
||||
}
|
||||
listDeletedIDsFn := func(ctx context.Context, since time.Time) ([]string, time.Time, error) {
|
||||
// Add the database read timeout to account for any deletes missed due to concurrent
|
||||
// transactions in the original list pagination phase.
|
||||
return repo.ListDeletedIds(ctx, since.Add(-globals.RefreshReadLookbackDuration))
|
||||
}
|
||||
|
||||
return pagination.ListRefreshPage(ctx, grantsHash, pageSize, filterItemFn, listItemsFn, repo.EstimatedCount, listDeletedIDsFn, tok)
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/boundary/internal/auth"
|
||||
"github.com/hashicorp/boundary/internal/auth/ldap"
|
||||
"github.com/hashicorp/boundary/internal/auth/oidc"
|
||||
"github.com/hashicorp/boundary/internal/auth/password"
|
||||
@@ -28,6 +29,7 @@ type (
|
||||
OidcAuthRepoFactory = oidc.OidcRepoFactory
|
||||
LdapAuthRepoFactory = ldap.RepoFactory
|
||||
PasswordAuthRepoFactory func() (*password.Repository, error)
|
||||
AuthMethodRepoFactory func() (*auth.AuthMethodRepository, error)
|
||||
ServersRepoFactory func() (*server.Repository, error)
|
||||
StaticRepoFactory func() (*static.Repository, error)
|
||||
PluginHostRepoFactory func() (*pluginhost.Repository, error)
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/auth"
|
||||
"github.com/hashicorp/boundary/internal/auth/ldap"
|
||||
"github.com/hashicorp/boundary/internal/auth/oidc"
|
||||
"github.com/hashicorp/boundary/internal/auth/password"
|
||||
@@ -134,6 +135,7 @@ type Controller struct {
|
||||
OidcRepoFn common.OidcAuthRepoFactory
|
||||
LdapRepoFn common.LdapAuthRepoFactory
|
||||
PasswordAuthRepoFn common.PasswordAuthRepoFactory
|
||||
AuthMethodRepoFn common.AuthMethodRepoFactory
|
||||
ServersRepoFn common.ServersRepoFactory
|
||||
SessionRepoFn session.RepositoryFactory
|
||||
ConnectionRepoFn common.ConnectionRepoFactory
|
||||
@@ -422,6 +424,9 @@ func New(ctx context.Context, conf *Config) (*Controller, error) {
|
||||
c.PasswordAuthRepoFn = func() (*password.Repository, error) {
|
||||
return password.NewRepository(ctx, dbase, dbase, c.kms)
|
||||
}
|
||||
c.AuthMethodRepoFn = func() (*auth.AuthMethodRepository, error) {
|
||||
return auth.NewAuthMethodRepository(ctx, dbase, dbase, c.kms)
|
||||
}
|
||||
c.TargetRepoFn = func(o ...target.Option) (*target.Repository, error) {
|
||||
return target.NewRepository(ctx, dbase, dbase, c.kms, o...)
|
||||
}
|
||||
|
||||
@@ -164,7 +164,17 @@ func (c *Controller) registerGrpcServices(s *grpc.Server) error {
|
||||
services.RegisterAccountServiceServer(s, accts)
|
||||
}
|
||||
if _, ok := currentServices[services.AuthMethodService_ServiceDesc.ServiceName]; !ok {
|
||||
authMethods, err := authmethods.NewService(c.baseContext, c.kms, c.PasswordAuthRepoFn, c.OidcRepoFn, c.IamRepoFn, c.AuthTokenRepoFn, c.LdapRepoFn)
|
||||
authMethods, err := authmethods.NewService(
|
||||
c.baseContext,
|
||||
c.kms,
|
||||
c.PasswordAuthRepoFn,
|
||||
c.OidcRepoFn,
|
||||
c.IamRepoFn,
|
||||
c.AuthTokenRepoFn,
|
||||
c.LdapRepoFn,
|
||||
c.AuthMethodRepoFn,
|
||||
c.conf.RawConfig.Controller.MaxPageSize,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create auth method handler service: %w", err)
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/listtoken"
|
||||
"github.com/hashicorp/boundary/internal/pagination"
|
||||
"github.com/hashicorp/boundary/internal/perms"
|
||||
"github.com/hashicorp/boundary/internal/requests"
|
||||
"github.com/hashicorp/boundary/internal/types/action"
|
||||
@@ -57,8 +59,6 @@ const (
|
||||
authMethodIdField = "auth_method_id"
|
||||
tokenTypeField = "type"
|
||||
isPrimaryField = "is_primary"
|
||||
|
||||
domain = "auth"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -84,18 +84,31 @@ var (
|
||||
type Service struct {
|
||||
pbs.UnsafeAuthMethodServiceServer
|
||||
|
||||
kms *kms.Kms
|
||||
pwRepoFn common.PasswordAuthRepoFactory
|
||||
oidcRepoFn common.OidcAuthRepoFactory
|
||||
iamRepoFn common.IamRepoFactory
|
||||
atRepoFn common.AuthTokenRepoFactory
|
||||
ldapRepoFn common.LdapAuthRepoFactory
|
||||
kms *kms.Kms
|
||||
pwRepoFn common.PasswordAuthRepoFactory
|
||||
oidcRepoFn common.OidcAuthRepoFactory
|
||||
iamRepoFn common.IamRepoFactory
|
||||
atRepoFn common.AuthTokenRepoFactory
|
||||
ldapRepoFn common.LdapAuthRepoFactory
|
||||
amRepoFn common.AuthMethodRepoFactory
|
||||
maxPageSize uint
|
||||
}
|
||||
|
||||
var _ pbs.AuthMethodServiceServer = (*Service)(nil)
|
||||
|
||||
// NewService returns a auth method service which handles auth method related requests to boundary.
|
||||
func NewService(ctx context.Context, kms *kms.Kms, pwRepoFn common.PasswordAuthRepoFactory, oidcRepoFn common.OidcAuthRepoFactory, iamRepoFn common.IamRepoFactory, atRepoFn common.AuthTokenRepoFactory, ldapRepoFn common.LdapAuthRepoFactory, opt ...handlers.Option) (Service, error) {
|
||||
func NewService(
|
||||
ctx context.Context,
|
||||
kms *kms.Kms,
|
||||
pwRepoFn common.PasswordAuthRepoFactory,
|
||||
oidcRepoFn common.OidcAuthRepoFactory,
|
||||
iamRepoFn common.IamRepoFactory,
|
||||
atRepoFn common.AuthTokenRepoFactory,
|
||||
ldapRepoFn common.LdapAuthRepoFactory,
|
||||
amRepoFn common.AuthMethodRepoFactory,
|
||||
maxPageSize uint,
|
||||
opt ...handlers.Option,
|
||||
) (Service, error) {
|
||||
const op = "authmethods.NewService"
|
||||
if kms == nil {
|
||||
return Service{}, errors.New(ctx, errors.InvalidParameter, op, "missing kms")
|
||||
@@ -115,15 +128,32 @@ func NewService(ctx context.Context, kms *kms.Kms, pwRepoFn common.PasswordAuthR
|
||||
if atRepoFn == nil {
|
||||
return Service{}, fmt.Errorf("nil auth token repository provided")
|
||||
}
|
||||
s := Service{kms: kms, pwRepoFn: pwRepoFn, oidcRepoFn: oidcRepoFn, iamRepoFn: iamRepoFn, atRepoFn: atRepoFn, ldapRepoFn: ldapRepoFn}
|
||||
if amRepoFn == nil {
|
||||
return Service{}, fmt.Errorf("nil auth method repository provided")
|
||||
}
|
||||
if maxPageSize == 0 {
|
||||
maxPageSize = uint(globals.DefaultMaxPageSize)
|
||||
}
|
||||
s := Service{
|
||||
kms: kms,
|
||||
pwRepoFn: pwRepoFn,
|
||||
oidcRepoFn: oidcRepoFn,
|
||||
iamRepoFn: iamRepoFn,
|
||||
atRepoFn: atRepoFn,
|
||||
ldapRepoFn: ldapRepoFn,
|
||||
amRepoFn: amRepoFn,
|
||||
maxPageSize: maxPageSize,
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// ListAuthMethods implements the interface pbs.AuthMethodServiceServer.
|
||||
func (s Service) ListAuthMethods(ctx context.Context, req *pbs.ListAuthMethodsRequest) (*pbs.ListAuthMethodsResponse, error) {
|
||||
const op = "authmethods.(Service).ListAuthMethods"
|
||||
|
||||
if err := validateListRequest(ctx, req); err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
authResults := s.authResult(ctx, req.GetScopeId(), action.List)
|
||||
if authResults.Error != nil {
|
||||
@@ -138,6 +168,21 @@ func (s Service) ListAuthMethods(ctx context.Context, req *pbs.ListAuthMethodsRe
|
||||
return nil, authResults.Error
|
||||
}
|
||||
}
|
||||
pageSize := int(s.maxPageSize)
|
||||
// Use the requested page size only if it is smaller than
|
||||
// the configured max.
|
||||
if req.GetPageSize() != 0 && uint(req.GetPageSize()) < s.maxPageSize {
|
||||
pageSize = int(req.GetPageSize())
|
||||
}
|
||||
|
||||
withUnauthenticatedUser := false
|
||||
reqCtx, ok := requests.RequestContextFromCtx(ctx)
|
||||
if !ok {
|
||||
return nil, errors.New(ctx, errors.Internal, op, "no request context found")
|
||||
}
|
||||
if reqCtx.UserId == globals.AnonymousUserId {
|
||||
withUnauthenticatedUser = true
|
||||
}
|
||||
|
||||
scopeIds, scopeInfoMap, err := scopeids.GetListingScopeIds(
|
||||
ctx, s.iamRepoFn, authResults, req.GetScopeId(), resource.AuthMethod, req.GetRecursive())
|
||||
@@ -149,63 +194,127 @@ func (s Service) ListAuthMethods(ctx context.Context, req *pbs.ListAuthMethodsRe
|
||||
return &pbs.ListAuthMethodsResponse{}, nil
|
||||
}
|
||||
|
||||
ul, err := s.listFromRepo(ctx, scopeIds, authResults)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(ul) == 0 {
|
||||
return &pbs.ListAuthMethodsResponse{}, nil
|
||||
var filterItemFn func(ctx context.Context, item auth.AuthMethod) (bool, error)
|
||||
switch {
|
||||
case req.GetFilter() != "":
|
||||
// Only use a filter if we need to
|
||||
filter, err := handlers.NewFilter(ctx, req.GetFilter())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// TODO: replace the need for this function with some way to convert the `filter`
|
||||
// to a domain type. This would allow filtering to happen in the domain, and we could
|
||||
// remove this callback altogether.
|
||||
filterItemFn = func(ctx context.Context, item auth.AuthMethod) (bool, error) {
|
||||
outputOpts, ok, err := newOutputOpts(ctx, item, scopeInfoMap, authResults)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
if !ok {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
pbItem, err := toAuthMethodProto(ctx, item, outputOpts...)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
filterable, err := subtypes.Filterable(ctx, pbItem)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return filter.Match(filterable), nil
|
||||
}
|
||||
default:
|
||||
filterItemFn = func(ctx context.Context, item auth.AuthMethod) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
filter, err := handlers.NewFilter(ctx, req.GetFilter())
|
||||
repo, err := s.amRepoFn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
finalItems := make([]*pb.AuthMethod, 0, len(ul))
|
||||
res := perms.Resource{
|
||||
Type: resource.AuthMethod,
|
||||
}
|
||||
for _, am := range ul {
|
||||
res.Id = am.GetPublicId()
|
||||
res.ScopeId = am.GetScopeId()
|
||||
authorizedActions := authResults.FetchActionSetForId(ctx, am.GetPublicId(), IdActions[globals.ResourceInfoFromPrefix(am.GetPublicId()).Subtype], requestauth.WithResource(&res)).Strings()
|
||||
if len(authorizedActions) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
outputFields := authResults.FetchOutputFields(res, action.List).SelfOrDefaults(authResults.UserId)
|
||||
outputOpts := make([]handlers.Option, 0, 3)
|
||||
outputOpts = append(outputOpts, handlers.WithOutputFields(outputFields))
|
||||
if outputFields.Has(globals.ScopeField) {
|
||||
outputOpts = append(outputOpts, handlers.WithScope(scopeInfoMap[am.GetScopeId()]))
|
||||
grantsHash, err := authResults.GrantsHash(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
|
||||
var listResp *pagination.ListResponse[auth.AuthMethod]
|
||||
var sortBy string
|
||||
if req.GetListToken() == "" {
|
||||
sortBy = "created_time"
|
||||
listResp, err = auth.ListAuthMethods(ctx, grantsHash, pageSize, filterItemFn, repo, scopeIds, withUnauthenticatedUser)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if outputFields.Has(globals.AuthorizedActionsField) {
|
||||
outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authorizedActions))
|
||||
} else {
|
||||
listToken, err := handlers.ParseListToken(ctx, req.GetListToken(), resource.AuthMethod, grantsHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if outputFields.Has(globals.AuthorizedCollectionActionsField) {
|
||||
collectionActions, err := requestauth.CalculateAuthorizedCollectionActions(ctx, authResults, collectionTypeMap, authResults.Scope.Id, am.GetPublicId())
|
||||
switch st := listToken.Subtype.(type) {
|
||||
case *listtoken.PaginationToken:
|
||||
sortBy = "created_time"
|
||||
listResp, err = auth.ListAuthMethodsPage(ctx, grantsHash, pageSize, filterItemFn, listToken, repo, scopeIds, withUnauthenticatedUser)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outputOpts = append(outputOpts, handlers.WithAuthorizedCollectionActions(collectionActions))
|
||||
}
|
||||
|
||||
item, err := toAuthMethodProto(ctx, am, outputOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// This comes last so that we can use item fields in the filter after
|
||||
// the allowed fields are populated above
|
||||
filterable, err := subtypes.Filterable(ctx, item)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if filter.Match(filterable) {
|
||||
finalItems = append(finalItems, item)
|
||||
case *listtoken.StartRefreshToken:
|
||||
sortBy = "updated_time"
|
||||
listResp, err = auth.ListAuthMethodsRefresh(ctx, grantsHash, pageSize, filterItemFn, listToken, repo, scopeIds, withUnauthenticatedUser)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case *listtoken.RefreshToken:
|
||||
sortBy = "updated_time"
|
||||
listResp, err = auth.ListAuthMethodsRefreshPage(ctx, grantsHash, pageSize, filterItemFn, listToken, repo, scopeIds, withUnauthenticatedUser)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, handlers.ApiErrorWithCodeAndMessage(codes.InvalidArgument, "unexpected list token subtype: %T", st)
|
||||
}
|
||||
}
|
||||
return &pbs.ListAuthMethodsResponse{Items: finalItems}, nil
|
||||
|
||||
finalItems := make([]*pb.AuthMethod, 0, len(listResp.Items))
|
||||
for _, item := range listResp.Items {
|
||||
outputOpts, ok, err := newOutputOpts(ctx, item, scopeInfoMap, authResults)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
pbItem, err := toAuthMethodProto(ctx, item, outputOpts...)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
finalItems = append(finalItems, pbItem)
|
||||
}
|
||||
respType := "delta"
|
||||
if listResp.CompleteListing {
|
||||
respType = "complete"
|
||||
}
|
||||
resp := &pbs.ListAuthMethodsResponse{
|
||||
Items: finalItems,
|
||||
EstItemCount: uint32(listResp.EstimatedItemCount),
|
||||
RemovedIds: listResp.DeletedIds,
|
||||
ResponseType: respType,
|
||||
SortBy: sortBy,
|
||||
SortDir: "desc",
|
||||
}
|
||||
|
||||
if listResp.ListToken != nil {
|
||||
resp.ListToken, err = handlers.MarshalListToken(ctx, listResp.ListToken, pbs.ResourceType_RESOURCE_TYPE_AUTH_METHOD)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetAuthMethod implements the interface pbs.AuthMethodServiceServer.
|
||||
@@ -499,54 +608,6 @@ func (s Service) getFromRepo(ctx context.Context, id string) (auth.AuthMethod, e
|
||||
return am, nil
|
||||
}
|
||||
|
||||
func (s Service) listFromRepo(ctx context.Context, scopeIds []string, authResults requestauth.VerifyResults) ([]auth.AuthMethod, error) {
|
||||
const op = "authmethods.(Service).listFromRepo"
|
||||
reqCtx, ok := requests.RequestContextFromCtx(ctx)
|
||||
if !ok {
|
||||
return nil, errors.New(ctx, errors.Internal, op, "no request context found")
|
||||
}
|
||||
|
||||
var outUl []auth.AuthMethod
|
||||
|
||||
oidcRepo, err := s.oidcRepoFn()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
ol, err := oidcRepo.ListAuthMethods(ctx, scopeIds, oidc.WithUnauthenticatedUser(reqCtx.UserId == globals.AnonymousUserId), oidc.WithLimit(-1))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
for _, item := range ol {
|
||||
outUl = append(outUl, item)
|
||||
}
|
||||
|
||||
repo, err := s.pwRepoFn()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
pl, err := repo.ListAuthMethods(ctx, scopeIds)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
for _, item := range pl {
|
||||
outUl = append(outUl, item)
|
||||
}
|
||||
|
||||
ldapRepo, err := s.ldapRepoFn()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
ll, err := ldapRepo.ListAuthMethods(ctx, scopeIds, ldap.WithUnauthenticatedUser(ctx, reqCtx.UserId == globals.AnonymousUserId))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(ctx, err, op)
|
||||
}
|
||||
for _, item := range ll {
|
||||
outUl = append(outUl, item)
|
||||
}
|
||||
|
||||
return outUl, nil
|
||||
}
|
||||
|
||||
func (s Service) createInRepo(ctx context.Context, scopeId string, item *pb.AuthMethod) (auth.AuthMethod, error) {
|
||||
const op = "authmethods.(Service).createInRepo"
|
||||
var out auth.AuthMethod
|
||||
@@ -1508,3 +1569,33 @@ func transformAuthenticateResponseAttributes(ctx context.Context, msg proto.Mess
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func newOutputOpts(ctx context.Context, item auth.AuthMethod, scopeInfoMap map[string]*scopes.ScopeInfo, authResults requestauth.VerifyResults) ([]handlers.Option, bool, error) {
|
||||
res := perms.Resource{
|
||||
Type: resource.AuthMethod,
|
||||
}
|
||||
res.Id = item.GetPublicId()
|
||||
res.ScopeId = item.GetScopeId()
|
||||
authorizedActions := authResults.FetchActionSetForId(ctx, item.GetPublicId(), IdActions[globals.ResourceInfoFromPrefix(item.GetPublicId()).Subtype], requestauth.WithResource(&res)).Strings()
|
||||
if len(authorizedActions) == 0 {
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
outputFields := authResults.FetchOutputFields(res, action.List).SelfOrDefaults(authResults.UserId)
|
||||
outputOpts := make([]handlers.Option, 0, 3)
|
||||
outputOpts = append(outputOpts, handlers.WithOutputFields(outputFields))
|
||||
if outputFields.Has(globals.ScopeField) {
|
||||
outputOpts = append(outputOpts, handlers.WithScope(scopeInfoMap[item.GetScopeId()]))
|
||||
}
|
||||
if outputFields.Has(globals.AuthorizedActionsField) {
|
||||
outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authorizedActions))
|
||||
}
|
||||
if outputFields.Has(globals.AuthorizedCollectionActionsField) {
|
||||
collectionActions, err := requestauth.CalculateAuthorizedCollectionActions(ctx, authResults, collectionTypeMap, authResults.Scope.Id, item.GetPublicId())
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
outputOpts = append(outputOpts, handlers.WithAuthorizedCollectionActions(collectionActions))
|
||||
}
|
||||
return outputOpts, true, nil
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
"github.com/hashicorp/boundary/internal/auth"
|
||||
"github.com/hashicorp/boundary/internal/auth/ldap"
|
||||
"github.com/hashicorp/boundary/internal/auth/oidc"
|
||||
"github.com/hashicorp/boundary/internal/auth/password"
|
||||
@@ -29,8 +30,11 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/db"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
|
||||
authpb "github.com/hashicorp/boundary/internal/gen/controller/auth"
|
||||
"github.com/hashicorp/boundary/internal/iam"
|
||||
"github.com/hashicorp/boundary/internal/kms"
|
||||
"github.com/hashicorp/boundary/internal/requests"
|
||||
"github.com/hashicorp/boundary/internal/server"
|
||||
"github.com/hashicorp/boundary/internal/types/action"
|
||||
"github.com/hashicorp/boundary/internal/types/scope"
|
||||
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/authmethods"
|
||||
@@ -112,6 +116,9 @@ func TestGet(t *testing.T) {
|
||||
atRepoFn := func() (*authtoken.Repository, error) {
|
||||
return authtoken.NewRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
authMethodRepoFn := func() (*auth.AuthMethodRepository, error) {
|
||||
return auth.NewAuthMethodRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
iamRepo := iam.TestRepo(t, conn, wrapper)
|
||||
|
||||
o, _ := iam.TestScopes(t, iamRepo)
|
||||
@@ -257,7 +264,7 @@ func TestGet(t *testing.T) {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
|
||||
s, err := authmethods.NewService(ctx, kmsCache, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn)
|
||||
s, err := authmethods.NewService(ctx, kmsCache, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn, authMethodRepoFn, 1000)
|
||||
require.NoError(err, "Couldn't create new auth_method service.")
|
||||
|
||||
got, gErr := s.GetAuthMethod(requestauth.DisabledAuthTestContext(iamRepoFn, tc.scopeId), tc.req)
|
||||
@@ -273,14 +280,14 @@ func TestGet(t *testing.T) {
|
||||
assert.Empty(cmp.Diff(
|
||||
got,
|
||||
tc.res,
|
||||
protocmp.Transform(),
|
||||
protocmp.IgnoreFields(&pb.OidcAuthMethodAttributes{}, "client_secret_hmac"),
|
||||
cmpopts.SortSlices(func(a, b string) bool {
|
||||
return a < b
|
||||
}),
|
||||
cmpopts.SortSlices(func(a, b protocmp.Message) bool {
|
||||
return a.String() < b.String()
|
||||
}),
|
||||
protocmp.Transform(),
|
||||
protocmp.IgnoreFields(&pb.OidcAuthMethodAttributes{}, "client_secret_hmac"),
|
||||
), "GetAuthMethod(%q) got response %q, wanted %q", tc.req, got, tc.res)
|
||||
})
|
||||
}
|
||||
@@ -307,6 +314,9 @@ func TestList(t *testing.T) {
|
||||
atRepoFn := func() (*authtoken.Repository, error) {
|
||||
return authtoken.NewRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
authMethodRepoFn := func() (*auth.AuthMethodRepository, error) {
|
||||
return auth.NewAuthMethodRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
iamRepo := iam.TestRepo(t, conn, wrapper)
|
||||
|
||||
oNoAuthMethods, _ := iam.TestScopes(t, iamRepo)
|
||||
@@ -435,17 +445,33 @@ func TestList(t *testing.T) {
|
||||
{
|
||||
name: "List Some Auth Methods",
|
||||
req: &pbs.ListAuthMethodsRequest{ScopeId: oWithAuthMethods.GetPublicId()},
|
||||
res: &pbs.ListAuthMethodsResponse{Items: cpSorted(wantSomeAuthMethods)},
|
||||
res: &pbs.ListAuthMethodsResponse{
|
||||
Items: cpSorted(wantSomeAuthMethods),
|
||||
EstItemCount: 5,
|
||||
ResponseType: "complete",
|
||||
SortBy: "created_time",
|
||||
SortDir: "desc",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "List Other Auth Methods",
|
||||
req: &pbs.ListAuthMethodsRequest{ScopeId: oWithOtherAuthMethods.GetPublicId()},
|
||||
res: &pbs.ListAuthMethodsResponse{Items: cpSorted(wantOtherAuthMethods)},
|
||||
res: &pbs.ListAuthMethodsResponse{
|
||||
Items: cpSorted(wantOtherAuthMethods),
|
||||
EstItemCount: 3,
|
||||
ResponseType: "complete",
|
||||
SortBy: "created_time",
|
||||
SortDir: "desc",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "List No Auth Methods",
|
||||
req: &pbs.ListAuthMethodsRequest{ScopeId: oNoAuthMethods.GetPublicId()},
|
||||
res: &pbs.ListAuthMethodsResponse{},
|
||||
res: &pbs.ListAuthMethodsResponse{
|
||||
ResponseType: "complete",
|
||||
SortBy: "created_time",
|
||||
SortDir: "desc",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Unfound Auth Method",
|
||||
@@ -459,6 +485,10 @@ func TestList(t *testing.T) {
|
||||
Items: func() []*pb.AuthMethod {
|
||||
return cpSorted(append(wantSomeAuthMethods, wantOtherAuthMethods...))
|
||||
}(),
|
||||
EstItemCount: 8,
|
||||
ResponseType: "complete",
|
||||
SortBy: "created_time",
|
||||
SortDir: "desc",
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -467,12 +497,22 @@ func TestList(t *testing.T) {
|
||||
ScopeId: "global", Recursive: true,
|
||||
Filter: fmt.Sprintf(`"/item/scope/id"==%q`, oWithAuthMethods.GetPublicId()),
|
||||
},
|
||||
res: &pbs.ListAuthMethodsResponse{Items: cpSorted(wantSomeAuthMethods)},
|
||||
res: &pbs.ListAuthMethodsResponse{
|
||||
Items: cpSorted(wantSomeAuthMethods),
|
||||
EstItemCount: 5,
|
||||
ResponseType: "complete",
|
||||
SortBy: "created_time",
|
||||
SortDir: "desc",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Filter All Auth Methods",
|
||||
req: &pbs.ListAuthMethodsRequest{ScopeId: oWithAuthMethods.GetPublicId(), Filter: `"/item/id"=="nothingmatchesthis"`},
|
||||
res: &pbs.ListAuthMethodsResponse{},
|
||||
res: &pbs.ListAuthMethodsResponse{
|
||||
ResponseType: "complete",
|
||||
SortBy: "created_time",
|
||||
SortDir: "desc",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Filter Bad Format",
|
||||
@@ -483,7 +523,7 @@ func TestList(t *testing.T) {
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
s, err := authmethods.NewService(ctx, kmsCache, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn)
|
||||
s, err := authmethods.NewService(ctx, kmsCache, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn, authMethodRepoFn, 1000)
|
||||
require.NoError(err, "Couldn't create new auth_method service.")
|
||||
|
||||
// First check with non-anonymous user
|
||||
@@ -501,18 +541,17 @@ func TestList(t *testing.T) {
|
||||
}
|
||||
|
||||
slices.SortFunc(got.Items, sorterFn)
|
||||
assert.Empty(cmp.Diff(
|
||||
got,
|
||||
tc.res,
|
||||
protocmp.Transform(),
|
||||
protocmp.IgnoreFields(&pb.OidcAuthMethodAttributes{}, "client_secret_hmac"),
|
||||
protocmp.IgnoreFields(&pb.LdapAuthMethodAttributes{}, "bind_password_hmac", "client_certificate_key_hmac"),
|
||||
assert.Empty(cmp.Diff(got, tc.res,
|
||||
cmpopts.SortSlices(func(a, b string) bool {
|
||||
return a < b
|
||||
}),
|
||||
cmpopts.SortSlices(func(a, b protocmp.Message) bool {
|
||||
return a.String() < b.String()
|
||||
}),
|
||||
protocmp.Transform(),
|
||||
protocmp.IgnoreFields(&pbs.ListAuthMethodsResponse{}, "list_token"),
|
||||
protocmp.IgnoreFields(&pb.OidcAuthMethodAttributes{}, "client_secret_hmac"),
|
||||
protocmp.IgnoreFields(&pb.LdapAuthMethodAttributes{}, "bind_password_hmac", "client_certificate_key_hmac"),
|
||||
), "ListAuthMethods() for scope %q got response %q, wanted %q", tc.req.GetScopeId(), got, tc.res)
|
||||
|
||||
// Now check with anonymous user
|
||||
@@ -550,6 +589,9 @@ func TestDelete(t *testing.T) {
|
||||
atRepoFn := func() (*authtoken.Repository, error) {
|
||||
return authtoken.NewRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
authMethodRepoFn := func() (*auth.AuthMethodRepository, error) {
|
||||
return auth.NewAuthMethodRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
iamRepo := iam.TestRepo(t, conn, wrapper)
|
||||
|
||||
o, _ := iam.TestScopes(t, iamRepo)
|
||||
@@ -563,7 +605,7 @@ func TestDelete(t *testing.T) {
|
||||
|
||||
ldapAm := ldap.TestAuthMethod(t, conn, databaseWrapper, o.GetPublicId(), []string{"ldaps://ldap1"})
|
||||
|
||||
s, err := authmethods.NewService(ctx, kmsCache, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn)
|
||||
s, err := authmethods.NewService(ctx, kmsCache, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn, authMethodRepoFn, 1000)
|
||||
require.NoError(t, err, "Error when getting new auth_method service.")
|
||||
|
||||
cases := []struct {
|
||||
@@ -643,12 +685,15 @@ func TestDelete_twice(t *testing.T) {
|
||||
atRepoFn := func() (*authtoken.Repository, error) {
|
||||
return authtoken.NewRepository(ctx, rw, rw, kms)
|
||||
}
|
||||
authMethodRepoFn := func() (*auth.AuthMethodRepository, error) {
|
||||
return auth.NewAuthMethodRepository(ctx, rw, rw, kms)
|
||||
}
|
||||
iamRepo := iam.TestRepo(t, conn, wrapper)
|
||||
|
||||
o, _ := iam.TestScopes(t, iamRepo)
|
||||
am := password.TestAuthMethods(t, conn, o.GetPublicId(), 1)[0]
|
||||
|
||||
s, err := authmethods.NewService(ctx, kms, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn)
|
||||
s, err := authmethods.NewService(ctx, kms, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn, authMethodRepoFn, 1000)
|
||||
require.NoError(err, "Error when getting new auth_method service.")
|
||||
|
||||
req := &pbs.DeleteAuthMethodRequest{
|
||||
@@ -682,6 +727,9 @@ func TestCreate(t *testing.T) {
|
||||
atRepoFn := func() (*authtoken.Repository, error) {
|
||||
return authtoken.NewRepository(ctx, rw, rw, testKms)
|
||||
}
|
||||
authMethodRepoFn := func() (*auth.AuthMethodRepository, error) {
|
||||
return auth.NewAuthMethodRepository(ctx, rw, rw, testKms)
|
||||
}
|
||||
iamRepo := iam.TestRepo(t, conn, wrapper)
|
||||
|
||||
o, _ := iam.TestScopes(t, iamRepo)
|
||||
@@ -1478,7 +1526,7 @@ func TestCreate(t *testing.T) {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
|
||||
s, err := authmethods.NewService(ctx, testKms, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn)
|
||||
s, err := authmethods.NewService(ctx, testKms, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn, authMethodRepoFn, 1000)
|
||||
require.NoError(err, "Error when getting new auth_method service.")
|
||||
|
||||
got, gErr := s.CreateAuthMethod(requestauth.DisabledAuthTestContext(iamRepoFn, tc.req.GetItem().GetScopeId()), tc.req)
|
||||
@@ -1550,3 +1598,426 @@ func TestCreate(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestListPagination(t *testing.T) {
|
||||
// Set database read timeout to avoid duplicates in response
|
||||
oldReadTimeout := globals.RefreshReadLookbackDuration
|
||||
globals.RefreshReadLookbackDuration = 0
|
||||
t.Cleanup(func() {
|
||||
globals.RefreshReadLookbackDuration = oldReadTimeout
|
||||
})
|
||||
ctx := context.Background()
|
||||
conn, _ := db.TestSetup(t, "postgres")
|
||||
rw := db.New(conn)
|
||||
sqlDB, err := conn.SqlDB(ctx)
|
||||
require.NoError(t, err)
|
||||
wrapper := db.TestWrapper(t)
|
||||
kmsCache := kms.TestKms(t, conn, wrapper)
|
||||
iamRepoFn := func() (*iam.Repository, error) {
|
||||
return iam.TestRepo(t, conn, wrapper), nil
|
||||
}
|
||||
oidcRepoFn := func() (*oidc.Repository, error) {
|
||||
return oidc.NewRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
ldapRepoFn := func() (*ldap.Repository, error) {
|
||||
return ldap.NewRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
pwRepoFn := func() (*password.Repository, error) {
|
||||
return password.NewRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
tokenRepoFn := func() (*authtoken.Repository, error) {
|
||||
return authtoken.NewRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
serversRepoFn := func() (*server.Repository, error) {
|
||||
return server.NewRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
authMethodRepoFn := func() (*auth.AuthMethodRepository, error) {
|
||||
return auth.NewAuthMethodRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
|
||||
iamRepo, err := iamRepoFn()
|
||||
require.NoError(t, err)
|
||||
tokenRepo, err := tokenRepoFn()
|
||||
require.NoError(t, err)
|
||||
ldapRepo, err := ldapRepoFn()
|
||||
require.NoError(t, err)
|
||||
oidcRepo, err := oidcRepoFn()
|
||||
require.NoError(t, err)
|
||||
|
||||
orgNoAms, _ := iam.TestScopes(t, iamRepo)
|
||||
org, proj := iam.TestScopes(t, iamRepo)
|
||||
databaseWrapper, err := kmsCache.GetWrapper(context.Background(), org.GetPublicId(), kms.KeyPurposeDatabase)
|
||||
require.NoError(t, err)
|
||||
|
||||
var allAuthMethods []*pb.AuthMethod
|
||||
|
||||
oidcam := oidc.TestAuthMethod(t, conn, databaseWrapper, org.GetPublicId(), oidc.ActivePublicState, "alice_rp", "secret",
|
||||
oidc.WithIssuer(oidc.TestConvertToUrls(t, "https://alice.com")[0]), oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://api.com")[0]), oidc.WithSigningAlgs(oidc.EdDSA),
|
||||
oidc.WithPrompts(oidc.Consent))
|
||||
iam.TestSetPrimaryAuthMethod(t, iamRepo, org, oidcam.GetPublicId())
|
||||
|
||||
allAuthMethods = append(allAuthMethods, &pb.AuthMethod{
|
||||
Id: oidcam.GetPublicId(),
|
||||
ScopeId: org.GetPublicId(),
|
||||
CreatedTime: oidcam.GetCreateTime().GetTimestamp(),
|
||||
UpdatedTime: oidcam.GetUpdateTime().GetTimestamp(),
|
||||
Scope: &scopepb.ScopeInfo{Id: org.GetPublicId(), Type: scope.Org.String(), ParentScopeId: scope.Global.String()},
|
||||
Version: 2,
|
||||
Type: oidc.Subtype.String(),
|
||||
Attrs: &pb.AuthMethod_OidcAuthMethodsAttributes{
|
||||
OidcAuthMethodsAttributes: &pb.OidcAuthMethodAttributes{
|
||||
Issuer: wrapperspb.String("https://alice.com"),
|
||||
ClientId: wrapperspb.String("alice_rp"),
|
||||
ClientSecretHmac: "<hmac>",
|
||||
State: string(oidc.ActivePublicState),
|
||||
ApiUrlPrefix: wrapperspb.String("https://api.com"),
|
||||
CallbackUrl: fmt.Sprintf(oidc.CallbackEndpoint, "https://api.com"),
|
||||
SigningAlgorithms: []string{
|
||||
string(oidc.EdDSA),
|
||||
},
|
||||
Prompts: []string{string(oidc.Consent)},
|
||||
},
|
||||
},
|
||||
IsPrimary: true,
|
||||
AuthorizedActions: oidcAuthorizedActions,
|
||||
AuthorizedCollectionActions: authorizedCollectionActions,
|
||||
})
|
||||
|
||||
ldapAm := ldap.TestAuthMethod(t, conn, databaseWrapper, org.GetPublicId(), []string{"ldaps://ldap1"},
|
||||
ldap.WithOperationalState(ctx, ldap.ActivePublicState),
|
||||
ldap.WithMaximumPageSize(ctx, 10),
|
||||
ldap.WithDerefAliases(ctx, ldap.DerefAlways),
|
||||
)
|
||||
allAuthMethods = append(allAuthMethods, &pb.AuthMethod{
|
||||
Id: ldapAm.GetPublicId(),
|
||||
ScopeId: org.GetPublicId(),
|
||||
CreatedTime: ldapAm.GetCreateTime().GetTimestamp(),
|
||||
UpdatedTime: ldapAm.GetUpdateTime().GetTimestamp(),
|
||||
Scope: &scopepb.ScopeInfo{Id: org.GetPublicId(), Type: scope.Org.String(), ParentScopeId: scope.Global.String()},
|
||||
Version: 1,
|
||||
Type: ldap.Subtype.String(),
|
||||
Attrs: &pb.AuthMethod_LdapAuthMethodsAttributes{
|
||||
LdapAuthMethodsAttributes: &pb.LdapAuthMethodAttributes{
|
||||
State: string(ldap.ActivePublicState),
|
||||
Urls: []string{"ldaps://ldap1"},
|
||||
MaximumPageSize: 10,
|
||||
DereferenceAliases: wrapperspb.String(string(ldap.DerefAlways)),
|
||||
},
|
||||
},
|
||||
AuthorizedActions: ldapAuthorizedActions,
|
||||
AuthorizedCollectionActions: authorizedCollectionActions,
|
||||
})
|
||||
|
||||
for _, am := range password.TestAuthMethods(t, conn, org.GetPublicId(), 7) {
|
||||
allAuthMethods = append(allAuthMethods, &pb.AuthMethod{
|
||||
Id: am.GetPublicId(),
|
||||
ScopeId: org.GetPublicId(),
|
||||
CreatedTime: am.GetCreateTime().GetTimestamp(),
|
||||
UpdatedTime: am.GetUpdateTime().GetTimestamp(),
|
||||
Scope: &scopepb.ScopeInfo{Id: org.GetPublicId(), Type: scope.Org.String(), ParentScopeId: scope.Global.String()},
|
||||
Version: 1,
|
||||
Type: "password",
|
||||
Attrs: &pb.AuthMethod_PasswordAuthMethodAttributes{
|
||||
PasswordAuthMethodAttributes: &pb.PasswordAuthMethodAttributes{
|
||||
MinPasswordLength: 8,
|
||||
MinLoginNameLength: 3,
|
||||
},
|
||||
},
|
||||
AuthorizedActions: pwAuthorizedActions,
|
||||
AuthorizedCollectionActions: authorizedCollectionActions,
|
||||
})
|
||||
}
|
||||
|
||||
masterAuthMethod := password.TestAuthMethods(t, conn, org.GetPublicId(), 1)[0]
|
||||
acct := password.TestAccount(t, conn, masterAuthMethod.GetPublicId(), "test_user")
|
||||
u := iam.TestUser(t, iamRepo, org.GetPublicId(), iam.WithAccountIds(acct.PublicId))
|
||||
orgRole := iam.TestRole(t, conn, org.GetPublicId())
|
||||
iam.TestRoleGrant(t, conn, orgRole.GetPublicId(), "id=*;type=*;actions=*")
|
||||
iam.TestUserRole(t, conn, orgRole.GetPublicId(), u.GetPublicId())
|
||||
projRole := iam.TestRole(t, conn, proj.GetPublicId())
|
||||
iam.TestRoleGrant(t, conn, projRole.GetPublicId(), "id=*;type=*;actions=*")
|
||||
iam.TestUserRole(t, conn, projRole.GetPublicId(), u.GetPublicId())
|
||||
at, err := tokenRepo.CreateAuthToken(ctx, u, acct.GetPublicId())
|
||||
require.NoError(t, err)
|
||||
|
||||
allAuthMethods = append(allAuthMethods, &pb.AuthMethod{
|
||||
Id: masterAuthMethod.GetPublicId(),
|
||||
ScopeId: org.GetPublicId(),
|
||||
CreatedTime: masterAuthMethod.GetCreateTime().GetTimestamp(),
|
||||
UpdatedTime: masterAuthMethod.GetUpdateTime().GetTimestamp(),
|
||||
Scope: &scopepb.ScopeInfo{Id: org.GetPublicId(), Type: scope.Org.String(), ParentScopeId: scope.Global.String()},
|
||||
Version: 1,
|
||||
Type: "password",
|
||||
Attrs: &pb.AuthMethod_PasswordAuthMethodAttributes{
|
||||
PasswordAuthMethodAttributes: &pb.PasswordAuthMethodAttributes{
|
||||
MinPasswordLength: 8,
|
||||
MinLoginNameLength: 3,
|
||||
},
|
||||
},
|
||||
AuthorizedActions: pwAuthorizedActions,
|
||||
AuthorizedCollectionActions: authorizedCollectionActions,
|
||||
})
|
||||
|
||||
// Reverse slice since we're sorting by create time descending
|
||||
slices.Reverse(allAuthMethods)
|
||||
|
||||
// Run analyze to update postgres meta tables
|
||||
_, err = sqlDB.ExecContext(ctx, "analyze")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Test without anon user
|
||||
requestInfo := authpb.RequestInfo{
|
||||
TokenFormat: uint32(requestauth.AuthTokenTypeBearer),
|
||||
PublicId: at.GetPublicId(),
|
||||
Token: at.GetToken(),
|
||||
}
|
||||
requestContext := context.WithValue(context.Background(), requests.ContextRequestInformationKey, &requests.RequestContext{})
|
||||
ctx = requestauth.NewVerifierContext(requestContext, iamRepoFn, tokenRepoFn, serversRepoFn, kmsCache, &requestInfo)
|
||||
|
||||
s, err := authmethods.NewService(ctx, kmsCache, pwRepoFn, oidcRepoFn, iamRepoFn, tokenRepoFn, ldapRepoFn, authMethodRepoFn, 1000)
|
||||
require.NoError(t, err)
|
||||
|
||||
cmpOptions := []cmp.Option{
|
||||
protocmp.Transform(),
|
||||
cmpopts.SortSlices(func(a, b string) bool {
|
||||
return a < b
|
||||
}),
|
||||
cmpopts.SortSlices(func(a, b protocmp.Message) bool {
|
||||
return a.String() < b.String()
|
||||
}),
|
||||
protocmp.IgnoreFields(&pb.OidcAuthMethodAttributes{}, "client_secret_hmac"),
|
||||
protocmp.IgnoreFields(&pb.LdapAuthMethodAttributes{}, "bind_password_hmac", "client_certificate_key_hmac"),
|
||||
protocmp.IgnoreFields(&pbs.ListAuthMethodsResponse{}, "list_token"),
|
||||
}
|
||||
|
||||
// Start paginating, recursively
|
||||
req := &pbs.ListAuthMethodsRequest{
|
||||
ScopeId: org.PublicId,
|
||||
Filter: "",
|
||||
ListToken: "",
|
||||
PageSize: 2,
|
||||
}
|
||||
got, err := s.ListAuthMethods(ctx, req)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, got.GetItems(), 2)
|
||||
assert.Empty(
|
||||
t,
|
||||
cmp.Diff(
|
||||
got,
|
||||
&pbs.ListAuthMethodsResponse{
|
||||
Items: allAuthMethods[0:2],
|
||||
ResponseType: "delta",
|
||||
ListToken: "",
|
||||
SortBy: "created_time",
|
||||
SortDir: "desc",
|
||||
RemovedIds: nil,
|
||||
EstItemCount: 10,
|
||||
},
|
||||
cmpOptions...,
|
||||
),
|
||||
)
|
||||
|
||||
// Request second page
|
||||
req.ListToken = got.ListToken
|
||||
got, err = s.ListAuthMethods(ctx, req)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, got.GetItems(), 2)
|
||||
assert.Empty(
|
||||
t,
|
||||
cmp.Diff(
|
||||
got,
|
||||
&pbs.ListAuthMethodsResponse{
|
||||
Items: allAuthMethods[2:4],
|
||||
ResponseType: "delta",
|
||||
ListToken: "",
|
||||
SortBy: "created_time",
|
||||
SortDir: "desc",
|
||||
RemovedIds: nil,
|
||||
EstItemCount: 10,
|
||||
},
|
||||
cmpOptions...,
|
||||
),
|
||||
)
|
||||
|
||||
// Request rest of results
|
||||
req.ListToken = got.ListToken
|
||||
req.PageSize = 10
|
||||
got, err = s.ListAuthMethods(ctx, req)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, got.GetItems(), 6)
|
||||
assert.Empty(
|
||||
t,
|
||||
cmp.Diff(
|
||||
got,
|
||||
&pbs.ListAuthMethodsResponse{
|
||||
Items: allAuthMethods[4:],
|
||||
ResponseType: "complete",
|
||||
ListToken: "",
|
||||
SortBy: "created_time",
|
||||
SortDir: "desc",
|
||||
RemovedIds: nil,
|
||||
EstItemCount: 10,
|
||||
},
|
||||
cmpOptions...,
|
||||
),
|
||||
)
|
||||
|
||||
// create another auth method
|
||||
am := password.TestAuthMethods(t, conn, org.GetPublicId(), 1)[0]
|
||||
ampb := &pb.AuthMethod{
|
||||
Id: am.GetPublicId(),
|
||||
ScopeId: org.GetPublicId(),
|
||||
CreatedTime: am.GetCreateTime().GetTimestamp(),
|
||||
UpdatedTime: am.GetUpdateTime().GetTimestamp(),
|
||||
Scope: &scopepb.ScopeInfo{Id: org.GetPublicId(), Type: scope.Org.String(), ParentScopeId: scope.Global.String()},
|
||||
Version: 1,
|
||||
Type: "password",
|
||||
Attrs: &pb.AuthMethod_PasswordAuthMethodAttributes{
|
||||
PasswordAuthMethodAttributes: &pb.PasswordAuthMethodAttributes{
|
||||
MinPasswordLength: 8,
|
||||
MinLoginNameLength: 3,
|
||||
},
|
||||
},
|
||||
AuthorizedActions: pwAuthorizedActions,
|
||||
AuthorizedCollectionActions: authorizedCollectionActions,
|
||||
}
|
||||
// add to front since it's most recently updated
|
||||
allAuthMethods = append([]*pb.AuthMethod{ampb}, allAuthMethods...)
|
||||
|
||||
// delete a different auth method
|
||||
_, err = oidcRepo.DeleteAuthMethod(ctx, allAuthMethods[len(allAuthMethods)-1].Id)
|
||||
require.NoError(t, err)
|
||||
deletedAM := allAuthMethods[len(allAuthMethods)-1]
|
||||
allAuthMethods = allAuthMethods[:len(allAuthMethods)-1]
|
||||
|
||||
// update a different auth method
|
||||
ldapAm.AuthMethod.Description = "new-description"
|
||||
allAuthMethods[len(allAuthMethods)-1].Description = wrapperspb.String("new-description")
|
||||
updatedAM, _, err := ldapRepo.UpdateAuthMethod(ctx, ldapAm, ldapAm.Version, []string{"description"})
|
||||
require.NoError(t, err)
|
||||
allAuthMethods[len(allAuthMethods)-1].UpdatedTime = updatedAM.UpdateTime.GetTimestamp()
|
||||
allAuthMethods[len(allAuthMethods)-1].Version = updatedAM.GetVersion()
|
||||
// add to front since it's most recently updated
|
||||
allAuthMethods = append([]*pb.AuthMethod{allAuthMethods[len(allAuthMethods)-1]}, allAuthMethods[:len(allAuthMethods)-1]...)
|
||||
|
||||
// request updated results
|
||||
req.ListToken = got.ListToken
|
||||
req.PageSize = 1
|
||||
got, err = s.ListAuthMethods(ctx, req)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, got.GetItems(), 1)
|
||||
assert.Empty(
|
||||
t,
|
||||
cmp.Diff(
|
||||
got,
|
||||
&pbs.ListAuthMethodsResponse{
|
||||
Items: []*pb.AuthMethod{allAuthMethods[0]},
|
||||
ResponseType: "delta",
|
||||
ListToken: "",
|
||||
SortBy: "updated_time",
|
||||
SortDir: "desc",
|
||||
// should be the deleted auth method
|
||||
RemovedIds: []string{deletedAM.Id},
|
||||
EstItemCount: 10,
|
||||
},
|
||||
cmpOptions...,
|
||||
),
|
||||
)
|
||||
|
||||
// get next page
|
||||
req.ListToken = got.ListToken
|
||||
got, err = s.ListAuthMethods(ctx, req)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, got.GetItems(), 1)
|
||||
assert.Empty(
|
||||
t,
|
||||
cmp.Diff(
|
||||
got,
|
||||
&pbs.ListAuthMethodsResponse{
|
||||
Items: []*pb.AuthMethod{allAuthMethods[1]},
|
||||
ResponseType: "complete",
|
||||
ListToken: "",
|
||||
SortBy: "updated_time",
|
||||
SortDir: "desc",
|
||||
RemovedIds: nil,
|
||||
EstItemCount: 10,
|
||||
},
|
||||
cmpOptions...,
|
||||
),
|
||||
)
|
||||
|
||||
// Request new page with filter requiring looping
|
||||
// to fill the page.
|
||||
req.ListToken = ""
|
||||
req.PageSize = 1
|
||||
req.Filter = fmt.Sprintf(`"/item/id"==%q or "/item/id"==%q`, allAuthMethods[len(allAuthMethods)-2].Id, allAuthMethods[len(allAuthMethods)-1].Id)
|
||||
got, err = s.ListAuthMethods(ctx, req)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, got.GetItems(), 1)
|
||||
assert.Empty(
|
||||
t,
|
||||
cmp.Diff(
|
||||
got,
|
||||
&pbs.ListAuthMethodsResponse{
|
||||
Items: []*pb.AuthMethod{allAuthMethods[len(allAuthMethods)-2]},
|
||||
ResponseType: "delta",
|
||||
ListToken: "",
|
||||
SortBy: "created_time",
|
||||
SortDir: "desc",
|
||||
// Should be empty again
|
||||
RemovedIds: nil,
|
||||
EstItemCount: 10,
|
||||
},
|
||||
cmpOptions...,
|
||||
),
|
||||
)
|
||||
req.ListToken = got.ListToken
|
||||
// Get the second page
|
||||
got, err = s.ListAuthMethods(ctx, req)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, got.GetItems(), 1)
|
||||
assert.Empty(
|
||||
t,
|
||||
cmp.Diff(
|
||||
got,
|
||||
&pbs.ListAuthMethodsResponse{
|
||||
Items: []*pb.AuthMethod{allAuthMethods[len(allAuthMethods)-1]},
|
||||
ResponseType: "complete",
|
||||
ListToken: "",
|
||||
SortBy: "created_time",
|
||||
SortDir: "desc",
|
||||
RemovedIds: nil,
|
||||
EstItemCount: 10,
|
||||
},
|
||||
cmpOptions...,
|
||||
),
|
||||
)
|
||||
req.ListToken = got.ListToken
|
||||
|
||||
// List items in the empty scope
|
||||
req = &pbs.ListAuthMethodsRequest{
|
||||
ScopeId: orgNoAms.PublicId,
|
||||
Filter: "",
|
||||
ListToken: "",
|
||||
PageSize: 2,
|
||||
}
|
||||
got, err = s.ListAuthMethods(ctx, req)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, got.GetItems(), 0)
|
||||
// Compare without comparing the list token
|
||||
assert.Empty(
|
||||
t,
|
||||
cmp.Diff(
|
||||
got,
|
||||
&pbs.ListAuthMethodsResponse{
|
||||
Items: nil,
|
||||
ResponseType: "complete",
|
||||
ListToken: "",
|
||||
SortBy: "created_time",
|
||||
SortDir: "desc",
|
||||
RemovedIds: nil,
|
||||
},
|
||||
cmpOptions...,
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
am "github.com/hashicorp/boundary/internal/auth"
|
||||
"github.com/hashicorp/boundary/internal/auth/ldap"
|
||||
"github.com/hashicorp/boundary/internal/auth/oidc"
|
||||
"github.com/hashicorp/boundary/internal/auth/password"
|
||||
@@ -67,10 +68,13 @@ func Test_UpdateLdap(t *testing.T) {
|
||||
atRepoFn := func() (*authtoken.Repository, error) {
|
||||
return authtoken.NewRepository(ctx, rw, rw, kms)
|
||||
}
|
||||
authMethodRepoFn := func() (*am.AuthMethodRepository, error) {
|
||||
return am.NewAuthMethodRepository(ctx, rw, rw, kms)
|
||||
}
|
||||
iamRepo := iam.TestRepo(t, conn, wrapper)
|
||||
|
||||
o, _ := iam.TestScopes(t, iamRepo)
|
||||
tested, err := authmethods.NewService(ctx, kms, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn)
|
||||
tested, err := authmethods.NewService(ctx, kms, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn, authMethodRepoFn, 1000)
|
||||
require.NoError(t, err, "Error when getting new auth_method service.")
|
||||
|
||||
defaultScopeInfo := &scopepb.ScopeInfo{Id: o.GetPublicId(), Type: o.GetType(), ParentScopeId: scope.Global.String()}
|
||||
@@ -915,6 +919,9 @@ func TestAuthenticate_Ldap(t *testing.T) {
|
||||
atRepoFn := func() (*authtoken.Repository, error) {
|
||||
return authtoken.NewRepository(testCtx, testRw, testRw, testKms)
|
||||
}
|
||||
authMethodRepoFn := func() (*am.AuthMethodRepository, error) {
|
||||
return am.NewAuthMethodRepository(testCtx, testRw, testRw, testKms)
|
||||
}
|
||||
|
||||
orgDbWrapper, err := testKms.GetWrapper(testCtx, o.GetPublicId(), kms.KeyPurposeDatabase)
|
||||
require.NoError(t, err)
|
||||
@@ -1094,7 +1101,7 @@ func TestAuthenticate_Ldap(t *testing.T) {
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
s, err := authmethods.NewService(testCtx, testKms, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn)
|
||||
s, err := authmethods.NewService(testCtx, testKms, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn, authMethodRepoFn, 1000)
|
||||
require.NoError(err)
|
||||
|
||||
resp, err := s.Authenticate(auth.DisabledAuthTestContext(iamRepoFn, o.GetPublicId()), tc.request)
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
authpb "github.com/hashicorp/boundary/internal/gen/controller/auth"
|
||||
|
||||
am "github.com/hashicorp/boundary/internal/auth"
|
||||
"github.com/hashicorp/boundary/internal/auth/ldap"
|
||||
"github.com/hashicorp/boundary/internal/auth/oidc"
|
||||
"github.com/hashicorp/boundary/internal/auth/password"
|
||||
@@ -63,6 +64,8 @@ type setup struct {
|
||||
ldapRepoFn common.LdapAuthRepoFactory
|
||||
pwRepoFn common.PasswordAuthRepoFactory
|
||||
atRepoFn common.AuthTokenRepoFactory
|
||||
authMethodRepoFn common.AuthMethodRepoFactory
|
||||
maxPageSize int
|
||||
org *iam.Scope
|
||||
proj *iam.Scope
|
||||
databaseWrapper wrapping.Wrapper
|
||||
@@ -104,12 +107,26 @@ func getSetup(t *testing.T) setup {
|
||||
ret.atRepoFn = func() (*authtoken.Repository, error) {
|
||||
return authtoken.NewRepository(ctx, ret.rw, ret.rw, ret.kmsCache)
|
||||
}
|
||||
ret.authMethodRepoFn = func() (*am.AuthMethodRepository, error) {
|
||||
return am.NewAuthMethodRepository(ctx, ret.rw, ret.rw, ret.kmsCache)
|
||||
}
|
||||
ret.maxPageSize = 1000
|
||||
|
||||
ret.org, ret.proj = iam.TestScopes(t, ret.iamRepo)
|
||||
ret.databaseWrapper, err = ret.kmsCache.GetWrapper(ret.ctx, ret.org.PublicId, kms.KeyPurposeDatabase)
|
||||
require.NoError(err)
|
||||
|
||||
ret.authMethodService, err = authmethods.NewService(ret.ctx, ret.kmsCache, ret.pwRepoFn, ret.oidcRepoFn, ret.iamRepoFn, ret.atRepoFn, ret.ldapRepoFn)
|
||||
ret.authMethodService, err = authmethods.NewService(
|
||||
ret.ctx,
|
||||
ret.kmsCache,
|
||||
ret.pwRepoFn,
|
||||
ret.oidcRepoFn,
|
||||
ret.iamRepoFn,
|
||||
ret.atRepoFn,
|
||||
ret.ldapRepoFn,
|
||||
ret.authMethodRepoFn,
|
||||
uint(ret.maxPageSize),
|
||||
)
|
||||
require.NoError(err)
|
||||
|
||||
ret.testProvider = capoidc.StartTestProvider(t)
|
||||
@@ -168,6 +185,9 @@ func TestList_FilterNonPublic(t *testing.T) {
|
||||
serversRepoFn := func() (*server.Repository, error) {
|
||||
return server.NewRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
authMethodRepoFn := func() (*am.AuthMethodRepository, error) {
|
||||
return am.NewAuthMethodRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
|
||||
iamRepo := iam.TestRepo(t, conn, wrapper)
|
||||
|
||||
@@ -195,7 +215,7 @@ func TestList_FilterNonPublic(t *testing.T) {
|
||||
oidc.WithIssuer(oidc.TestConvertToUrls(t, fmt.Sprintf("https://alice%d.com", i))[0]), oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://api.com")[0]))
|
||||
}
|
||||
|
||||
s, err := authmethods.NewService(ctx, kmsCache, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn)
|
||||
s, err := authmethods.NewService(ctx, kmsCache, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn, authMethodRepoFn, 1000)
|
||||
require.NoError(t, err, "Couldn't create new auth_method service.")
|
||||
|
||||
req := &pbs.ListAuthMethodsRequest{
|
||||
@@ -270,10 +290,13 @@ func TestUpdate_OIDC(t *testing.T) {
|
||||
atRepoFn := func() (*authtoken.Repository, error) {
|
||||
return authtoken.NewRepository(ctx, rw, rw, kms)
|
||||
}
|
||||
authMethodRepoFn := func() (*am.AuthMethodRepository, error) {
|
||||
return am.NewAuthMethodRepository(ctx, rw, rw, kms)
|
||||
}
|
||||
iamRepo := iam.TestRepo(t, conn, wrapper)
|
||||
|
||||
o, _ := iam.TestScopes(t, iamRepo)
|
||||
tested, err := authmethods.NewService(ctx, kms, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn)
|
||||
tested, err := authmethods.NewService(ctx, kms, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn, authMethodRepoFn, 1000)
|
||||
require.NoError(t, err, "Error when getting new auth_method service.")
|
||||
|
||||
defaultScopeInfo := &scopepb.ScopeInfo{Id: o.GetPublicId(), Type: o.GetType(), ParentScopeId: scope.Global.String()}
|
||||
@@ -1139,6 +1162,9 @@ func TestUpdate_OIDCDryRun(t *testing.T) {
|
||||
atRepoFn := func() (*authtoken.Repository, error) {
|
||||
return authtoken.NewRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
authMethodRepoFn := func() (*am.AuthMethodRepository, error) {
|
||||
return am.NewAuthMethodRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
iamRepo := iam.TestRepo(t, conn, wrapper)
|
||||
|
||||
o, _ := iam.TestScopes(t, iamRepo)
|
||||
@@ -1192,7 +1218,7 @@ func TestUpdate_OIDCDryRun(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
tested, err := authmethods.NewService(ctx, kmsCache, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn)
|
||||
tested, err := authmethods.NewService(ctx, kmsCache, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn, authMethodRepoFn, 1000)
|
||||
require.NoError(t, err, "Error when getting new auth_method service.")
|
||||
cases := []struct {
|
||||
name string
|
||||
@@ -1339,6 +1365,9 @@ func TestChangeState_OIDC(t *testing.T) {
|
||||
atRepoFn := func() (*authtoken.Repository, error) {
|
||||
return authtoken.NewRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
authMethodRepoFn := func() (*am.AuthMethodRepository, error) {
|
||||
return am.NewAuthMethodRepository(ctx, rw, rw, kmsCache)
|
||||
}
|
||||
iamRepo := iam.TestRepo(t, conn, wrapper)
|
||||
|
||||
o, _ := iam.TestScopes(t, iamRepo)
|
||||
@@ -1362,7 +1391,7 @@ func TestChangeState_OIDC(t *testing.T) {
|
||||
mismatchedAM := oidc.TestAuthMethod(t, conn, databaseWrapper, o.PublicId, "inactive", "different_client_id", oidc.ClientSecret(tpClientSecret),
|
||||
oidc.WithIssuer(oidc.TestConvertToUrls(t, tp.Addr())[0]), oidc.WithSigningAlgs(oidc.EdDSA), oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://example.callback:58")[0]), oidc.WithCertificates(tpCert...))
|
||||
|
||||
s, err := authmethods.NewService(ctx, kmsCache, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn)
|
||||
s, err := authmethods.NewService(ctx, kmsCache, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn, authMethodRepoFn, 1000)
|
||||
require.NoError(t, err, "Error when getting new auth_method service.")
|
||||
|
||||
wantTemplate := &pb.AuthMethod{
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/hashicorp/boundary/globals"
|
||||
am "github.com/hashicorp/boundary/internal/auth"
|
||||
"github.com/hashicorp/boundary/internal/auth/ldap"
|
||||
"github.com/hashicorp/boundary/internal/auth/oidc"
|
||||
"github.com/hashicorp/boundary/internal/auth/password"
|
||||
@@ -62,10 +63,13 @@ func TestUpdate_Password(t *testing.T) {
|
||||
atRepoFn := func() (*authtoken.Repository, error) {
|
||||
return authtoken.NewRepository(ctx, rw, rw, kms)
|
||||
}
|
||||
authMethodRepoFn := func() (*am.AuthMethodRepository, error) {
|
||||
return am.NewAuthMethodRepository(ctx, rw, rw, kms)
|
||||
}
|
||||
iamRepo := iam.TestRepo(t, conn, wrapper)
|
||||
|
||||
o, _ := iam.TestScopes(t, iamRepo)
|
||||
tested, err := authmethods.NewService(ctx, kms, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn)
|
||||
tested, err := authmethods.NewService(ctx, kms, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn, authMethodRepoFn, 1000)
|
||||
require.NoError(t, err, "Error when getting new auth_method service.")
|
||||
|
||||
defaultScopeInfo := &scopepb.ScopeInfo{Id: o.GetPublicId(), Type: o.GetType(), ParentScopeId: scope.Global.String()}
|
||||
@@ -510,6 +514,9 @@ func TestAuthenticate_Password(t *testing.T) {
|
||||
atRepoFn := func() (*authtoken.Repository, error) {
|
||||
return authtoken.NewRepository(ctx, rw, rw, kms)
|
||||
}
|
||||
authMethodRepoFn := func() (*am.AuthMethodRepository, error) {
|
||||
return am.NewAuthMethodRepository(ctx, rw, rw, kms)
|
||||
}
|
||||
am := password.TestAuthMethods(t, conn, o.GetPublicId(), 1)[0]
|
||||
|
||||
iam.TestSetPrimaryAuthMethod(t, iam.TestRepo(t, conn, wrapper), o, am.PublicId)
|
||||
@@ -652,7 +659,7 @@ func TestAuthenticate_Password(t *testing.T) {
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
assert, require := assert.New(t), require.New(t)
|
||||
s, err := authmethods.NewService(ctx, kms, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn)
|
||||
s, err := authmethods.NewService(ctx, kms, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn, authMethodRepoFn, 1000)
|
||||
require.NoError(err)
|
||||
|
||||
resp, err := s.Authenticate(auth.DisabledAuthTestContext(iamRepoFn, o.GetPublicId()), tc.request)
|
||||
@@ -718,6 +725,9 @@ func TestAuthenticate_AuthAccountConnectedToIamUser_Password(t *testing.T) {
|
||||
atRepoFn := func() (*authtoken.Repository, error) {
|
||||
return authtoken.NewRepository(ctx, rw, rw, kms)
|
||||
}
|
||||
authMethodRepoFn := func() (*am.AuthMethodRepository, error) {
|
||||
return am.NewAuthMethodRepository(ctx, rw, rw, kms)
|
||||
}
|
||||
|
||||
am := password.TestAuthMethods(t, conn, o.GetPublicId(), 1)[0]
|
||||
acct, err := password.NewAccount(ctx, am.GetPublicId(), password.WithLoginName(testLoginName))
|
||||
@@ -735,7 +745,7 @@ func TestAuthenticate_AuthAccountConnectedToIamUser_Password(t *testing.T) {
|
||||
iamUser, err := iamRepo.LookupUserWithLogin(context.Background(), acct.GetPublicId())
|
||||
require.NoError(err)
|
||||
|
||||
s, err := authmethods.NewService(ctx, kms, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn)
|
||||
s, err := authmethods.NewService(ctx, kms, pwRepoFn, oidcRepoFn, iamRepoFn, atRepoFn, ldapRepoFn, authMethodRepoFn, 1000)
|
||||
require.NoError(err)
|
||||
resp, err := s.Authenticate(auth.DisabledAuthTestContext(iamRepoFn, o.GetPublicId()), &pbs.AuthenticateRequest{
|
||||
AuthMethodId: am.GetPublicId(),
|
||||
|
||||
@@ -27,6 +27,7 @@ where
|
||||
-- migration 07_auth.up.sql This new definition also inserts the sub type's name
|
||||
-- into the base type. The name column must be on the base type, so the database
|
||||
-- can ensure that auth method names are unique across all sub types.
|
||||
-- Replaced in 80/09_auth_method_base_table_updates.up.sql
|
||||
create or replace function insert_auth_method_subtype() returns trigger
|
||||
as $$
|
||||
begin
|
||||
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
-- Copyright (c) HashiCorp, Inc.
|
||||
-- SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
begin;
|
||||
|
||||
-- Add create_time, update_time and is_active_public_state to auth_method table.
|
||||
alter table auth_method
|
||||
add column create_time wt_timestamp,
|
||||
add column update_time wt_timestamp,
|
||||
add column is_active_public_state boolean not null default false
|
||||
;
|
||||
|
||||
-- Update rows with current values from LDAP auth method
|
||||
with
|
||||
sub_auth_method (public_id, create_time, update_time, is_active_public_state) as (
|
||||
select public_id,
|
||||
create_time,
|
||||
update_time,
|
||||
state = 'active-public'
|
||||
from auth_ldap_method
|
||||
)
|
||||
update auth_method
|
||||
set create_time = sub_auth_method.create_time,
|
||||
update_time = sub_auth_method.update_time,
|
||||
is_active_public_state = sub_auth_method.is_active_public_state
|
||||
from sub_auth_method
|
||||
where auth_method.public_id = sub_auth_method.public_id;
|
||||
|
||||
-- Update rows with current values from OIDC auth method
|
||||
with
|
||||
sub_auth_method (public_id, create_time, update_time, is_active_public_state) as (
|
||||
select public_id,
|
||||
create_time,
|
||||
update_time,
|
||||
state = 'active-public'
|
||||
from auth_oidc_method
|
||||
)
|
||||
update auth_method
|
||||
set create_time = sub_auth_method.create_time,
|
||||
update_time = sub_auth_method.update_time,
|
||||
is_active_public_state = sub_auth_method.is_active_public_state
|
||||
from sub_auth_method
|
||||
where auth_method.public_id = sub_auth_method.public_id;
|
||||
|
||||
-- Update rows with current values from password auth method
|
||||
with
|
||||
sub_auth_method (public_id, create_time, update_time, is_active_public_state) as (
|
||||
select public_id,
|
||||
create_time,
|
||||
update_time,
|
||||
true
|
||||
from auth_password_method
|
||||
)
|
||||
update auth_method
|
||||
set create_time = sub_auth_method.create_time,
|
||||
update_time = sub_auth_method.update_time,
|
||||
is_active_public_state = sub_auth_method.is_active_public_state
|
||||
from sub_auth_method
|
||||
where auth_method.public_id = sub_auth_method.public_id;
|
||||
|
||||
-- Replace the insert trigger to also set the create_time
|
||||
-- Partially replaces the insert_auth_method_subtype function defined in 2/10_auth.up.sql
|
||||
-- This is because ldap and oidc subtypes have a state column, but password does not.
|
||||
create or replace function insert_auth_method_subtype() returns trigger
|
||||
as $$
|
||||
begin
|
||||
insert into auth_method
|
||||
(public_id, scope_id, name, create_time, is_active_public_state)
|
||||
values
|
||||
(new.public_id, new.scope_id, new.name, new.create_time, new.state = 'active-public');
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
comment on function insert_auth_method_subtype() is
|
||||
'insert_auth_method_subtype() inserts sub type name, create time, update time, '
|
||||
'and whether it is an active public state into the base type auth method table, '
|
||||
'specifically for ldap or oidc subtypes.';
|
||||
|
||||
-- Replace the insert trigger to also set the create_time
|
||||
-- Partially replaces the insert_auth_method_subtype function defined in 2/10_auth.up.sql
|
||||
-- This is because ldap and oidc subtypes have a state column, but password does not.
|
||||
create function insert_auth_method_password_subtype() returns trigger
|
||||
as $$
|
||||
begin
|
||||
insert into auth_method
|
||||
(public_id, scope_id, name, create_time, is_active_public_state)
|
||||
values
|
||||
(new.public_id, new.scope_id, new.name, new.create_time, true);
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
comment on function insert_auth_method_password_subtype() is
|
||||
'insert_auth_method_password_subtype() inserts sub type name, create time, update time, '
|
||||
'and that it is an active public state into the base type auth method table, '
|
||||
'specifically for the password subtype.';
|
||||
|
||||
-- Add trigger to update the new update_time column on every subtype update.
|
||||
create function update_auth_method_table_update_time() returns trigger
|
||||
as $$
|
||||
begin
|
||||
update auth_method set update_time = now() where public_id = new.public_id;
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
comment on function update_auth_method_table_update_time() is
|
||||
'update_auth_method_table_update_time is used to automatically update the update_time '
|
||||
'of the base table whenever one of the subtype tables are updated';
|
||||
|
||||
-- Add trigger to update the new is_active_public_state column on ldap and oidc subtype update.
|
||||
-- Password subtype has no state and will always be considered active public.
|
||||
create function update_auth_method_table_is_active_public_state() returns trigger
|
||||
as $$
|
||||
begin
|
||||
if new.state = 'active-public' then
|
||||
update auth_method set is_active_public_state = true where public_id = new.public_id;
|
||||
return new;
|
||||
else
|
||||
update auth_method set is_active_public_state = false where public_id = new.public_id;
|
||||
return new;
|
||||
end if;
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
comment on function update_auth_method_table_is_active_public_state() is
|
||||
'update_auth_method_table_is_active_public_state is used to automatically update the '
|
||||
'is_active_public_state column of the base table whenever one of the subtype tables are updated';
|
||||
|
||||
-- Add triggers to subtype tables
|
||||
create trigger update_auth_method_table_update_time before update on auth_ldap_method
|
||||
for each row execute procedure update_auth_method_table_update_time();
|
||||
create trigger update_auth_method_table_update_time before update on auth_oidc_method
|
||||
for each row execute procedure update_auth_method_table_update_time();
|
||||
create trigger update_auth_method_table_update_time before update on auth_password_method
|
||||
for each row execute procedure update_auth_method_table_update_time();
|
||||
|
||||
-- Replace trigger on password subtype table
|
||||
drop trigger insert_auth_method_subtype on auth_password_method;
|
||||
create trigger insert_auth_method_password_subtype before insert on auth_password_method
|
||||
for each row execute procedure insert_auth_method_password_subtype();
|
||||
|
||||
-- Add is_active_public_state triggers to ldap and oidc tables, as password has no state column.
|
||||
create trigger update_auth_method_table_is_active_public_state before update on auth_ldap_method
|
||||
for each row execute procedure update_auth_method_table_is_active_public_state();
|
||||
create trigger update_auth_method_table_is_active_public_state before update on auth_oidc_method
|
||||
for each row execute procedure update_auth_method_table_is_active_public_state();
|
||||
|
||||
-- Add new indexes for the create and update time queries.
|
||||
create index auth_method_create_time_public_id_idx
|
||||
on auth_method (create_time desc, public_id desc);
|
||||
create index auth_method_update_time_public_id_idx
|
||||
on auth_method (update_time desc, public_id desc);
|
||||
|
||||
analyze auth_method;
|
||||
|
||||
commit;
|
||||
@@ -0,0 +1,59 @@
|
||||
-- Copyright (c) HashiCorp, Inc.
|
||||
-- SPDX-License-Identifier: BUSL-1.1
|
||||
|
||||
begin;
|
||||
select plan(17);
|
||||
-- load to test with ldap auth method
|
||||
select wtt_load('widgets', 'iam', 'kms', 'auth');
|
||||
|
||||
-- validate the setup data
|
||||
select is(count(*), 1::bigint) from auth_ldap_account where public_id = 'ala___walter';
|
||||
select is(count(*), 1::bigint) from auth_account where public_id = 'ala___walter';
|
||||
|
||||
-- validate the insert triggers
|
||||
prepare insert_ldap_account as
|
||||
insert into auth_ldap_account
|
||||
(auth_method_id, public_id, login_name)
|
||||
values
|
||||
('alm___widget', 'ala___tania', 'tania');
|
||||
select lives_ok('insert_ldap_account');
|
||||
|
||||
-- Verify the trigger functions exist and are declared properly
|
||||
select has_function('update_auth_method_table_update_time');
|
||||
select volatility_is('update_auth_method_table_update_time', 'volatile');
|
||||
select isnt_strict('update_auth_method_table_update_time');
|
||||
select has_trigger('auth_ldap_method', 'update_auth_method_table_update_time');
|
||||
select has_trigger('auth_oidc_method', 'update_auth_method_table_update_time');
|
||||
select has_trigger('auth_password_method', 'update_auth_method_table_update_time');
|
||||
select has_trigger('auth_password_method', 'insert_auth_method_password_subtype');
|
||||
select has_trigger('auth_ldap_method', 'update_auth_method_table_is_active_public_state');
|
||||
select has_trigger('auth_oidc_method', 'update_auth_method_table_is_active_public_state');
|
||||
select has_index('auth_method', 'auth_method_create_time_public_id_idx', array['create_time', 'public_id']);
|
||||
select has_index('auth_method', 'auth_method_update_time_public_id_idx', array['update_time', 'public_id']);
|
||||
|
||||
-- To test that the trigger that sets the create_time of the base table
|
||||
-- when an insert into a subtype table happens works, we check that the
|
||||
-- create time of the entries in both tables match
|
||||
prepare auth_method_create_time as select create_time from auth_method where public_id='apm___colors';
|
||||
prepare auth_password_method_create_time as select create_time from auth_password_method where public_id='apm___colors';
|
||||
select results_eq('auth_method_create_time','auth_password_method_create_time');
|
||||
|
||||
-- To test the trigger that updates the update_time of the base table,
|
||||
-- we update one of the existing subtypes and check that the base table
|
||||
-- entry has the same update_time as the subtype one.
|
||||
update auth_password_method set name='blue black am' where public_id='apm___colors';
|
||||
prepare auth_method_update_time as select update_time from auth_method where public_id='apm___colors';
|
||||
prepare auth_password_method_update_time as select update_time from auth_password_method where public_id='apm___colors';
|
||||
select results_eq('auth_method_update_time','auth_password_method_update_time');
|
||||
|
||||
-- To test the trigger that updates the is_active_public_state of the base table,
|
||||
-- we set one of the existing subtypes states to 'active-public' and check that the base table
|
||||
-- entry has updated its column to true.
|
||||
update auth_ldap_method set state='active-public' where public_id='ala___tania';
|
||||
prepare auth_method_is_active_public_state as select is_active_public_state from auth_method where public_id='ala___tania';
|
||||
prepare auth_ldap_method_state_is_active_public_state as select state = 'active-public' from auth_ldap_method where public_id='ala___tania';
|
||||
select results_eq('auth_method_is_active_public_state','auth_ldap_method_state_is_active_public_state');
|
||||
|
||||
select * from finish();
|
||||
|
||||
rollback;
|
||||
@@ -341,6 +341,21 @@
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "list_token",
|
||||
"description": "An opaque token used to continue an existing iteration or\nrequest updated items. If not specified, pagination\nwill start from the beginning.",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "page_size",
|
||||
"description": "The maximum size of a page in this iteration.\nIf unset, the default page size configured will be used.\nIf the page_size is greater than the max page size configured,\nthe page size will be truncated to this number.",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
@@ -7658,7 +7673,36 @@
|
||||
"items": {
|
||||
"type": "object",
|
||||
"$ref": "#/definitions/controller.api.resources.authmethods.v1.AuthMethod"
|
||||
}
|
||||
},
|
||||
"description": "The items returned in this page."
|
||||
},
|
||||
"response_type": {
|
||||
"type": "string",
|
||||
"description": "The type of response, either \"delta\" or \"complete\".\nDelta signifies that this is part of a paginated result\nor an update to a previously completed pagination.\nComplete signifies that it is the last page."
|
||||
},
|
||||
"list_token": {
|
||||
"type": "string",
|
||||
"description": "An opaque token used to continue an existing pagination or\nrequest updated items. Use this token in the next list request\nto request the next page."
|
||||
},
|
||||
"sort_by": {
|
||||
"type": "string",
|
||||
"description": "The name of the field which the items are sorted by."
|
||||
},
|
||||
"sort_dir": {
|
||||
"type": "string",
|
||||
"description": "The direction of the sort, either \"asc\" or \"desc\"."
|
||||
},
|
||||
"removed_ids": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "A list of item IDs that have been removed since they were returned\nas part of a pagination. They should be dropped from any client cache.\nThis may contain items that are not known to the cache, if they were\ncreated and deleted between listings."
|
||||
},
|
||||
"est_item_count": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"description": "An estimate at the total items available. This may change during pagination."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -133,6 +133,15 @@ type ListAuthMethodsRequest struct {
|
||||
ScopeId string `protobuf:"bytes,1,opt,name=scope_id,proto3" json:"scope_id,omitempty" class:"public" eventstream:"observation"` // @gotags: `class:"public" eventstream:"observation"`
|
||||
Recursive bool `protobuf:"varint,20,opt,name=recursive,proto3" json:"recursive,omitempty" class:"public" eventstream:"observation"` // @gotags: `class:"public" eventstream:"observation"`
|
||||
Filter string `protobuf:"bytes,30,opt,name=filter,proto3" json:"filter,omitempty" class:"public"` // @gotags: `class:"public"`
|
||||
// An opaque token used to continue an existing iteration or
|
||||
// request updated items. If not specified, pagination
|
||||
// will start from the beginning.
|
||||
ListToken string `protobuf:"bytes,40,opt,name=list_token,proto3" json:"list_token,omitempty" class:"public"` // @gotags: `class:"public"`
|
||||
// The maximum size of a page in this iteration.
|
||||
// If unset, the default page size configured will be used.
|
||||
// If the page_size is greater than the max page size configured,
|
||||
// the page size will be truncated to this number.
|
||||
PageSize uint32 `protobuf:"varint,50,opt,name=page_size,proto3" json:"page_size,omitempty" class:"public"` // @gotags: `class:"public"`
|
||||
}
|
||||
|
||||
func (x *ListAuthMethodsRequest) Reset() {
|
||||
@@ -188,12 +197,47 @@ func (x *ListAuthMethodsRequest) GetFilter() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ListAuthMethodsRequest) GetListToken() string {
|
||||
if x != nil {
|
||||
return x.ListToken
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ListAuthMethodsRequest) GetPageSize() uint32 {
|
||||
if x != nil {
|
||||
return x.PageSize
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type ListAuthMethodsResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// The items returned in this page.
|
||||
Items []*authmethods.AuthMethod `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"`
|
||||
// The type of response, either "delta" or "complete".
|
||||
// Delta signifies that this is part of a paginated result
|
||||
// or an update to a previously completed pagination.
|
||||
// Complete signifies that it is the last page.
|
||||
ResponseType string `protobuf:"bytes,2,opt,name=response_type,proto3" json:"response_type,omitempty" class:"public"` // @gotags: `class:"public"`
|
||||
// An opaque token used to continue an existing pagination or
|
||||
// request updated items. Use this token in the next list request
|
||||
// to request the next page.
|
||||
ListToken string `protobuf:"bytes,3,opt,name=list_token,proto3" json:"list_token,omitempty" class:"public"` // @gotags: `class:"public"`
|
||||
// The name of the field which the items are sorted by.
|
||||
SortBy string `protobuf:"bytes,4,opt,name=sort_by,proto3" json:"sort_by,omitempty" class:"public"` // @gotags: `class:"public"`
|
||||
// The direction of the sort, either "asc" or "desc".
|
||||
SortDir string `protobuf:"bytes,5,opt,name=sort_dir,proto3" json:"sort_dir,omitempty" class:"public"` // @gotags: `class:"public"`
|
||||
// A list of item IDs that have been removed since they were returned
|
||||
// as part of a pagination. They should be dropped from any client cache.
|
||||
// This may contain items that are not known to the cache, if they were
|
||||
// created and deleted between listings.
|
||||
RemovedIds []string `protobuf:"bytes,6,rep,name=removed_ids,proto3" json:"removed_ids,omitempty" class:"public"` // @gotags: `class:"public"`
|
||||
// An estimate at the total items available. This may change during pagination.
|
||||
EstItemCount uint32 `protobuf:"varint,7,opt,name=est_item_count,proto3" json:"est_item_count,omitempty" class:"public"` // @gotags: `class:"public"`
|
||||
}
|
||||
|
||||
func (x *ListAuthMethodsResponse) Reset() {
|
||||
@@ -235,6 +279,48 @@ func (x *ListAuthMethodsResponse) GetItems() []*authmethods.AuthMethod {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ListAuthMethodsResponse) GetResponseType() string {
|
||||
if x != nil {
|
||||
return x.ResponseType
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ListAuthMethodsResponse) GetListToken() string {
|
||||
if x != nil {
|
||||
return x.ListToken
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ListAuthMethodsResponse) GetSortBy() string {
|
||||
if x != nil {
|
||||
return x.SortBy
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ListAuthMethodsResponse) GetSortDir() string {
|
||||
if x != nil {
|
||||
return x.SortDir
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ListAuthMethodsResponse) GetRemovedIds() []string {
|
||||
if x != nil {
|
||||
return x.RemovedIds
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ListAuthMethodsResponse) GetEstItemCount() uint32 {
|
||||
if x != nil {
|
||||
return x.EstItemCount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type CreateAuthMethodRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -1276,323 +1362,339 @@ var file_controller_api_services_v1_auth_method_service_proto_rawDesc = []byte{
|
||||
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73,
|
||||
0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6d, 0x65, 0x74, 0x68, 0x6f,
|
||||
0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64,
|
||||
0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x6a, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75,
|
||||
0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x12, 0x1a, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09,
|
||||
0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||
0x09, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69,
|
||||
0x6c, 0x74, 0x65, 0x72, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74,
|
||||
0x65, 0x72, 0x22, 0x64, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65,
|
||||
0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0xa8, 0x01, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x41,
|
||||
0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, 0x12, 0x1c, 0x0a,
|
||||
0x09, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08,
|
||||
0x52, 0x09, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66,
|
||||
0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x69, 0x6c,
|
||||
0x74, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65,
|
||||
0x6e, 0x18, 0x28, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x74, 0x6f,
|
||||
0x6b, 0x65, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65,
|
||||
0x18, 0x32, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a,
|
||||
0x65, 0x22, 0xaa, 0x02, 0x0a, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65,
|
||||
0x74, 0x68, 0x6f, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a,
|
||||
0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x63,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65,
|
||||
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6d, 0x65, 0x74, 0x68,
|
||||
0x6f, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f,
|
||||
0x64, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x62, 0x0a, 0x17, 0x43, 0x72, 0x65, 0x61,
|
||||
0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x12, 0x47, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61,
|
||||
0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x75, 0x74,
|
||||
0x68, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68,
|
||||
0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x75, 0x0a, 0x18,
|
||||
0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x69, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x12, 0x47, 0x0a, 0x04, 0x69, 0x74,
|
||||
0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
||||
0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72,
|
||||
0x63, 0x65, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x04, 0x69,
|
||||
0x74, 0x65, 0x6d, 0x22, 0xb0, 0x01, 0x0a, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x75,
|
||||
0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
|
||||
0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12,
|
||||
0x47, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72,
|
||||
0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6d, 0x65, 0x74,
|
||||
0x68, 0x6f, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68,
|
||||
0x6f, 0x64, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x3c, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61,
|
||||
0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
|
||||
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
|
||||
0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74,
|
||||
0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x22, 0x63, 0x0a, 0x18, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65,
|
||||
0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x12, 0x47, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70,
|
||||
0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68,
|
||||
0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x4d,
|
||||
0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x29, 0x0a, 0x17, 0x44,
|
||||
0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x1a, 0x0a, 0x18, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
|
||||
0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x22, 0x85, 0x01, 0x0a, 0x19, 0x4f, 0x69, 0x64, 0x63, 0x43, 0x68, 0x61, 0x6e, 0x67,
|
||||
0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73,
|
||||
0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x52, 0x0a, 0x24, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c,
|
||||
0x65, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6e,
|
||||
0x66, 0x69, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x24, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x64, 0x69,
|
||||
0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f,
|
||||
0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xa4, 0x02, 0x0a, 0x12, 0x43,
|
||||
0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69,
|
||||
0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x46, 0x0a, 0x0a, 0x61,
|
||||
0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
|
||||
0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x42, 0x0b, 0x9a, 0xe3, 0x29, 0x07, 0x64, 0x65,
|
||||
0x66, 0x61, 0x75, 0x6c, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75,
|
||||
0x74, 0x65, 0x73, 0x12, 0x92, 0x01, 0x0a, 0x1c, 0x6f, 0x69, 0x64, 0x63, 0x5f, 0x63, 0x68, 0x61,
|
||||
0x6e, 0x67, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62,
|
||||
0x75, 0x74, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x63, 0x6f, 0x6e,
|
||||
0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76,
|
||||
0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x69, 0x64, 0x63, 0x43, 0x68, 0x61, 0x6e,
|
||||
0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65,
|
||||
0x73, 0x42, 0x18, 0x9a, 0xe3, 0x29, 0x04, 0x6f, 0x69, 0x64, 0x63, 0xfa, 0xd2, 0xe4, 0x93, 0x02,
|
||||
0x0a, 0x12, 0x08, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x48, 0x00, 0x52, 0x19, 0x6f,
|
||||
0x69, 0x64, 0x63, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x41, 0x74,
|
||||
0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x42, 0x07, 0x0a, 0x05, 0x61, 0x74, 0x74, 0x72,
|
||||
0x73, 0x22, 0x5e, 0x0a, 0x13, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65,
|
||||
0x64, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x0d, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1e,
|
||||
0x0a, 0x0a, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x0a, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x18,
|
||||
0x0a, 0x07, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x62, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x07, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x62, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x6f, 0x72, 0x74,
|
||||
0x5f, 0x64, 0x69, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x6f, 0x72, 0x74,
|
||||
0x5f, 0x64, 0x69, 0x72, 0x12, 0x20, 0x0a, 0x0b, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x5f,
|
||||
0x69, 0x64, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x65, 0x6d, 0x6f, 0x76,
|
||||
0x65, 0x64, 0x5f, 0x69, 0x64, 0x73, 0x12, 0x26, 0x0a, 0x0e, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x74,
|
||||
0x65, 0x6d, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e,
|
||||
0x65, 0x73, 0x74, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x62,
|
||||
0x0a, 0x17, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68,
|
||||
0x6f, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x47, 0x0a, 0x04, 0x69, 0x74, 0x65,
|
||||
0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
|
||||
0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
|
||||
0x65, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x04, 0x69, 0x74,
|
||||
0x65, 0x6d, 0x22, 0x75, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68,
|
||||
0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10,
|
||||
0x0a, 0x03, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x69,
|
||||
0x12, 0x47, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33,
|
||||
0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e,
|
||||
0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6d, 0x65,
|
||||
0x74, 0x68, 0x6f, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74,
|
||||
0x68, 0x6f, 0x64, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0xb0, 0x01, 0x0a, 0x17, 0x55, 0x70,
|
||||
0x64, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x47, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
|
||||
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x61,
|
||||
0x75, 0x74, 0x68, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75,
|
||||
0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x3c,
|
||||
0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52,
|
||||
0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x22, 0x63, 0x0a, 0x18,
|
||||
0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
||||
0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
|
||||
0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x04, 0x69, 0x74, 0x65,
|
||||
0x6d, 0x22, 0x55, 0x0a, 0x17, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67,
|
||||
0x69, 0x6e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x0a,
|
||||
0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x0a, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08,
|
||||
0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08,
|
||||
0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x96, 0x01, 0x0a, 0x13, 0x4f, 0x69, 0x64,
|
||||
0x63, 0x53, 0x74, 0x61, 0x72, 0x74, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73,
|
||||
0x12, 0x45, 0x0a, 0x11, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69, 0x70, 0x5f, 0x70, 0x61,
|
||||
0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f,
|
||||
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74,
|
||||
0x72, 0x75, 0x63, 0x74, 0x52, 0x11, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69, 0x70, 0x5f,
|
||||
0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x38, 0x0a, 0x18, 0x63, 0x61, 0x63, 0x68, 0x65,
|
||||
0x64, 0x5f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69, 0x70, 0x5f, 0x70, 0x61, 0x79, 0x6c,
|
||||
0x6f, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x63, 0x61, 0x63, 0x68, 0x65,
|
||||
0x64, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69, 0x70, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61,
|
||||
0x64, 0x22, 0x51, 0x0a, 0x13, 0x4c, 0x64, 0x61, 0x70, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x41, 0x74,
|
||||
0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x6c, 0x6f, 0x67, 0x69,
|
||||
0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6c, 0x6f,
|
||||
0x67, 0x69, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73,
|
||||
0x77, 0x6f, 0x72, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73,
|
||||
0x77, 0x6f, 0x72, 0x64, 0x22, 0xed, 0x07, 0x0a, 0x13, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74,
|
||||
0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0e,
|
||||
0x61, 0x75, 0x74, 0x68, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f,
|
||||
0x64, 0x5f, 0x69, 0x64, 0x12, 0x22, 0x0a, 0x0a, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x74, 0x79,
|
||||
0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02, 0x18, 0x01, 0x52, 0x0a, 0x74, 0x6f,
|
||||
0x6b, 0x65, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65,
|
||||
0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x39, 0x0a, 0x0a,
|
||||
0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||
0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x61, 0x74, 0x74,
|
||||
0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x83, 0x01, 0x0a, 0x19, 0x70, 0x61, 0x73, 0x73,
|
||||
0x77, 0x6f, 0x72, 0x64, 0x5f, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69,
|
||||
0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x63, 0x6f,
|
||||
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72,
|
||||
0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72,
|
||||
0x64, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73,
|
||||
0x42, 0x10, 0xfa, 0xd2, 0xe4, 0x93, 0x02, 0x0a, 0x12, 0x08, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e,
|
||||
0x41, 0x4c, 0x48, 0x00, 0x52, 0x17, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x4c, 0x6f,
|
||||
0x67, 0x69, 0x6e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x77, 0x0a,
|
||||
0x15, 0x6f, 0x69, 0x64, 0x63, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x61, 0x74, 0x74, 0x72,
|
||||
0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x63,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65,
|
||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x69, 0x64, 0x63, 0x53, 0x74,
|
||||
0x61, 0x72, 0x74, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x42, 0x10, 0xfa,
|
||||
0xd2, 0xe4, 0x93, 0x02, 0x0a, 0x12, 0x08, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x48,
|
||||
0x00, 0x52, 0x13, 0x6f, 0x69, 0x64, 0x63, 0x53, 0x74, 0x61, 0x72, 0x74, 0x41, 0x74, 0x74, 0x72,
|
||||
0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0xc9, 0x01, 0x0a, 0x2e, 0x6f, 0x69, 0x64, 0x63, 0x5f,
|
||||
0x61, 0x75, 0x74, 0x68, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x61, 0x75, 0x74, 0x68,
|
||||
0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
|
||||
0x6b, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x52, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69,
|
||||
0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6d,
|
||||
0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x69, 0x64, 0x63, 0x41, 0x75,
|
||||
0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69,
|
||||
0x63, 0x61, 0x74, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x42, 0x10, 0xfa, 0xd2, 0xe4, 0x93, 0x02, 0x0a, 0x12, 0x08, 0x49, 0x4e, 0x54,
|
||||
0x45, 0x52, 0x4e, 0x41, 0x4c, 0x48, 0x00, 0x52, 0x29, 0x6f, 0x69, 0x64, 0x63, 0x41, 0x75, 0x74,
|
||||
0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63,
|
||||
0x61, 0x74, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x12, 0xc0, 0x01, 0x0a, 0x2b, 0x6f, 0x69, 0x64, 0x63, 0x5f, 0x61, 0x75, 0x74, 0x68,
|
||||
0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69,
|
||||
0x63, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x4f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
||||
0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72,
|
||||
0x63, 0x65, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x4f, 0x69, 0x64, 0x63, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f,
|
||||
0x64, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b,
|
||||
0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x10, 0xfa, 0xd2, 0xe4, 0x93, 0x02,
|
||||
0x0a, 0x12, 0x08, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x48, 0x00, 0x52, 0x26, 0x6f,
|
||||
0x69, 0x64, 0x63, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x41, 0x75, 0x74,
|
||||
0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x77, 0x0a, 0x15, 0x6c, 0x64, 0x61, 0x70, 0x5f, 0x6c, 0x6f,
|
||||
0x67, 0x69, 0x6e, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x0b,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
|
||||
0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x4c, 0x64, 0x61, 0x70, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x41, 0x74, 0x74, 0x72, 0x69,
|
||||
0x62, 0x75, 0x74, 0x65, 0x73, 0x42, 0x10, 0xfa, 0xd2, 0xe4, 0x93, 0x02, 0x0a, 0x12, 0x08, 0x49,
|
||||
0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x48, 0x00, 0x52, 0x13, 0x6c, 0x64, 0x61, 0x70, 0x4c,
|
||||
0x6f, 0x67, 0x69, 0x6e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x18,
|
||||
0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x42, 0x07, 0x0a, 0x05, 0x61, 0x74, 0x74, 0x72,
|
||||
0x73, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x52, 0x0b, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74,
|
||||
0x69, 0x61, 0x6c, 0x73, 0x22, 0xf8, 0x06, 0x0a, 0x14, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74,
|
||||
0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a,
|
||||
0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70,
|
||||
0x65, 0x12, 0x39, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18,
|
||||
0x6d, 0x22, 0x29, 0x0a, 0x17, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4d,
|
||||
0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02,
|
||||
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x1a, 0x0a, 0x18,
|
||||
0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x85, 0x01, 0x0a, 0x19, 0x4f, 0x69, 0x64,
|
||||
0x63, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x41, 0x74, 0x74, 0x72,
|
||||
0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x52, 0x0a, 0x24,
|
||||
0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72,
|
||||
0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x24, 0x64, 0x69, 0x73, 0x61,
|
||||
0x62, 0x6c, 0x65, 0x5f, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x65, 0x64, 0x5f, 0x63,
|
||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x22, 0xa4, 0x02, 0x0a, 0x12, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69,
|
||||
0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
|
||||
0x6e, 0x12, 0x46, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18,
|
||||
0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x48, 0x00,
|
||||
0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0xc3, 0x01, 0x0a,
|
||||
0x2c, 0x6f, 0x69, 0x64, 0x63, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f,
|
||||
0x64, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x73,
|
||||
0x74, 0x61, 0x72, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x06, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x50, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
|
||||
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x61,
|
||||
0x75, 0x74, 0x68, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x69,
|
||||
0x64, 0x63, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x41, 0x75, 0x74, 0x68,
|
||||
0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x10, 0xfa, 0xd2, 0xe4, 0x93, 0x02, 0x0a, 0x12, 0x08, 0x49,
|
||||
0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x48, 0x00, 0x52, 0x27, 0x6f, 0x69, 0x64, 0x63, 0x41,
|
||||
0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74,
|
||||
0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x12, 0xcc, 0x01, 0x0a, 0x2f, 0x6f, 0x69, 0x64, 0x63, 0x5f, 0x61, 0x75, 0x74, 0x68,
|
||||
0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69,
|
||||
0x63, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x72, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x53, 0x2e, 0x63,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x42, 0x0b,
|
||||
0x9a, 0xe3, 0x29, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x61,
|
||||
0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x92, 0x01, 0x0a, 0x1c, 0x6f, 0x69,
|
||||
0x64, 0x63, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f,
|
||||
0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b,
|
||||
0x32, 0x35, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70,
|
||||
0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x69,
|
||||
0x64, 0x63, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x41, 0x74, 0x74,
|
||||
0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x42, 0x18, 0x9a, 0xe3, 0x29, 0x04, 0x6f, 0x69, 0x64,
|
||||
0x63, 0xfa, 0xd2, 0xe4, 0x93, 0x02, 0x0a, 0x12, 0x08, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41,
|
||||
0x4c, 0x48, 0x00, 0x52, 0x19, 0x6f, 0x69, 0x64, 0x63, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53,
|
||||
0x74, 0x61, 0x74, 0x65, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x42, 0x07,
|
||||
0x0a, 0x05, 0x61, 0x74, 0x74, 0x72, 0x73, 0x22, 0x5e, 0x0a, 0x13, 0x43, 0x68, 0x61, 0x6e, 0x67,
|
||||
0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47,
|
||||
0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x63,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65,
|
||||
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6d, 0x65, 0x74, 0x68,
|
||||
0x6f, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x69, 0x64, 0x63, 0x41, 0x75, 0x74, 0x68, 0x4d,
|
||||
0x65, 0x74, 0x68, 0x6f, 0x64, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74,
|
||||
0x65, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x42, 0x10, 0xfa, 0xd2, 0xe4, 0x93, 0x02, 0x0a, 0x12, 0x08, 0x49, 0x4e, 0x54, 0x45, 0x52,
|
||||
0x4e, 0x41, 0x4c, 0x48, 0x00, 0x52, 0x2a, 0x6f, 0x69, 0x64, 0x63, 0x41, 0x75, 0x74, 0x68, 0x4d,
|
||||
0x65, 0x74, 0x68, 0x6f, 0x64, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74,
|
||||
0x65, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x12, 0xc3, 0x01, 0x0a, 0x2c, 0x6f, 0x69, 0x64, 0x63, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f,
|
||||
0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63,
|
||||
0x61, 0x74, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x50, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
||||
0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72,
|
||||
0x63, 0x65, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x4f, 0x69, 0x64, 0x63, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f,
|
||||
0x64, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b,
|
||||
0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x10, 0xfa, 0xd2, 0xe4, 0x93,
|
||||
0x02, 0x0a, 0x12, 0x08, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x48, 0x00, 0x52, 0x27,
|
||||
0x6f, 0x69, 0x64, 0x63, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x41, 0x75,
|
||||
0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x75, 0x0a, 0x13, 0x61, 0x75, 0x74, 0x68, 0x5f,
|
||||
0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x09,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
|
||||
0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e,
|
||||
0x61, 0x75, 0x74, 0x68, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75,
|
||||
0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x10, 0xfa, 0xd2, 0xe4, 0x93, 0x02, 0x0a, 0x12,
|
||||
0x08, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x48, 0x00, 0x52, 0x11, 0x61, 0x75, 0x74,
|
||||
0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18,
|
||||
0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x42, 0x07, 0x0a, 0x05, 0x61, 0x74, 0x74, 0x72,
|
||||
0x73, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x52, 0x04, 0x69,
|
||||
0x74, 0x65, 0x6d, 0x52, 0x0a, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x32,
|
||||
0x95, 0x0b, 0x0a, 0x11, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x53, 0x65,
|
||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xb8, 0x01, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x41, 0x75, 0x74,
|
||||
0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
|
||||
0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
|
||||
0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68,
|
||||
0x6f, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
|
||||
0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69,
|
||||
0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65,
|
||||
0x74, 0x68, 0x6f, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x42, 0x92, 0x41,
|
||||
0x1c, 0x12, 0x1a, 0x47, 0x65, 0x74, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65,
|
||||
0x20, 0x41, 0x75, 0x74, 0x68, 0x20, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x2e, 0x82, 0xd3, 0xe4,
|
||||
0x93, 0x02, 0x1d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x61,
|
||||
0x75, 0x74, 0x68, 0x2d, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d,
|
||||
0x12, 0xb0, 0x01, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74,
|
||||
0x68, 0x6f, 0x64, 0x73, 0x12, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
|
||||
0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64,
|
||||
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
||||
0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
|
||||
0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65,
|
||||
0x74, 0x68, 0x6f, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x34, 0x92,
|
||||
0x41, 0x19, 0x12, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x41, 0x75,
|
||||
0x74, 0x68, 0x20, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02,
|
||||
0x12, 0x12, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2d, 0x6d, 0x65, 0x74, 0x68,
|
||||
0x6f, 0x64, 0x73, 0x12, 0xc5, 0x01, 0x0a, 0x10, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x75,
|
||||
0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
||||
0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
|
||||
0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68,
|
||||
0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73,
|
||||
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74,
|
||||
0x65, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x22, 0x46, 0x92, 0x41, 0x1f, 0x12, 0x1d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65,
|
||||
0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x20,
|
||||
0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x3a, 0x04, 0x69,
|
||||
0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x61,
|
||||
0x75, 0x74, 0x68, 0x2d, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x12, 0xc4, 0x01, 0x0a, 0x10,
|
||||
0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64,
|
||||
0x12, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70,
|
||||
0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70,
|
||||
0x64, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
|
||||
0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74,
|
||||
0x68, 0x6f, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x45, 0x92, 0x41, 0x19,
|
||||
0x12, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x41, 0x75, 0x74,
|
||||
0x68, 0x20, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x23, 0x3a,
|
||||
0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x32, 0x15, 0x2f, 0x76, 0x31,
|
||||
0x2f, 0x61, 0x75, 0x74, 0x68, 0x2d, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2f, 0x7b, 0x69,
|
||||
0x64, 0x7d, 0x12, 0xb6, 0x01, 0x0a, 0x10, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x75, 0x74,
|
||||
0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f,
|
||||
0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
|
||||
0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4d,
|
||||
0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x63,
|
||||
0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65,
|
||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65,
|
||||
0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x22, 0x37, 0x92, 0x41, 0x17, 0x12, 0x15, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73,
|
||||
0x20, 0x61, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x82, 0xd3,
|
||||
0xe4, 0x93, 0x02, 0x17, 0x2a, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2d, 0x6d,
|
||||
0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0xcf, 0x01, 0x0a, 0x0b,
|
||||
0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2e, 0x2e, 0x63, 0x6f,
|
||||
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72,
|
||||
0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53,
|
||||
0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x63, 0x6f,
|
||||
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72,
|
||||
0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53,
|
||||
0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x5f, 0x92, 0x41,
|
||||
0x29, 0x12, 0x27, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
|
||||
0x74, 0x61, 0x74, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x4f, 0x49, 0x44, 0x43, 0x20,
|
||||
0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2d,
|
||||
0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x22, 0x2f, 0x76, 0x31, 0x2f, 0x61,
|
||||
0x75, 0x74, 0x68, 0x2d, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d,
|
||||
0x3a, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2d, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0xf7, 0x01,
|
||||
0x0a, 0x0c, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x2f,
|
||||
0x6f, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f,
|
||||
0x64, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x55, 0x0a, 0x17, 0x50, 0x61, 0x73, 0x73, 0x77,
|
||||
0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
|
||||
0x65, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x5f, 0x6e, 0x61,
|
||||
0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x96,
|
||||
0x01, 0x0a, 0x13, 0x4f, 0x69, 0x64, 0x63, 0x53, 0x74, 0x61, 0x72, 0x74, 0x41, 0x74, 0x74, 0x72,
|
||||
0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x45, 0x0a, 0x11, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x74,
|
||||
0x72, 0x69, 0x70, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x11, 0x72, 0x6f, 0x75, 0x6e,
|
||||
0x64, 0x74, 0x72, 0x69, 0x70, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x38, 0x0a,
|
||||
0x18, 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69,
|
||||
0x70, 0x5f, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x16, 0x63, 0x61, 0x63, 0x68, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x74, 0x72, 0x69, 0x70,
|
||||
0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x51, 0x0a, 0x13, 0x4c, 0x64, 0x61, 0x70, 0x4c,
|
||||
0x6f, 0x67, 0x69, 0x6e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x1e,
|
||||
0x0a, 0x0a, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x0a, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a,
|
||||
0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0xed, 0x07, 0x0a, 0x13, 0x41,
|
||||
0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x12, 0x26, 0x0a, 0x0e, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f,
|
||||
0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x61, 0x75, 0x74, 0x68,
|
||||
0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x69, 0x64, 0x12, 0x22, 0x0a, 0x0a, 0x74, 0x6f,
|
||||
0x6b, 0x65, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x02,
|
||||
0x18, 0x01, 0x52, 0x0a, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12,
|
||||
0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79,
|
||||
0x70, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73,
|
||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x48,
|
||||
0x00, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x83, 0x01,
|
||||
0x0a, 0x19, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x6c, 0x6f, 0x67, 0x69, 0x6e,
|
||||
0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61,
|
||||
0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x50,
|
||||
0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x41, 0x74, 0x74, 0x72,
|
||||
0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x42, 0x10, 0xfa, 0xd2, 0xe4, 0x93, 0x02, 0x0a, 0x12, 0x08,
|
||||
0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x48, 0x00, 0x52, 0x17, 0x70, 0x61, 0x73, 0x73,
|
||||
0x77, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75,
|
||||
0x74, 0x65, 0x73, 0x12, 0x77, 0x0a, 0x15, 0x6f, 0x69, 0x64, 0x63, 0x5f, 0x73, 0x74, 0x61, 0x72,
|
||||
0x74, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e,
|
||||
0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x4f, 0x69, 0x64, 0x63, 0x53, 0x74, 0x61, 0x72, 0x74, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75,
|
||||
0x74, 0x65, 0x73, 0x42, 0x10, 0xfa, 0xd2, 0xe4, 0x93, 0x02, 0x0a, 0x12, 0x08, 0x49, 0x4e, 0x54,
|
||||
0x45, 0x52, 0x4e, 0x41, 0x4c, 0x48, 0x00, 0x52, 0x13, 0x6f, 0x69, 0x64, 0x63, 0x53, 0x74, 0x61,
|
||||
0x72, 0x74, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0xc9, 0x01, 0x0a,
|
||||
0x2e, 0x6f, 0x69, 0x64, 0x63, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f,
|
||||
0x64, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x63,
|
||||
0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18,
|
||||
0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x52, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
|
||||
0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73,
|
||||
0x2e, 0x61, 0x75, 0x74, 0x68, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x4f, 0x69, 0x64, 0x63, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x41, 0x75,
|
||||
0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61,
|
||||
0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x10, 0xfa, 0xd2, 0xe4, 0x93, 0x02,
|
||||
0x0a, 0x12, 0x08, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x48, 0x00, 0x52, 0x29, 0x6f,
|
||||
0x69, 0x64, 0x63, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x41, 0x75, 0x74,
|
||||
0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63,
|
||||
0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xc0, 0x01, 0x0a, 0x2b, 0x6f, 0x69, 0x64,
|
||||
0x63, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x61, 0x75,
|
||||
0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e,
|
||||
0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x4f,
|
||||
0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e,
|
||||
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68,
|
||||
0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69,
|
||||
0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74,
|
||||
0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x22, 0x83, 0x01, 0x92, 0x41, 0x47, 0x12, 0x45, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74,
|
||||
0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x61, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, 0x74, 0x6f, 0x20,
|
||||
0x61, 0x6e, 0x20, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x72, 0x65, 0x74,
|
||||
0x72, 0x69, 0x65, 0x76, 0x65, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74,
|
||||
0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x2e, 0x82, 0xd3,
|
||||
0xe4, 0x93, 0x02, 0x33, 0x3a, 0x01, 0x2a, 0x22, 0x2e, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x75, 0x74,
|
||||
0x68, 0x2d, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2f, 0x7b, 0x61, 0x75, 0x74, 0x68, 0x5f,
|
||||
0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x69, 0x64, 0x7d, 0x3a, 0x61, 0x75, 0x74, 0x68, 0x65,
|
||||
0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x42, 0x55, 0xa2, 0xe3, 0x29, 0x04, 0x61, 0x75, 0x74,
|
||||
0x68, 0x5a, 0x4b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61,
|
||||
0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79,
|
||||
0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f,
|
||||
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72,
|
||||
0x76, 0x69, 0x63, 0x65, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62, 0x06,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6d, 0x65,
|
||||
0x74, 0x68, 0x6f, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x69, 0x64, 0x63, 0x41, 0x75, 0x74,
|
||||
0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63,
|
||||
0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42,
|
||||
0x10, 0xfa, 0xd2, 0xe4, 0x93, 0x02, 0x0a, 0x12, 0x08, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41,
|
||||
0x4c, 0x48, 0x00, 0x52, 0x26, 0x6f, 0x69, 0x64, 0x63, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74,
|
||||
0x68, 0x6f, 0x64, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x54,
|
||||
0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x77, 0x0a, 0x15, 0x6c,
|
||||
0x64, 0x61, 0x70, 0x5f, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62,
|
||||
0x75, 0x74, 0x65, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x63, 0x6f, 0x6e,
|
||||
0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76,
|
||||
0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x64, 0x61, 0x70, 0x4c, 0x6f, 0x67, 0x69,
|
||||
0x6e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x42, 0x10, 0xfa, 0xd2, 0xe4,
|
||||
0x93, 0x02, 0x0a, 0x12, 0x08, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x48, 0x00, 0x52,
|
||||
0x13, 0x6c, 0x64, 0x61, 0x70, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62,
|
||||
0x75, 0x74, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18,
|
||||
0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x42, 0x07,
|
||||
0x0a, 0x05, 0x61, 0x74, 0x74, 0x72, 0x73, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x52, 0x0b, 0x63,
|
||||
0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x22, 0xf8, 0x06, 0x0a, 0x14, 0x41,
|
||||
0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69,
|
||||
0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f,
|
||||
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74,
|
||||
0x72, 0x75, 0x63, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
|
||||
0x65, 0x73, 0x12, 0xc3, 0x01, 0x0a, 0x2c, 0x6f, 0x69, 0x64, 0x63, 0x5f, 0x61, 0x75, 0x74, 0x68,
|
||||
0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69,
|
||||
0x63, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x50, 0x2e, 0x63, 0x6f, 0x6e, 0x74,
|
||||
0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75,
|
||||
0x72, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x69, 0x64, 0x63, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68,
|
||||
0x6f, 0x64, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x74,
|
||||
0x61, 0x72, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x10, 0xfa, 0xd2, 0xe4,
|
||||
0x93, 0x02, 0x0a, 0x12, 0x08, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x48, 0x00, 0x52,
|
||||
0x27, 0x6f, 0x69, 0x64, 0x63, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x41,
|
||||
0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xcc, 0x01, 0x0a, 0x2f, 0x6f, 0x69, 0x64,
|
||||
0x63, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x61, 0x75,
|
||||
0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x62,
|
||||
0x61, 0x63, 0x6b, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x07, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x53, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e,
|
||||
0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x75,
|
||||
0x74, 0x68, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x69, 0x64,
|
||||
0x63, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x41, 0x75, 0x74, 0x68, 0x65,
|
||||
0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x10, 0xfa, 0xd2, 0xe4, 0x93, 0x02, 0x0a, 0x12,
|
||||
0x08, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x48, 0x00, 0x52, 0x2a, 0x6f, 0x69, 0x64,
|
||||
0x63, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x41, 0x75, 0x74, 0x68, 0x65,
|
||||
0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xc3, 0x01, 0x0a, 0x2c, 0x6f, 0x69, 0x64, 0x63,
|
||||
0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x61, 0x75, 0x74,
|
||||
0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f,
|
||||
0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x50,
|
||||
0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e,
|
||||
0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6d, 0x65,
|
||||
0x74, 0x68, 0x6f, 0x64, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x69, 0x64, 0x63, 0x41, 0x75, 0x74,
|
||||
0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63,
|
||||
0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x42, 0x10, 0xfa, 0xd2, 0xe4, 0x93, 0x02, 0x0a, 0x12, 0x08, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e,
|
||||
0x41, 0x4c, 0x48, 0x00, 0x52, 0x27, 0x6f, 0x69, 0x64, 0x63, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65,
|
||||
0x74, 0x68, 0x6f, 0x64, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65,
|
||||
0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x75, 0x0a,
|
||||
0x13, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x72, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x63, 0x6f, 0x6e,
|
||||
0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f,
|
||||
0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x42, 0x10, 0xfa,
|
||||
0xd2, 0xe4, 0x93, 0x02, 0x0a, 0x12, 0x08, 0x49, 0x4e, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x48,
|
||||
0x00, 0x52, 0x11, 0x61, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18,
|
||||
0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x42, 0x07,
|
||||
0x0a, 0x05, 0x61, 0x74, 0x74, 0x72, 0x73, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x4a, 0x04, 0x08,
|
||||
0x02, 0x10, 0x03, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x52, 0x0a, 0x74, 0x6f, 0x6b, 0x65, 0x6e,
|
||||
0x5f, 0x74, 0x79, 0x70, 0x65, 0x32, 0x95, 0x0b, 0x0a, 0x11, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65,
|
||||
0x74, 0x68, 0x6f, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xb8, 0x01, 0x0a, 0x0d,
|
||||
0x47, 0x65, 0x74, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x30, 0x2e,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73,
|
||||
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x75,
|
||||
0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x31, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69,
|
||||
0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74,
|
||||
0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x22, 0x42, 0x92, 0x41, 0x1c, 0x12, 0x1a, 0x47, 0x65, 0x74, 0x73, 0x20, 0x61, 0x20,
|
||||
0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x20, 0x4d, 0x65, 0x74, 0x68,
|
||||
0x6f, 0x64, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12,
|
||||
0x15, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2d, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64,
|
||||
0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0xb0, 0x01, 0x0a, 0x0f, 0x4c, 0x69, 0x73, 0x74, 0x41,
|
||||
0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x12, 0x32, 0x2e, 0x63, 0x6f, 0x6e,
|
||||
0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76,
|
||||
0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x75, 0x74, 0x68,
|
||||
0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x33,
|
||||
0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e,
|
||||
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74,
|
||||
0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x22, 0x34, 0x92, 0x41, 0x19, 0x12, 0x17, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x20,
|
||||
0x61, 0x6c, 0x6c, 0x20, 0x41, 0x75, 0x74, 0x68, 0x20, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73,
|
||||
0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x75, 0x74,
|
||||
0x68, 0x2d, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x12, 0xc5, 0x01, 0x0a, 0x10, 0x43, 0x72,
|
||||
0x65, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x33,
|
||||
0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e,
|
||||
0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61,
|
||||
0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72,
|
||||
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f,
|
||||
0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x46, 0x92, 0x41, 0x1f, 0x12, 0x1d,
|
||||
0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65,
|
||||
0x20, 0x41, 0x75, 0x74, 0x68, 0x20, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x2e, 0x82, 0xd3, 0xe4,
|
||||
0x93, 0x02, 0x1e, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22,
|
||||
0x10, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2d, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64,
|
||||
0x73, 0x12, 0xc4, 0x01, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68,
|
||||
0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x33, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c,
|
||||
0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65,
|
||||
0x74, 0x68, 0x6f, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x63, 0x6f,
|
||||
0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72,
|
||||
0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41,
|
||||
0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x22, 0x45, 0x92, 0x41, 0x19, 0x12, 0x17, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x20,
|
||||
0x61, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x20, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x2e, 0x82,
|
||||
0xd3, 0xe4, 0x93, 0x02, 0x23, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65,
|
||||
0x6d, 0x32, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2d, 0x6d, 0x65, 0x74, 0x68,
|
||||
0x6f, 0x64, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0xb6, 0x01, 0x0a, 0x10, 0x44, 0x65, 0x6c,
|
||||
0x65, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x33, 0x2e,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73,
|
||||
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74,
|
||||
0x65, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x34, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e,
|
||||
0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x37, 0x92, 0x41, 0x17, 0x12, 0x15, 0x44,
|
||||
0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65,
|
||||
0x74, 0x68, 0x6f, 0x64, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x2a, 0x15, 0x2f, 0x76, 0x31, 0x2f,
|
||||
0x61, 0x75, 0x74, 0x68, 0x2d, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2f, 0x7b, 0x69, 0x64,
|
||||
0x7d, 0x12, 0xcf, 0x01, 0x0a, 0x0b, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74,
|
||||
0x65, 0x12, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61,
|
||||
0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43,
|
||||
0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61,
|
||||
0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43,
|
||||
0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x22, 0x5f, 0x92, 0x41, 0x29, 0x12, 0x27, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73,
|
||||
0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e,
|
||||
0x20, 0x4f, 0x49, 0x44, 0x43, 0x20, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64,
|
||||
0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2d, 0x3a, 0x01, 0x2a, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22,
|
||||
0x22, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2d, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64,
|
||||
0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2d, 0x73, 0x74,
|
||||
0x61, 0x74, 0x65, 0x12, 0xf7, 0x01, 0x0a, 0x0c, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69,
|
||||
0x63, 0x61, 0x74, 0x65, 0x12, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65,
|
||||
0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
|
||||
0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x83, 0x01, 0x92, 0x41, 0x47, 0x12, 0x45, 0x41,
|
||||
0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x61, 0x20, 0x75, 0x73,
|
||||
0x65, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x6e, 0x20, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x20, 0x61,
|
||||
0x6e, 0x64, 0x20, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x76, 0x65, 0x20, 0x61, 0x6e, 0x20, 0x61,
|
||||
0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f,
|
||||
0x6b, 0x65, 0x6e, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x33, 0x3a, 0x01, 0x2a, 0x22, 0x2e, 0x2f,
|
||||
0x76, 0x31, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2d, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x73, 0x2f,
|
||||
0x7b, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x5f, 0x69, 0x64, 0x7d,
|
||||
0x3a, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x42, 0x55, 0xa2,
|
||||
0xe3, 0x29, 0x04, 0x61, 0x75, 0x74, 0x68, 0x5a, 0x4b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f,
|
||||
0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f,
|
||||
0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61,
|
||||
0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76,
|
||||
0x69, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -107,10 +107,40 @@ message ListAuthMethodsRequest {
|
||||
string scope_id = 1 [json_name = "scope_id"]; // @gotags: `class:"public" eventstream:"observation"`
|
||||
bool recursive = 20 [json_name = "recursive"]; // @gotags: `class:"public" eventstream:"observation"`
|
||||
string filter = 30 [json_name = "filter"]; // @gotags: `class:"public"`
|
||||
// An opaque token used to continue an existing iteration or
|
||||
// request updated items. If not specified, pagination
|
||||
// will start from the beginning.
|
||||
string list_token = 40 [json_name = "list_token"]; // @gotags: `class:"public"`
|
||||
// The maximum size of a page in this iteration.
|
||||
// If unset, the default page size configured will be used.
|
||||
// If the page_size is greater than the max page size configured,
|
||||
// the page size will be truncated to this number.
|
||||
uint32 page_size = 50 [json_name = "page_size"]; // @gotags: `class:"public"`
|
||||
}
|
||||
|
||||
message ListAuthMethodsResponse {
|
||||
// The items returned in this page.
|
||||
repeated resources.authmethods.v1.AuthMethod items = 1;
|
||||
// The type of response, either "delta" or "complete".
|
||||
// Delta signifies that this is part of a paginated result
|
||||
// or an update to a previously completed pagination.
|
||||
// Complete signifies that it is the last page.
|
||||
string response_type = 2 [json_name = "response_type"]; // @gotags: `class:"public"`
|
||||
// An opaque token used to continue an existing pagination or
|
||||
// request updated items. Use this token in the next list request
|
||||
// to request the next page.
|
||||
string list_token = 3 [json_name = "list_token"]; // @gotags: `class:"public"`
|
||||
// The name of the field which the items are sorted by.
|
||||
string sort_by = 4 [json_name = "sort_by"]; // @gotags: `class:"public"`
|
||||
// The direction of the sort, either "asc" or "desc".
|
||||
string sort_dir = 5 [json_name = "sort_dir"]; // @gotags: `class:"public"`
|
||||
// A list of item IDs that have been removed since they were returned
|
||||
// as part of a pagination. They should be dropped from any client cache.
|
||||
// This may contain items that are not known to the cache, if they were
|
||||
// created and deleted between listings.
|
||||
repeated string removed_ids = 6 [json_name = "removed_ids"]; // @gotags: `class:"public"`
|
||||
// An estimate at the total items available. This may change during pagination.
|
||||
uint32 est_item_count = 7 [json_name = "est_item_count"]; // @gotags: `class:"public"`
|
||||
}
|
||||
|
||||
message CreateAuthMethodRequest {
|
||||
|
||||
@@ -200,9 +200,9 @@ func TestList(t *testing.T) {
|
||||
result, err := amClient.List(tc.Context(), global)
|
||||
require.NoError(err)
|
||||
require.Len(result.Items, 3)
|
||||
genOIDCAM := result.Items[0]
|
||||
genPWAM := result.Items[1]
|
||||
genLDAPAM := result.Items[2]
|
||||
genLDAPAM := result.Items[0]
|
||||
genOIDCAM := result.Items[1]
|
||||
genPWAM := result.Items[2]
|
||||
|
||||
pwAM, err := amClient.Create(tc.Context(), "password", global,
|
||||
authmethods.WithName("bar"),
|
||||
|
||||
Reference in new issue
Block a user