1// Copyright 2020-2021 InfluxData, Inc. All rights reserved. 2// Use of this source code is governed by MIT 3// license that can be found in the LICENSE file. 4 5package api 6 7import ( 8 "context" 9 "encoding/base64" 10 "fmt" 11 nethttp "net/http" 12 "net/http/cookiejar" 13 "sync" 14 15 "github.com/influxdata/influxdb-client-go/v2/api/http" 16 "github.com/influxdata/influxdb-client-go/v2/domain" 17 "golang.org/x/net/publicsuffix" 18) 19 20// UsersAPI provides methods for managing users in a InfluxDB server 21type UsersAPI interface { 22 // GetUsers returns all users 23 GetUsers(ctx context.Context) (*[]domain.User, error) 24 // FindUserByID returns user with userID 25 FindUserByID(ctx context.Context, userID string) (*domain.User, error) 26 // FindUserByName returns user with name userName 27 FindUserByName(ctx context.Context, userName string) (*domain.User, error) 28 // CreateUser creates new user 29 CreateUser(ctx context.Context, user *domain.User) (*domain.User, error) 30 // CreateUserWithName creates new user with userName 31 CreateUserWithName(ctx context.Context, userName string) (*domain.User, error) 32 // UpdateUser updates user 33 UpdateUser(ctx context.Context, user *domain.User) (*domain.User, error) 34 // UpdateUserPassword sets password for an user 35 UpdateUserPassword(ctx context.Context, user *domain.User, password string) error 36 // UpdateUserPasswordWithID sets password for an user with userID 37 UpdateUserPasswordWithID(ctx context.Context, userID string, password string) error 38 // DeleteUserWithID deletes an user with userID 39 DeleteUserWithID(ctx context.Context, userID string) error 40 // DeleteUser deletes an user 41 DeleteUser(ctx context.Context, user *domain.User) error 42 // Me returns actual user 43 Me(ctx context.Context) (*domain.User, error) 44 // MeUpdatePassword set password of actual user 45 MeUpdatePassword(ctx context.Context, oldPassword, newPassword string) error 46 // SignIn exchanges username and password credentials to establish an authenticated session with the InfluxDB server. The Client's authentication token is then ignored, it can be empty. 47 SignIn(ctx context.Context, username, password string) error 48 // SignOut signs out previously signed in user 49 SignOut(ctx context.Context) error 50} 51 52// usersAPI implements UsersAPI 53type usersAPI struct { 54 apiClient *domain.ClientWithResponses 55 httpService http.Service 56 httpClient *nethttp.Client 57 deleteCookieJar bool 58 lock sync.Mutex 59} 60 61// NewUsersAPI creates new instance of UsersAPI 62func NewUsersAPI(apiClient *domain.ClientWithResponses, httpService http.Service, httpClient *nethttp.Client) UsersAPI { 63 return &usersAPI{ 64 apiClient: apiClient, 65 httpService: httpService, 66 httpClient: httpClient, 67 } 68} 69 70func (u *usersAPI) GetUsers(ctx context.Context) (*[]domain.User, error) { 71 params := &domain.GetUsersParams{} 72 response, err := u.apiClient.GetUsersWithResponse(ctx, params) 73 if err != nil { 74 return nil, err 75 } 76 if response.JSONDefault != nil { 77 return nil, domain.ErrorToHTTPError(response.JSONDefault, response.StatusCode()) 78 } 79 return response.JSON200.Users, nil 80} 81 82func (u *usersAPI) FindUserByID(ctx context.Context, userID string) (*domain.User, error) { 83 params := &domain.GetUsersIDParams{} 84 response, err := u.apiClient.GetUsersIDWithResponse(ctx, userID, params) 85 if err != nil { 86 return nil, err 87 } 88 if response.JSONDefault != nil { 89 return nil, domain.ErrorToHTTPError(response.JSONDefault, response.StatusCode()) 90 } 91 return response.JSON200, nil 92} 93 94func (u *usersAPI) FindUserByName(ctx context.Context, userName string) (*domain.User, error) { 95 users, err := u.GetUsers(ctx) 96 if err != nil { 97 return nil, err 98 } 99 var user *domain.User 100 for _, u := range *users { 101 if u.Name == userName { 102 user = &u 103 break 104 } 105 } 106 if user == nil { 107 return nil, fmt.Errorf("user '%s' not found", userName) 108 } 109 return user, nil 110} 111 112func (u *usersAPI) CreateUserWithName(ctx context.Context, userName string) (*domain.User, error) { 113 user := &domain.User{Name: userName} 114 return u.CreateUser(ctx, user) 115} 116 117func (u *usersAPI) CreateUser(ctx context.Context, user *domain.User) (*domain.User, error) { 118 params := &domain.PostUsersParams{} 119 response, err := u.apiClient.PostUsersWithResponse(ctx, params, domain.PostUsersJSONRequestBody(*user)) 120 if err != nil { 121 return nil, err 122 } 123 if response.JSONDefault != nil { 124 return nil, domain.ErrorToHTTPError(response.JSONDefault, response.StatusCode()) 125 } 126 return response.JSON201, nil 127} 128 129func (u *usersAPI) UpdateUser(ctx context.Context, user *domain.User) (*domain.User, error) { 130 params := &domain.PatchUsersIDParams{} 131 response, err := u.apiClient.PatchUsersIDWithResponse(ctx, *user.Id, params, domain.PatchUsersIDJSONRequestBody(*user)) 132 if err != nil { 133 return nil, err 134 } 135 if response.JSONDefault != nil { 136 return nil, domain.ErrorToHTTPError(response.JSONDefault, response.StatusCode()) 137 } 138 return response.JSON200, nil 139} 140 141func (u *usersAPI) UpdateUserPassword(ctx context.Context, user *domain.User, password string) error { 142 return u.UpdateUserPasswordWithID(ctx, *user.Id, password) 143} 144 145func (u *usersAPI) UpdateUserPasswordWithID(ctx context.Context, userID string, password string) error { 146 params := &domain.PostUsersIDPasswordParams{} 147 body := &domain.PasswordResetBody{Password: password} 148 response, err := u.apiClient.PostUsersIDPasswordWithResponse(ctx, userID, params, domain.PostUsersIDPasswordJSONRequestBody(*body)) 149 if err != nil { 150 return err 151 } 152 if response.JSONDefault != nil { 153 return domain.ErrorToHTTPError(response.JSONDefault, response.StatusCode()) 154 } 155 return nil 156} 157 158func (u *usersAPI) DeleteUser(ctx context.Context, user *domain.User) error { 159 return u.DeleteUserWithID(ctx, *user.Id) 160} 161 162func (u *usersAPI) DeleteUserWithID(ctx context.Context, userID string) error { 163 params := &domain.DeleteUsersIDParams{} 164 response, err := u.apiClient.DeleteUsersIDWithResponse(ctx, userID, params) 165 if err != nil { 166 return err 167 } 168 if response.JSONDefault != nil { 169 return domain.ErrorToHTTPError(response.JSONDefault, response.StatusCode()) 170 } 171 return nil 172} 173 174func (u *usersAPI) Me(ctx context.Context) (*domain.User, error) { 175 params := &domain.GetMeParams{} 176 response, err := u.apiClient.GetMeWithResponse(ctx, params) 177 if err != nil { 178 return nil, err 179 } 180 if response.JSONDefault != nil { 181 return nil, domain.ErrorToHTTPError(response.JSONDefault, response.StatusCode()) 182 } 183 return response.JSON200, nil 184} 185 186func (u *usersAPI) MeUpdatePassword(ctx context.Context, oldPassword, newPassword string) error { 187 u.lock.Lock() 188 defer u.lock.Unlock() 189 me, err := u.Me(ctx) 190 if err != nil { 191 return err 192 } 193 creds := base64.StdEncoding.EncodeToString([]byte(me.Name + ":" + oldPassword)) 194 auth := u.httpService.Authorization() 195 defer u.httpService.SetAuthorization(auth) 196 u.httpService.SetAuthorization("Basic " + creds) 197 params := &domain.PutMePasswordParams{} 198 body := &domain.PasswordResetBody{Password: newPassword} 199 response, err := u.apiClient.PutMePasswordWithResponse(ctx, params, domain.PutMePasswordJSONRequestBody(*body)) 200 if err != nil { 201 return err 202 } 203 if response.JSONDefault != nil { 204 return domain.ErrorToHTTPError(response.JSONDefault, response.StatusCode()) 205 } 206 return nil 207} 208 209func (u *usersAPI) SignIn(ctx context.Context, username, password string) error { 210 u.lock.Lock() 211 defer u.lock.Unlock() 212 if u.httpClient.Jar == nil { 213 jar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List}) 214 if err != nil { 215 return err 216 } 217 u.httpClient.Jar = jar 218 u.deleteCookieJar = true 219 } 220 creds := base64.StdEncoding.EncodeToString([]byte(username + ":" + password)) 221 u.httpService.SetAuthorization("Basic " + creds) 222 defer u.httpService.SetAuthorization("") 223 resp, err := u.apiClient.PostSigninWithResponse(ctx, &domain.PostSigninParams{}) 224 if err != nil { 225 return err 226 } 227 if resp.JSONDefault != nil { 228 return domain.ErrorToHTTPError(resp.JSONDefault, resp.StatusCode()) 229 } 230 if resp.JSON401 != nil { 231 return domain.ErrorToHTTPError(resp.JSON401, resp.StatusCode()) 232 } 233 if resp.JSON403 != nil { 234 return domain.ErrorToHTTPError(resp.JSON403, resp.StatusCode()) 235 } 236 return nil 237} 238 239func (u *usersAPI) SignOut(ctx context.Context) error { 240 u.lock.Lock() 241 defer u.lock.Unlock() 242 resp, err := u.apiClient.PostSignoutWithResponse(ctx, &domain.PostSignoutParams{}) 243 if err != nil { 244 return err 245 } 246 if resp.JSONDefault != nil { 247 return domain.ErrorToHTTPError(resp.JSONDefault, resp.StatusCode()) 248 } 249 if resp.JSON401 != nil { 250 return domain.ErrorToHTTPError(resp.JSON401, resp.StatusCode()) 251 } 252 if u.deleteCookieJar { 253 u.httpClient.Jar = nil 254 } 255 return nil 256} 257