forked from gravitational/teleport
-
Notifications
You must be signed in to change notification settings - Fork 0
/
user_command.go
167 lines (148 loc) · 5.23 KB
/
user_command.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/*
Copyright 2015-2017 Gravitational, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package common
import (
"fmt"
"net"
"os"
"strconv"
"strings"
"github.com/gravitational/kingpin"
"github.com/gravitational/teleport/lib/auth"
"github.com/gravitational/teleport/lib/defaults"
"github.com/gravitational/teleport/lib/service"
"github.com/gravitational/teleport/lib/services"
"github.com/gravitational/teleport/lib/web"
"github.com/gravitational/trace"
)
// UserCommand implements `tctl users` set of commands
// It implements CLICommand interface
type UserCommand struct {
config *service.Config
login string
allowedLogins string
roles string
identities []string
userAdd *kingpin.CmdClause
userUpdate *kingpin.CmdClause
userList *kingpin.CmdClause
userDelete *kingpin.CmdClause
}
// Initialize allows UserCommand to plug itself into the CLI parser
func (u *UserCommand) Initialize(app *kingpin.Application, config *service.Config) {
u.config = config
users := app.Command("users", "Manage user accounts")
u.userAdd = users.Command("add", "Generate a user invitation token")
u.userAdd.Arg("account", "Teleport user account name").Required().StringVar(&u.login)
u.userAdd.Arg("local-logins", "Local UNIX users this account can log in as [login]").
Default("").StringVar(&u.allowedLogins)
u.userAdd.Alias(AddUserHelp)
u.userUpdate = users.Command("update", "Update properties for existing user").Hidden()
u.userUpdate.Arg("login", "Teleport user login").Required().StringVar(&u.login)
u.userUpdate.Flag("set-roles", "Roles to assign to this user").
Default("").StringVar(&u.roles)
u.userList = users.Command("ls", "List all user accounts")
u.userDelete = users.Command("rm", "Deletes user accounts").Alias("del")
u.userDelete.Arg("logins", "Comma-separated list of user logins to delete").
Required().StringVar(&u.login)
}
// TryRun takes the CLI command as an argument (like "users add") and executes it.
func (u *UserCommand) TryRun(cmd string, client *auth.TunClient) (match bool, err error) {
switch cmd {
case u.userAdd.FullCommand():
err = u.Add(client)
case u.userUpdate.FullCommand():
err = u.Update(client)
case u.userList.FullCommand():
err = u.List(client)
case u.userDelete.FullCommand():
err = u.Delete(client)
default:
return false, nil
}
return true, trace.Wrap(err)
}
// Add creates a new sign-up token and prints a token URL to stdout.
// A user is not created until he visits the sign-up URL and completes the process
func (u *UserCommand) Add(client *auth.TunClient) error {
// if no local logins were specified, default to 'login'
if u.allowedLogins == "" {
u.allowedLogins = u.login
}
user := services.UserV1{
Name: u.login,
AllowedLogins: strings.Split(u.allowedLogins, ","),
}
token, err := client.CreateSignupToken(user)
if err != nil {
return err
}
proxies, err := client.GetProxies()
if err != nil {
return trace.Wrap(err)
}
hostname := "teleport-proxy"
if len(proxies) == 0 {
fmt.Printf("\x1b[1mWARNING\x1b[0m: this Teleport cluster does not have any proxy servers online.\nYou need to start some to be able to login.\n\n")
} else {
hostname = proxies[0].GetHostname()
}
// try to auto-suggest the activation link
_, proxyPort, err := net.SplitHostPort(u.config.Proxy.WebAddr.Addr)
if err != nil {
proxyPort = strconv.Itoa(defaults.HTTPListenPort)
}
url := web.CreateSignupLink(net.JoinHostPort(hostname, proxyPort), token)
fmt.Printf("Signup token has been created and is valid for %v seconds. Share this URL with the user:\n%v\n\nNOTE: make sure '%s' is accessible!\n", defaults.MaxSignupTokenTTL.Seconds(), url, hostname)
return nil
}
// Update updates existing user
func (u *UserCommand) Update(client *auth.TunClient) error {
user, err := client.GetUser(u.login)
if err != nil {
return trace.Wrap(err)
}
roles := strings.Split(u.roles, ",")
for _, role := range roles {
if _, err := client.GetRole(role); err != nil {
return trace.Wrap(err)
}
}
user.SetRoles(roles)
if err := client.UpsertUser(user); err != nil {
return trace.Wrap(err)
}
fmt.Printf("%v has been updated with roles %v\n", user.GetName(), strings.Join(user.GetRoles(), ","))
return nil
}
// List prints all existing user accounts
func (u *UserCommand) List(client *auth.TunClient) error {
users, err := client.GetUsers()
if err != nil {
return trace.Wrap(err)
}
coll := &userCollection{users: users}
coll.writeText(os.Stdout)
return nil
}
// Delete deletes teleport user(s). User IDs are passed as a comma-separated
// list in UserCommand.login
func (u *UserCommand) Delete(client *auth.TunClient) error {
for _, l := range strings.Split(u.login, ",") {
if err := client.DeleteUser(l); err != nil {
return trace.Wrap(err)
}
fmt.Printf("User '%v' has been deleted\n", l)
}
return nil
}