1// Copyright 2016 The etcd Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package clientv3
16
17import (
18	"context"
19	"fmt"
20	"strings"
21
22	"go.etcd.io/etcd/api/v3/authpb"
23	pb "go.etcd.io/etcd/api/v3/etcdserverpb"
24	"google.golang.org/grpc"
25)
26
27type (
28	AuthEnableResponse               pb.AuthEnableResponse
29	AuthDisableResponse              pb.AuthDisableResponse
30	AuthStatusResponse               pb.AuthStatusResponse
31	AuthenticateResponse             pb.AuthenticateResponse
32	AuthUserAddResponse              pb.AuthUserAddResponse
33	AuthUserDeleteResponse           pb.AuthUserDeleteResponse
34	AuthUserChangePasswordResponse   pb.AuthUserChangePasswordResponse
35	AuthUserGrantRoleResponse        pb.AuthUserGrantRoleResponse
36	AuthUserGetResponse              pb.AuthUserGetResponse
37	AuthUserRevokeRoleResponse       pb.AuthUserRevokeRoleResponse
38	AuthRoleAddResponse              pb.AuthRoleAddResponse
39	AuthRoleGrantPermissionResponse  pb.AuthRoleGrantPermissionResponse
40	AuthRoleGetResponse              pb.AuthRoleGetResponse
41	AuthRoleRevokePermissionResponse pb.AuthRoleRevokePermissionResponse
42	AuthRoleDeleteResponse           pb.AuthRoleDeleteResponse
43	AuthUserListResponse             pb.AuthUserListResponse
44	AuthRoleListResponse             pb.AuthRoleListResponse
45
46	PermissionType authpb.Permission_Type
47	Permission     authpb.Permission
48)
49
50const (
51	PermRead      = authpb.READ
52	PermWrite     = authpb.WRITE
53	PermReadWrite = authpb.READWRITE
54)
55
56type UserAddOptions authpb.UserAddOptions
57
58type Auth interface {
59	// Authenticate login and get token
60	Authenticate(ctx context.Context, name string, password string) (*AuthenticateResponse, error)
61
62	// AuthEnable enables auth of an etcd cluster.
63	AuthEnable(ctx context.Context) (*AuthEnableResponse, error)
64
65	// AuthDisable disables auth of an etcd cluster.
66	AuthDisable(ctx context.Context) (*AuthDisableResponse, error)
67
68	// AuthStatus returns the status of auth of an etcd cluster.
69	AuthStatus(ctx context.Context) (*AuthStatusResponse, error)
70
71	// UserAdd adds a new user to an etcd cluster.
72	UserAdd(ctx context.Context, name string, password string) (*AuthUserAddResponse, error)
73
74	// UserAddWithOptions adds a new user to an etcd cluster with some options.
75	UserAddWithOptions(ctx context.Context, name string, password string, opt *UserAddOptions) (*AuthUserAddResponse, error)
76
77	// UserDelete deletes a user from an etcd cluster.
78	UserDelete(ctx context.Context, name string) (*AuthUserDeleteResponse, error)
79
80	// UserChangePassword changes a password of a user.
81	UserChangePassword(ctx context.Context, name string, password string) (*AuthUserChangePasswordResponse, error)
82
83	// UserGrantRole grants a role to a user.
84	UserGrantRole(ctx context.Context, user string, role string) (*AuthUserGrantRoleResponse, error)
85
86	// UserGet gets a detailed information of a user.
87	UserGet(ctx context.Context, name string) (*AuthUserGetResponse, error)
88
89	// UserList gets a list of all users.
90	UserList(ctx context.Context) (*AuthUserListResponse, error)
91
92	// UserRevokeRole revokes a role of a user.
93	UserRevokeRole(ctx context.Context, name string, role string) (*AuthUserRevokeRoleResponse, error)
94
95	// RoleAdd adds a new role to an etcd cluster.
96	RoleAdd(ctx context.Context, name string) (*AuthRoleAddResponse, error)
97
98	// RoleGrantPermission grants a permission to a role.
99	RoleGrantPermission(ctx context.Context, name string, key, rangeEnd string, permType PermissionType) (*AuthRoleGrantPermissionResponse, error)
100
101	// RoleGet gets a detailed information of a role.
102	RoleGet(ctx context.Context, role string) (*AuthRoleGetResponse, error)
103
104	// RoleList gets a list of all roles.
105	RoleList(ctx context.Context) (*AuthRoleListResponse, error)
106
107	// RoleRevokePermission revokes a permission from a role.
108	RoleRevokePermission(ctx context.Context, role string, key, rangeEnd string) (*AuthRoleRevokePermissionResponse, error)
109
110	// RoleDelete deletes a role.
111	RoleDelete(ctx context.Context, role string) (*AuthRoleDeleteResponse, error)
112}
113
114type authClient struct {
115	remote   pb.AuthClient
116	callOpts []grpc.CallOption
117}
118
119func NewAuth(c *Client) Auth {
120	api := &authClient{remote: RetryAuthClient(c)}
121	if c != nil {
122		api.callOpts = c.callOpts
123	}
124	return api
125}
126
127func NewAuthFromAuthClient(remote pb.AuthClient, c *Client) Auth {
128	api := &authClient{remote: remote}
129	if c != nil {
130		api.callOpts = c.callOpts
131	}
132	return api
133}
134
135func (auth *authClient) Authenticate(ctx context.Context, name string, password string) (*AuthenticateResponse, error) {
136	resp, err := auth.remote.Authenticate(ctx, &pb.AuthenticateRequest{Name: name, Password: password}, auth.callOpts...)
137	return (*AuthenticateResponse)(resp), toErr(ctx, err)
138}
139
140func (auth *authClient) AuthEnable(ctx context.Context) (*AuthEnableResponse, error) {
141	resp, err := auth.remote.AuthEnable(ctx, &pb.AuthEnableRequest{}, auth.callOpts...)
142	return (*AuthEnableResponse)(resp), toErr(ctx, err)
143}
144
145func (auth *authClient) AuthDisable(ctx context.Context) (*AuthDisableResponse, error) {
146	resp, err := auth.remote.AuthDisable(ctx, &pb.AuthDisableRequest{}, auth.callOpts...)
147	return (*AuthDisableResponse)(resp), toErr(ctx, err)
148}
149
150func (auth *authClient) AuthStatus(ctx context.Context) (*AuthStatusResponse, error) {
151	resp, err := auth.remote.AuthStatus(ctx, &pb.AuthStatusRequest{}, auth.callOpts...)
152	return (*AuthStatusResponse)(resp), toErr(ctx, err)
153}
154
155func (auth *authClient) UserAdd(ctx context.Context, name string, password string) (*AuthUserAddResponse, error) {
156	resp, err := auth.remote.UserAdd(ctx, &pb.AuthUserAddRequest{Name: name, Password: password, Options: &authpb.UserAddOptions{NoPassword: false}}, auth.callOpts...)
157	return (*AuthUserAddResponse)(resp), toErr(ctx, err)
158}
159
160func (auth *authClient) UserAddWithOptions(ctx context.Context, name string, password string, options *UserAddOptions) (*AuthUserAddResponse, error) {
161	resp, err := auth.remote.UserAdd(ctx, &pb.AuthUserAddRequest{Name: name, Password: password, Options: (*authpb.UserAddOptions)(options)}, auth.callOpts...)
162	return (*AuthUserAddResponse)(resp), toErr(ctx, err)
163}
164
165func (auth *authClient) UserDelete(ctx context.Context, name string) (*AuthUserDeleteResponse, error) {
166	resp, err := auth.remote.UserDelete(ctx, &pb.AuthUserDeleteRequest{Name: name}, auth.callOpts...)
167	return (*AuthUserDeleteResponse)(resp), toErr(ctx, err)
168}
169
170func (auth *authClient) UserChangePassword(ctx context.Context, name string, password string) (*AuthUserChangePasswordResponse, error) {
171	resp, err := auth.remote.UserChangePassword(ctx, &pb.AuthUserChangePasswordRequest{Name: name, Password: password}, auth.callOpts...)
172	return (*AuthUserChangePasswordResponse)(resp), toErr(ctx, err)
173}
174
175func (auth *authClient) UserGrantRole(ctx context.Context, user string, role string) (*AuthUserGrantRoleResponse, error) {
176	resp, err := auth.remote.UserGrantRole(ctx, &pb.AuthUserGrantRoleRequest{User: user, Role: role}, auth.callOpts...)
177	return (*AuthUserGrantRoleResponse)(resp), toErr(ctx, err)
178}
179
180func (auth *authClient) UserGet(ctx context.Context, name string) (*AuthUserGetResponse, error) {
181	resp, err := auth.remote.UserGet(ctx, &pb.AuthUserGetRequest{Name: name}, auth.callOpts...)
182	return (*AuthUserGetResponse)(resp), toErr(ctx, err)
183}
184
185func (auth *authClient) UserList(ctx context.Context) (*AuthUserListResponse, error) {
186	resp, err := auth.remote.UserList(ctx, &pb.AuthUserListRequest{}, auth.callOpts...)
187	return (*AuthUserListResponse)(resp), toErr(ctx, err)
188}
189
190func (auth *authClient) UserRevokeRole(ctx context.Context, name string, role string) (*AuthUserRevokeRoleResponse, error) {
191	resp, err := auth.remote.UserRevokeRole(ctx, &pb.AuthUserRevokeRoleRequest{Name: name, Role: role}, auth.callOpts...)
192	return (*AuthUserRevokeRoleResponse)(resp), toErr(ctx, err)
193}
194
195func (auth *authClient) RoleAdd(ctx context.Context, name string) (*AuthRoleAddResponse, error) {
196	resp, err := auth.remote.RoleAdd(ctx, &pb.AuthRoleAddRequest{Name: name}, auth.callOpts...)
197	return (*AuthRoleAddResponse)(resp), toErr(ctx, err)
198}
199
200func (auth *authClient) RoleGrantPermission(ctx context.Context, name string, key, rangeEnd string, permType PermissionType) (*AuthRoleGrantPermissionResponse, error) {
201	perm := &authpb.Permission{
202		Key:      []byte(key),
203		RangeEnd: []byte(rangeEnd),
204		PermType: authpb.Permission_Type(permType),
205	}
206	resp, err := auth.remote.RoleGrantPermission(ctx, &pb.AuthRoleGrantPermissionRequest{Name: name, Perm: perm}, auth.callOpts...)
207	return (*AuthRoleGrantPermissionResponse)(resp), toErr(ctx, err)
208}
209
210func (auth *authClient) RoleGet(ctx context.Context, role string) (*AuthRoleGetResponse, error) {
211	resp, err := auth.remote.RoleGet(ctx, &pb.AuthRoleGetRequest{Role: role}, auth.callOpts...)
212	return (*AuthRoleGetResponse)(resp), toErr(ctx, err)
213}
214
215func (auth *authClient) RoleList(ctx context.Context) (*AuthRoleListResponse, error) {
216	resp, err := auth.remote.RoleList(ctx, &pb.AuthRoleListRequest{}, auth.callOpts...)
217	return (*AuthRoleListResponse)(resp), toErr(ctx, err)
218}
219
220func (auth *authClient) RoleRevokePermission(ctx context.Context, role string, key, rangeEnd string) (*AuthRoleRevokePermissionResponse, error) {
221	resp, err := auth.remote.RoleRevokePermission(ctx, &pb.AuthRoleRevokePermissionRequest{Role: role, Key: []byte(key), RangeEnd: []byte(rangeEnd)}, auth.callOpts...)
222	return (*AuthRoleRevokePermissionResponse)(resp), toErr(ctx, err)
223}
224
225func (auth *authClient) RoleDelete(ctx context.Context, role string) (*AuthRoleDeleteResponse, error) {
226	resp, err := auth.remote.RoleDelete(ctx, &pb.AuthRoleDeleteRequest{Role: role}, auth.callOpts...)
227	return (*AuthRoleDeleteResponse)(resp), toErr(ctx, err)
228}
229
230func StrToPermissionType(s string) (PermissionType, error) {
231	val, ok := authpb.Permission_Type_value[strings.ToUpper(s)]
232	if ok {
233		return PermissionType(val), nil
234	}
235	return PermissionType(-1), fmt.Errorf("invalid permission type: %s", s)
236}
237