mirror of
https://github.com/gravitational/teleport.git
synced 2026-10-12 02:15:01 +00:00
Adjust provision.Token interface to unsplit Bot accessors in preparation for SQN (#67746)
* Adjust `provision.Token` interface to unsplit Bot accessors in preparation for SQN (variant b) * add todo godocs
This commit is contained in:
@@ -176,11 +176,10 @@ type ProvisionToken interface {
|
||||
GetAWSIIDTTL() Duration
|
||||
// GetJoinMethod returns joining method that must be used with this token.
|
||||
GetJoinMethod() JoinMethod
|
||||
// GetBotName returns the BotName field which must be set for joining bots.
|
||||
GetBotName() string
|
||||
// GetBotScope returns the BotScope field which must be set for bots joining
|
||||
// with a scoped token. It is empty for unscoped bots.
|
||||
GetBotScope() string
|
||||
// GetBot returns the name and scope of the bot that this token can join.
|
||||
// An empty name indicates that this is not a bot token. Provision tokens
|
||||
// can only refer to unscoped bots, so the scope is always empty.
|
||||
GetBot() (name, scope string)
|
||||
// IsStatic returns true if the token is statically configured
|
||||
IsStatic() bool
|
||||
// GetSuggestedLabels returns the set of labels that the resource should add when adding itself to the cluster
|
||||
@@ -609,16 +608,11 @@ func (p *ProvisionTokenV2) IsStatic() bool {
|
||||
return p.Origin() == OriginConfigFile
|
||||
}
|
||||
|
||||
// GetBotName returns the BotName field which must be set for joining bots.
|
||||
func (p *ProvisionTokenV2) GetBotName() string {
|
||||
return p.Spec.BotName
|
||||
}
|
||||
|
||||
// GetBotScope returns the BotScope field which must be set for bots joining
|
||||
// with a scoped token. It is empty for unscoped bots.
|
||||
func (p *ProvisionTokenV2) GetBotScope() string {
|
||||
// Always empty for ProvisionTokenV2
|
||||
return ""
|
||||
// GetBot returns the name and scope of the bot that this token can join. An
|
||||
// empty name indicates that this is not a bot token. Provision tokens can
|
||||
// only refer to unscoped bots, so the scope is always empty.
|
||||
func (p *ProvisionTokenV2) GetBot() (name, scope string) {
|
||||
return p.Spec.BotName, ""
|
||||
}
|
||||
|
||||
// GetKind returns resource kind
|
||||
|
||||
+2
-5
@@ -135,12 +135,10 @@ func (a *Server) handleJoinFailure(
|
||||
if pt != nil {
|
||||
botJoinEvent.Method = string(pt.GetJoinMethod())
|
||||
botJoinEvent.TokenName = pt.GetSafeName()
|
||||
botJoinEvent.BotName = pt.GetBotName()
|
||||
|
||||
// We don't want to perform a backend fetch here, so we'll use the
|
||||
// bot scope indicated in the token rather than the one embedded in
|
||||
// the user.
|
||||
botJoinEvent.Scope = pt.GetBotScope()
|
||||
botJoinEvent.BotName, botJoinEvent.Scope = pt.GetBot()
|
||||
}
|
||||
evt = botJoinEvent
|
||||
} else {
|
||||
@@ -361,7 +359,7 @@ func (a *Server) GenerateBotCertsForJoin(
|
||||
) (*proto.Certs, string, error) {
|
||||
// bots use this endpoint but get a user cert
|
||||
// botResourceName must be set, enforced in CheckAndSetDefaults
|
||||
botName := token.GetBotName()
|
||||
botName, tokenBotScope := token.GetBot()
|
||||
joinMethod := token.GetJoinMethod()
|
||||
|
||||
// Check this is a join method for bots we support.
|
||||
@@ -463,7 +461,6 @@ func (a *Server) GenerateBotCertsForJoin(
|
||||
return nil, "", trace.AccessDenied("scoped token usage mode must be 'bot' for bot joining")
|
||||
}
|
||||
|
||||
tokenBotScope := scoped.GetScoped().GetSpec().GetBotScope()
|
||||
if botScope != tokenBotScope {
|
||||
a.logger.WarnContext(ctx, "bot scope must match token scope",
|
||||
"token_scope", tokenBotScope,
|
||||
|
||||
@@ -86,9 +86,13 @@ type JoinStateParams struct {
|
||||
}
|
||||
|
||||
func (p *JoinStateParams) GetSubject() (string, error) {
|
||||
botName, _ := p.Token.GetBot()
|
||||
switch {
|
||||
case p.Token.GetBotName() != "":
|
||||
return p.Token.GetBotName(), nil
|
||||
case botName != "":
|
||||
// TODO(strideynet): the bare bot name is only a unique identifier
|
||||
// while bots are globally namespaced. Revisit the subject for scoped
|
||||
// bots once bot users are namespaced by scope.
|
||||
return botName, nil
|
||||
case p.HostID != "":
|
||||
return p.HostID, nil
|
||||
case p.Token.GetBoundKeypairStatus().BoundHostID != "":
|
||||
|
||||
@@ -610,6 +610,9 @@ func emitBoundKeypairRecoveryEvent(
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(strideynet): When bots become scope namespaced, ensure this call
|
||||
// site reflects scopedness.
|
||||
botName, _ := token.GetBot()
|
||||
if err := params.AuthService.EmitAuditEvent(context.WithoutCancel(ctx), &apievents.BoundKeypairRecovery{
|
||||
Metadata: apievents.Metadata{
|
||||
Type: events.BoundKeypairRecovery,
|
||||
@@ -620,7 +623,7 @@ func emitBoundKeypairRecoveryEvent(
|
||||
RemoteAddr: params.Diag.Get().RemoteAddr,
|
||||
},
|
||||
TokenName: token.GetName(),
|
||||
BotName: token.GetBotName(),
|
||||
BotName: botName,
|
||||
PublicKey: boundPublicKey,
|
||||
RecoveryCount: recoveryCount,
|
||||
RecoveryMode: token.GetBoundKeypair().Recovery.Mode,
|
||||
@@ -650,6 +653,9 @@ func emitBoundKeypairRotationEvent(
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(strideynet): When bots become scope namespaced, ensure this call
|
||||
// site reflects scopedness.
|
||||
botName, _ := token.GetBot()
|
||||
if err := params.AuthService.EmitAuditEvent(context.WithoutCancel(ctx), &apievents.BoundKeypairRotation{
|
||||
Metadata: apievents.Metadata{
|
||||
Type: events.BoundKeypairRotation,
|
||||
@@ -660,7 +666,7 @@ func emitBoundKeypairRotationEvent(
|
||||
RemoteAddr: params.Diag.Get().RemoteAddr,
|
||||
},
|
||||
TokenName: token.GetName(),
|
||||
BotName: token.GetBotName(),
|
||||
BotName: botName,
|
||||
PreviousPublicKey: prevPublicKey,
|
||||
NewPublicKey: newPublicKey,
|
||||
}); err != nil {
|
||||
@@ -676,6 +682,9 @@ func tryLockTokenInvalidJoinState(
|
||||
) {
|
||||
log := params.Logger.With("join_token", token.GetName(), "validation_error", validationError)
|
||||
|
||||
// TODO(strideynet): When bots become scope namespaced, ensure this call
|
||||
// site reflects scopedness.
|
||||
botName, _ := token.GetBot()
|
||||
if auditErr := params.AuthService.EmitAuditEvent(context.WithoutCancel(ctx), &apievents.BoundKeypairJoinStateVerificationFailed{
|
||||
Metadata: apievents.Metadata{
|
||||
Type: events.BoundKeypairJoinStateVerificationFailed,
|
||||
@@ -689,7 +698,7 @@ func tryLockTokenInvalidJoinState(
|
||||
RemoteAddr: params.Diag.Get().RemoteAddr,
|
||||
},
|
||||
TokenName: token.GetName(),
|
||||
BotName: token.GetBotName(),
|
||||
BotName: botName,
|
||||
}); auditErr != nil {
|
||||
log.WarnContext(ctx, "Failed to emit failed join state verification event", "error", auditErr)
|
||||
}
|
||||
@@ -700,7 +709,7 @@ func tryLockTokenInvalidJoinState(
|
||||
"The join token %q has been locked by bot %q after a client "+
|
||||
"failed to verify its join state, possibly indicating a "+
|
||||
"stolen keypair.",
|
||||
token.GetName(), token.GetBotName(),
|
||||
token.GetName(), botName,
|
||||
)
|
||||
} else {
|
||||
message = fmt.Sprintf(
|
||||
|
||||
@@ -43,11 +43,11 @@ type Token interface {
|
||||
GetRoles() types.SystemRoles
|
||||
// Expiry returns the token's expiration time.
|
||||
Expiry() time.Time
|
||||
// GetBotName returns the BotName field which must be set for joining bots.
|
||||
GetBotName() string
|
||||
// GetBotScope returns the BotScope field which must be set for bots joining
|
||||
// with a scoped token. It is empty for unscoped bots.
|
||||
GetBotScope() string
|
||||
// GetBot returns the name and scope of the bot that this token can join.
|
||||
// An empty name indicates that this is not a bot token. An empty scope
|
||||
// refers to an unscoped bot; scoped bot tokens always carry both
|
||||
// components.
|
||||
GetBot() (name, scope string)
|
||||
// GetAssignedScope returns the scope that will be assigned to provisioned resources
|
||||
// provisioned using the wrapped [joiningv1.ScopedToken].
|
||||
GetAssignedScope() string
|
||||
|
||||
+1
-3
@@ -278,11 +278,9 @@ func (s *Server) Join(stream messages.ServerStream) (err error) {
|
||||
i.SafeTokenName = token.GetSafeName()
|
||||
i.TokenJoinMethod = string(configuredJoinMethod(token))
|
||||
i.TokenExpires = token.Expiry()
|
||||
i.BotName = token.GetBotName()
|
||||
|
||||
// It's not worth fetching the true bot scope here (via bot user label)
|
||||
// so we'll just include the one embedded in the token.
|
||||
i.BotScope = token.GetBotScope()
|
||||
i.BotName, i.BotScope = token.GetBot()
|
||||
})
|
||||
|
||||
// Validate that the requested join method matches the join method
|
||||
|
||||
@@ -207,7 +207,9 @@ func AdaptRegisterUsingBoundKeypairMethod(
|
||||
i.SafeTokenName = provisionToken.GetSafeName()
|
||||
i.TokenJoinMethod = string(provisionToken.GetJoinMethod())
|
||||
i.TokenExpires = provisionToken.Expiry()
|
||||
i.BotName = provisionToken.GetBotName()
|
||||
// TODO(strideynet): When bots become scope namespaced, ensure this
|
||||
// call site reflects scopedness.
|
||||
i.BotName, _ = provisionToken.GetBot()
|
||||
})
|
||||
if provisionToken.GetJoinMethod() != types.JoinMethodBoundKeypair {
|
||||
return nil, trace.BadParameter("specified join token is not for `%s` method", types.JoinMethodBoundKeypair)
|
||||
|
||||
+58
-28
@@ -296,7 +296,7 @@ func validateJoinMethod(token *joiningv1.ScopedToken) error {
|
||||
|
||||
// validateBot is used to validate plausibly-bot tokens (if `isBotToken()` has
|
||||
// returned true).
|
||||
func validateBotToken(token *joiningv1.ScopedToken, roles types.SystemRoles) error {
|
||||
func strongValidateBotToken(token *joiningv1.ScopedToken, roles types.SystemRoles) error {
|
||||
spec := token.GetSpec()
|
||||
|
||||
if spec.GetBotName() == "" {
|
||||
@@ -362,6 +362,30 @@ func validateNonBotToken(token *joiningv1.ScopedToken) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateBotRef weak-validates the bot reference fields of a scoped token
|
||||
// spec and returns the referenced bot's name and scope. Bot tokens must carry
|
||||
// both components. For non-bot tokens the bot fields are ignored and empty
|
||||
// values are returned: stray bot fields on a non-bot token are rejected by
|
||||
// strong validation at write time, but tolerated here to match weak
|
||||
// validation's posture toward existing resources.
|
||||
func validateBotRef(spec *joiningv1.ScopedTokenSpec, isBotToken bool) (name, scope string, err error) {
|
||||
if !isBotToken {
|
||||
return "", "", nil
|
||||
}
|
||||
|
||||
if spec.GetBotName() == "" {
|
||||
return "", "", trace.BadParameter("expected non-empty bot_name for a scoped bot token")
|
||||
}
|
||||
if spec.GetBotScope() == "" {
|
||||
return "", "", trace.BadParameter("expected non-empty bot_scope for a scoped bot token")
|
||||
}
|
||||
if err := scopes.WeakValidate(spec.GetBotScope()); err != nil {
|
||||
return "", "", trace.Wrap(err, "validating scoped token bot_scope")
|
||||
}
|
||||
|
||||
return spec.GetBotName(), spec.GetBotScope(), nil
|
||||
}
|
||||
|
||||
// StrongValidateToken checks if the scoped token is well-formed according to
|
||||
// all scoped token rules. This function *must* be used to validate any scoped
|
||||
// token being created from scratch. When validating existing scoped token
|
||||
@@ -424,7 +448,7 @@ func StrongValidateToken(token *joiningv1.ScopedToken) error {
|
||||
}
|
||||
|
||||
if roles.Include(types.RoleBot) {
|
||||
if err := validateBotToken(token, roles); err != nil {
|
||||
if err := strongValidateBotToken(token, roles); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
} else {
|
||||
@@ -456,19 +480,10 @@ func WeakValidateToken(token *joiningv1.ScopedToken) error {
|
||||
// Determine if this is a bot token without potentially trying to validate
|
||||
// other unknown roles.
|
||||
isBotToken := slices.Contains(spec.GetRoles(), string(types.RoleBot))
|
||||
if isBotToken {
|
||||
if token.GetSpec().GetBotName() == "" {
|
||||
return trace.BadParameter("expected non-empty bot_name for a scoped bot token")
|
||||
}
|
||||
|
||||
if token.GetSpec().GetBotScope() == "" {
|
||||
return trace.BadParameter("expected non-empty bot_scope for a scoped bot token")
|
||||
}
|
||||
|
||||
if err := scopes.WeakValidate(spec.GetBotScope()); err != nil {
|
||||
return trace.Wrap(err, "validating scoped token bot_scope")
|
||||
}
|
||||
} else {
|
||||
if _, _, err := validateBotRef(spec, isBotToken); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
if !isBotToken {
|
||||
if err := scopes.WeakValidate(token.GetSpec().GetAssignedScope()); err != nil {
|
||||
return trace.Wrap(err, "validating scoped token assigned scope")
|
||||
}
|
||||
@@ -548,13 +563,17 @@ type Token struct {
|
||||
scoped *joiningv1.ScopedToken
|
||||
joinMethod types.JoinMethod
|
||||
roles types.SystemRoles
|
||||
botName string
|
||||
botScope string
|
||||
}
|
||||
|
||||
// NewToken returns the wrapped version of the given [joiningv1.ScopedToken].
|
||||
// It will return an error if the configured join method is not a valid
|
||||
// [types.JoinMethod] or if any of the configured roles are not a valid
|
||||
// [types.SystemRole]. The validated join method and roles are cached on the
|
||||
// [Scoped] wrapper itself so they can be read without repeating validation.
|
||||
// [types.JoinMethod], if any of the configured roles are not a valid
|
||||
// [types.SystemRole], or if the bot_name/bot_scope fields are inconsistent
|
||||
// with the configured roles. The validated join method, roles, and bot
|
||||
// reference are cached on the [Token] wrapper itself so they can be read
|
||||
// without repeating validation.
|
||||
func NewToken(token *joiningv1.ScopedToken) (*Token, error) {
|
||||
joinMethod := types.JoinMethod(token.GetSpec().GetJoinMethod())
|
||||
if err := types.ValidateJoinMethod(joinMethod); err != nil {
|
||||
@@ -566,7 +585,18 @@ func NewToken(token *joiningv1.ScopedToken) (*Token, error) {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
return &Token{scoped: token, joinMethod: joinMethod, roles: roles}, nil
|
||||
botName, botScope, err := validateBotRef(token.GetSpec(), roles.Include(types.RoleBot))
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
}
|
||||
|
||||
return &Token{
|
||||
scoped: token,
|
||||
joinMethod: joinMethod,
|
||||
roles: roles,
|
||||
botName: botName,
|
||||
botScope: botScope,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetName returns the name of a [joiningv1.ScopedToken].
|
||||
@@ -614,16 +644,16 @@ func (t *Token) Expiry() time.Time {
|
||||
return expiry.AsTime()
|
||||
}
|
||||
|
||||
// GetBotName returns an empty string because scoped tokens do not currently
|
||||
// support configuring a bot name.
|
||||
func (t *Token) GetBotName() string {
|
||||
return t.scoped.GetSpec().GetBotName()
|
||||
}
|
||||
// GetBot returns the cached name and scope of the bot that this token can
|
||||
// join, validated when the [joiningv1.ScopedToken] was wrapped. An empty name
|
||||
// indicates that this is not a bot token; otherwise both components are
|
||||
// non-empty.
|
||||
func (t *Token) GetBot() (name, scope string) {
|
||||
if t == nil {
|
||||
return "", ""
|
||||
}
|
||||
|
||||
// GetBotScope returns the BotScope field which must be set for bots joining
|
||||
// with a scoped token. It is empty for unscoped bots.
|
||||
func (t *Token) GetBotScope() string {
|
||||
return t.scoped.GetSpec().GetBotScope()
|
||||
return t.botName, t.botScope
|
||||
}
|
||||
|
||||
// GetAssignedScope returns the scope that will be assigned to resources
|
||||
|
||||
@@ -1115,6 +1115,116 @@ func TestScopedTokenAzureRoundTrip(t *testing.T) {
|
||||
}, token.GetAzure())
|
||||
}
|
||||
|
||||
func TestNewTokenGetBot(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
newBotToken := func() *joiningv1.ScopedToken {
|
||||
return joiningv1.ScopedToken_builder{
|
||||
Kind: types.KindScopedToken,
|
||||
Scope: "/aa/bb",
|
||||
Version: types.V1,
|
||||
Metadata: headerv1.Metadata_builder{
|
||||
Name: "testtoken",
|
||||
}.Build(),
|
||||
Spec: joiningv1.ScopedTokenSpec_builder{
|
||||
Roles: []string{types.RoleBot.String()},
|
||||
BotScope: "/aa/bb",
|
||||
BotName: "test-bot",
|
||||
JoinMethod: string(types.JoinMethodBoundKeypair),
|
||||
UsageMode: joining.TokenUsageModeBot,
|
||||
}.Build(),
|
||||
}.Build()
|
||||
}
|
||||
newNonBotToken := func() *joiningv1.ScopedToken {
|
||||
return joiningv1.ScopedToken_builder{
|
||||
Kind: types.KindScopedToken,
|
||||
Scope: "/aa/bb",
|
||||
Version: types.V1,
|
||||
Metadata: headerv1.Metadata_builder{
|
||||
Name: "testtoken",
|
||||
}.Build(),
|
||||
Spec: joiningv1.ScopedTokenSpec_builder{
|
||||
Roles: []string{types.RoleNode.String()},
|
||||
AssignedScope: "/aa/bb",
|
||||
JoinMethod: string(types.JoinMethodToken),
|
||||
UsageMode: string(joining.TokenUsageModeUnlimited),
|
||||
}.Build(),
|
||||
}.Build()
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
token *joiningv1.ScopedToken
|
||||
modFn func(*joiningv1.ScopedToken)
|
||||
expectedBotName string
|
||||
expectedBotScope string
|
||||
expectedErr string
|
||||
}{
|
||||
{
|
||||
name: "bot token",
|
||||
token: newBotToken(),
|
||||
expectedBotName: "test-bot",
|
||||
expectedBotScope: "/aa/bb",
|
||||
},
|
||||
{
|
||||
name: "non-bot token",
|
||||
token: newNonBotToken(),
|
||||
},
|
||||
{
|
||||
// Stray bot fields on a non-bot token are rejected by strong
|
||||
// validation at write time but tolerated when wrapping, matching
|
||||
// weak validation; the bot reference is empty.
|
||||
name: "non-bot token with stray bot fields",
|
||||
token: newNonBotToken(),
|
||||
modFn: func(tok *joiningv1.ScopedToken) {
|
||||
tok.GetSpec().SetBotName("test-bot")
|
||||
tok.GetSpec().SetBotScope("/aa/bb")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "bot token without bot_name",
|
||||
token: newBotToken(),
|
||||
modFn: func(tok *joiningv1.ScopedToken) {
|
||||
tok.GetSpec().SetBotName("")
|
||||
},
|
||||
expectedErr: "expected non-empty bot_name",
|
||||
},
|
||||
{
|
||||
name: "bot token without bot_scope",
|
||||
token: newBotToken(),
|
||||
modFn: func(tok *joiningv1.ScopedToken) {
|
||||
tok.GetSpec().SetBotScope("")
|
||||
},
|
||||
expectedErr: "expected non-empty bot_scope",
|
||||
},
|
||||
{
|
||||
name: "bot token with malformed bot_scope",
|
||||
token: newBotToken(),
|
||||
modFn: func(tok *joiningv1.ScopedToken) {
|
||||
tok.GetSpec().SetBotScope("aa/bb}")
|
||||
},
|
||||
expectedErr: "validating scoped token bot_scope",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if tc.modFn != nil {
|
||||
tc.modFn(tc.token)
|
||||
}
|
||||
token, err := joining.NewToken(tc.token)
|
||||
if tc.expectedErr != "" {
|
||||
require.ErrorContains(t, err, tc.expectedErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
botName, botScope := token.GetBot()
|
||||
require.Equal(t, tc.expectedBotName, botName)
|
||||
require.Equal(t, tc.expectedBotScope, botScope)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestImmutableLabelHashing(t *testing.T) {
|
||||
labels := joiningv1.ImmutableLabels_builder{
|
||||
Ssh: map[string]string{
|
||||
|
||||
@@ -294,7 +294,10 @@ func MatchToken(t types.ProvisionToken, anyRoles types.SystemRoles, botName stri
|
||||
return false
|
||||
}
|
||||
|
||||
if botName != "" && (!t.GetRoles().Include(types.RoleBot) || t.GetBotName() != botName) {
|
||||
// TODO(strideynet): When bots become scope namespaced, ensure this call
|
||||
// site reflects scopedness.
|
||||
tokenBotName, _ := t.GetBot()
|
||||
if botName != "" && (!t.GetRoles().Include(types.RoleBot) || tokenBotName != botName) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@@ -621,7 +621,10 @@ func TestEditToken(t *testing.T) {
|
||||
// Fetch the token and compare
|
||||
editedToken, err := env.server.Auth().GetToken(ctx, tokenName)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "test-bot_EDITED", editedToken.GetBotName())
|
||||
// TODO(strideynet): When bots become scope namespaced, ensure
|
||||
// this call site reflects scopedness.
|
||||
editedBotName, _ := editedToken.GetBot()
|
||||
require.Equal(t, "test-bot_EDITED", editedBotName)
|
||||
require.Equal(t, expiry, *editedToken.GetMetadata().Expires)
|
||||
require.Equal(t, map[string]string{
|
||||
"test-key": "test-value",
|
||||
|
||||
@@ -65,10 +65,13 @@ func MakeJoinToken(token types.ProvisionToken) (*JoinToken, error) {
|
||||
|
||||
_, isCloudSystem := token.GetMetadata().Labels["teleport.internal/cloud/token"]
|
||||
|
||||
// TODO(strideynet): When bots become scope namespaced, ensure this call
|
||||
// site reflects scopedness.
|
||||
botName, _ := token.GetBot()
|
||||
uiToken := &JoinToken{
|
||||
ID: token.GetName(),
|
||||
SafeName: token.GetSafeName(),
|
||||
BotName: token.GetBotName(),
|
||||
BotName: botName,
|
||||
Expiry: token.Expiry(),
|
||||
Roles: token.GetRoles(),
|
||||
IsStatic: token.IsStatic(),
|
||||
|
||||
@@ -501,9 +501,11 @@ func (c *BotsCommand) AddBot(ctx context.Context, client botsCommandClient) erro
|
||||
return trace.BadParameter("token %q is not valid for role %q",
|
||||
c.tokenID, types.RoleBot)
|
||||
}
|
||||
if token.GetBotName() != c.botName {
|
||||
// TODO(strideynet): When bots become scope namespaced, ensure this
|
||||
// call site reflects scopedness.
|
||||
if tokenBotName, _ := token.GetBot(); tokenBotName != c.botName {
|
||||
return trace.BadParameter("token %q is valid for bot with name %q, not %q",
|
||||
c.tokenID, token.GetBotName(), c.botName)
|
||||
c.tokenID, tokenBotName, c.botName)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -954,9 +956,11 @@ func (c *BotsCommand) AddBotInstance(ctx context.Context, client botsCommandClie
|
||||
return trace.BadParameter("token %q is not valid for role %q",
|
||||
c.tokenID, types.RoleBot)
|
||||
}
|
||||
if token.GetBotName() != c.botName {
|
||||
// TODO(strideynet): When bots become scope namespaced, ensure this call
|
||||
// site reflects scopedness.
|
||||
if tokenBotName, _ := token.GetBot(); tokenBotName != c.botName {
|
||||
return trace.BadParameter("token %q is valid for bot with name %q, not %q",
|
||||
c.tokenID, token.GetBotName(), c.botName)
|
||||
c.tokenID, tokenBotName, c.botName)
|
||||
}
|
||||
|
||||
return trace.Wrap(c.outputToken(ctx, client, bot, token))
|
||||
|
||||
Reference in New Issue
Block a user