1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package client
16
17 import (
18 "bytes"
19 "context"
20 "encoding/json"
21 "net/http"
22 "net/url"
23 "path"
24 )
25
26 var (
27 defaultV2AuthPrefix = "/v2/auth"
28 )
29
30 type User struct {
31 User string `json:"user"`
32 Password string `json:"password,omitempty"`
33 Roles []string `json:"roles"`
34 Grant []string `json:"grant,omitempty"`
35 Revoke []string `json:"revoke,omitempty"`
36 }
37
38
39 type userListEntry struct {
40 User string `json:"user"`
41 Roles []Role `json:"roles"`
42 }
43
44 type UserRoles struct {
45 User string `json:"user"`
46 Roles []Role `json:"roles"`
47 }
48
49 func v2AuthURL(ep url.URL, action string, name string) *url.URL {
50 if name != "" {
51 ep.Path = path.Join(ep.Path, defaultV2AuthPrefix, action, name)
52 return &ep
53 }
54 ep.Path = path.Join(ep.Path, defaultV2AuthPrefix, action)
55 return &ep
56 }
57
58
59
60 func NewAuthAPI(c Client) AuthAPI {
61 return &httpAuthAPI{
62 client: c,
63 }
64 }
65
66 type AuthAPI interface {
67
68 Enable(ctx context.Context) error
69
70
71 Disable(ctx context.Context) error
72 }
73
74 type httpAuthAPI struct {
75 client httpClient
76 }
77
78 func (s *httpAuthAPI) Enable(ctx context.Context) error {
79 return s.enableDisable(ctx, &authAPIAction{"PUT"})
80 }
81
82 func (s *httpAuthAPI) Disable(ctx context.Context) error {
83 return s.enableDisable(ctx, &authAPIAction{"DELETE"})
84 }
85
86 func (s *httpAuthAPI) enableDisable(ctx context.Context, req httpAction) error {
87 resp, body, err := s.client.Do(ctx, req)
88 if err != nil {
89 return err
90 }
91 if err = assertStatusCode(resp.StatusCode, http.StatusOK, http.StatusCreated); err != nil {
92 var sec authError
93 err = json.Unmarshal(body, &sec)
94 if err != nil {
95 return err
96 }
97 return sec
98 }
99 return nil
100 }
101
102 type authAPIAction struct {
103 verb string
104 }
105
106 func (l *authAPIAction) HTTPRequest(ep url.URL) *http.Request {
107 u := v2AuthURL(ep, "enable", "")
108 req, _ := http.NewRequest(l.verb, u.String(), nil)
109 return req
110 }
111
112 type authError struct {
113 Message string `json:"message"`
114 Code int `json:"-"`
115 }
116
117 func (e authError) Error() string {
118 return e.Message
119 }
120
121
122
123 func NewAuthUserAPI(c Client) AuthUserAPI {
124 return &httpAuthUserAPI{
125 client: c,
126 }
127 }
128
129 type AuthUserAPI interface {
130
131 AddUser(ctx context.Context, username string, password string) error
132
133
134 RemoveUser(ctx context.Context, username string) error
135
136
137 GetUser(ctx context.Context, username string) (*User, error)
138
139
140 GrantUser(ctx context.Context, username string, roles []string) (*User, error)
141
142
143 RevokeUser(ctx context.Context, username string, roles []string) (*User, error)
144
145
146 ChangePassword(ctx context.Context, username string, password string) (*User, error)
147
148
149 ListUsers(ctx context.Context) ([]string, error)
150 }
151
152 type httpAuthUserAPI struct {
153 client httpClient
154 }
155
156 type authUserAPIAction struct {
157 verb string
158 username string
159 user *User
160 }
161
162 type authUserAPIList struct{}
163
164 func (list *authUserAPIList) HTTPRequest(ep url.URL) *http.Request {
165 u := v2AuthURL(ep, "users", "")
166 req, _ := http.NewRequest("GET", u.String(), nil)
167 req.Header.Set("Content-Type", "application/json")
168 return req
169 }
170
171 func (l *authUserAPIAction) HTTPRequest(ep url.URL) *http.Request {
172 u := v2AuthURL(ep, "users", l.username)
173 if l.user == nil {
174 req, _ := http.NewRequest(l.verb, u.String(), nil)
175 return req
176 }
177 b, err := json.Marshal(l.user)
178 if err != nil {
179 panic(err)
180 }
181 body := bytes.NewReader(b)
182 req, _ := http.NewRequest(l.verb, u.String(), body)
183 req.Header.Set("Content-Type", "application/json")
184 return req
185 }
186
187 func (u *httpAuthUserAPI) ListUsers(ctx context.Context) ([]string, error) {
188 resp, body, err := u.client.Do(ctx, &authUserAPIList{})
189 if err != nil {
190 return nil, err
191 }
192 if err = assertStatusCode(resp.StatusCode, http.StatusOK); err != nil {
193 var sec authError
194 err = json.Unmarshal(body, &sec)
195 if err != nil {
196 return nil, err
197 }
198 return nil, sec
199 }
200
201 var userList struct {
202 Users []userListEntry `json:"users"`
203 }
204
205 if err = json.Unmarshal(body, &userList); err != nil {
206 return nil, err
207 }
208
209 ret := make([]string, 0, len(userList.Users))
210 for _, u := range userList.Users {
211 ret = append(ret, u.User)
212 }
213 return ret, nil
214 }
215
216 func (u *httpAuthUserAPI) AddUser(ctx context.Context, username string, password string) error {
217 user := &User{
218 User: username,
219 Password: password,
220 }
221 return u.addRemoveUser(ctx, &authUserAPIAction{
222 verb: "PUT",
223 username: username,
224 user: user,
225 })
226 }
227
228 func (u *httpAuthUserAPI) RemoveUser(ctx context.Context, username string) error {
229 return u.addRemoveUser(ctx, &authUserAPIAction{
230 verb: "DELETE",
231 username: username,
232 })
233 }
234
235 func (u *httpAuthUserAPI) addRemoveUser(ctx context.Context, req *authUserAPIAction) error {
236 resp, body, err := u.client.Do(ctx, req)
237 if err != nil {
238 return err
239 }
240 if err = assertStatusCode(resp.StatusCode, http.StatusOK, http.StatusCreated); err != nil {
241 var sec authError
242 err = json.Unmarshal(body, &sec)
243 if err != nil {
244 return err
245 }
246 return sec
247 }
248 return nil
249 }
250
251 func (u *httpAuthUserAPI) GetUser(ctx context.Context, username string) (*User, error) {
252 return u.modUser(ctx, &authUserAPIAction{
253 verb: "GET",
254 username: username,
255 })
256 }
257
258 func (u *httpAuthUserAPI) GrantUser(ctx context.Context, username string, roles []string) (*User, error) {
259 user := &User{
260 User: username,
261 Grant: roles,
262 }
263 return u.modUser(ctx, &authUserAPIAction{
264 verb: "PUT",
265 username: username,
266 user: user,
267 })
268 }
269
270 func (u *httpAuthUserAPI) RevokeUser(ctx context.Context, username string, roles []string) (*User, error) {
271 user := &User{
272 User: username,
273 Revoke: roles,
274 }
275 return u.modUser(ctx, &authUserAPIAction{
276 verb: "PUT",
277 username: username,
278 user: user,
279 })
280 }
281
282 func (u *httpAuthUserAPI) ChangePassword(ctx context.Context, username string, password string) (*User, error) {
283 user := &User{
284 User: username,
285 Password: password,
286 }
287 return u.modUser(ctx, &authUserAPIAction{
288 verb: "PUT",
289 username: username,
290 user: user,
291 })
292 }
293
294 func (u *httpAuthUserAPI) modUser(ctx context.Context, req *authUserAPIAction) (*User, error) {
295 resp, body, err := u.client.Do(ctx, req)
296 if err != nil {
297 return nil, err
298 }
299 if err = assertStatusCode(resp.StatusCode, http.StatusOK); err != nil {
300 var sec authError
301 err = json.Unmarshal(body, &sec)
302 if err != nil {
303 return nil, err
304 }
305 return nil, sec
306 }
307 var user User
308 if err = json.Unmarshal(body, &user); err != nil {
309 var userR UserRoles
310 if urerr := json.Unmarshal(body, &userR); urerr != nil {
311 return nil, err
312 }
313 user.User = userR.User
314 for _, r := range userR.Roles {
315 user.Roles = append(user.Roles, r.Role)
316 }
317 }
318 return &user, nil
319 }
320
View as plain text