Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit89b7f3f

Browse files
BrunoQuaresmakylecarbs
authored andcommitted
feat: Add update user password endpoint (#1310)
1 parent67a0c74 commit89b7f3f

File tree

12 files changed

+160
-26
lines changed

12 files changed

+160
-26
lines changed

‎coderd/coderd.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,10 @@ func New(options *Options) (http.Handler, func()) {
240240
r.Get("/",api.userByName)
241241
r.Put("/profile",api.putUserProfile)
242242
r.Put("/suspend",api.putUserSuspend)
243+
r.Route("/password",func(r chi.Router) {
244+
r.Use(httpmw.WithRBACObject(rbac.ResourceUserPasswordRole))
245+
r.Put("/",authorize(api.putUserPassword,rbac.ActionUpdate))
246+
})
243247
r.Get("/organizations",api.organizationsByUser)
244248
r.Post("/organizations",api.postOrganizationsByUser)
245249
// These roles apply to the site wide permissions.

‎coderd/coderdtest/coderdtest.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -174,21 +174,22 @@ func NewProvisionerDaemon(t *testing.T, client *codersdk.Client) io.Closer {
174174
returncloser
175175
}
176176

177+
varFirstUserParams= codersdk.CreateFirstUserRequest{
178+
Email:"testuser@coder.com",
179+
Username:"testuser",
180+
Password:"testpass",
181+
OrganizationName:"testorg",
182+
}
183+
177184
// CreateFirstUser creates a user with preset credentials and authenticates
178185
// with the passed in codersdk client.
179186
funcCreateFirstUser(t*testing.T,client*codersdk.Client) codersdk.CreateFirstUserResponse {
180-
req:= codersdk.CreateFirstUserRequest{
181-
Email:"testuser@coder.com",
182-
Username:"testuser",
183-
Password:"testpass",
184-
OrganizationName:"testorg",
185-
}
186-
resp,err:=client.CreateFirstUser(context.Background(),req)
187+
resp,err:=client.CreateFirstUser(context.Background(),FirstUserParams)
187188
require.NoError(t,err)
188189

189190
login,err:=client.LoginWithPassword(context.Background(), codersdk.LoginWithPasswordRequest{
190-
Email:req.Email,
191-
Password:req.Password,
191+
Email:FirstUserParams.Email,
192+
Password:FirstUserParams.Password,
192193
})
193194
require.NoError(t,err)
194195
client.SessionToken=login.SessionToken

‎coderd/database/databasefake/databasefake.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,6 +1314,21 @@ func (q *fakeQuerier) UpdateUserStatus(_ context.Context, arg database.UpdateUse
13141314
return database.User{},sql.ErrNoRows
13151315
}
13161316

1317+
func (q*fakeQuerier)UpdateUserHashedPassword(_ context.Context,arg database.UpdateUserHashedPasswordParams)error {
1318+
q.mutex.Lock()
1319+
deferq.mutex.Unlock()
1320+
1321+
fori,user:=rangeq.users {
1322+
ifuser.ID!=arg.ID {
1323+
continue
1324+
}
1325+
user.HashedPassword=arg.HashedPassword
1326+
q.users[i]=user
1327+
returnnil
1328+
}
1329+
returnsql.ErrNoRows
1330+
}
1331+
13171332
func (q*fakeQuerier)InsertWorkspace(_ context.Context,arg database.InsertWorkspaceParams) (database.Workspace,error) {
13181333
q.mutex.Lock()
13191334
deferq.mutex.Unlock()

‎coderd/database/querier.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/queries.sql.go

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/queries/users.sql

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,14 @@ WHERE
5959
id= @id
6060
RETURNING*;
6161

62+
-- name: UpdateUserHashedPassword :exec
63+
UPDATE
64+
users
65+
SET
66+
hashed_password= $2
67+
WHERE
68+
id= $1;
69+
6270
-- name: GetUsers :many
6371
SELECT
6472
*
@@ -133,4 +141,4 @@ FROM
133141
LEFT JOIN organization_members
134142
ON id= user_id
135143
WHERE
136-
id= @user_id;
144+
id= @user_id;

‎coderd/httpmw/userparam.go

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,6 @@ func ExtractUserParam(db database.Store) func(http.Handler) http.Handler {
7676
}
7777
}
7878

79-
apiKey:=APIKey(r)
80-
ifapiKey.UserID!=user.ID {
81-
httpapi.Write(rw,http.StatusBadRequest, httpapi.Response{
82-
Message:"getting non-personal users isn't supported yet",
83-
})
84-
return
85-
}
86-
8779
ctx:=context.WithValue(r.Context(),userParamContextKey{},user)
8880
next.ServeHTTP(rw,r.WithContext(ctx))
8981
})

‎coderd/rbac/object.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ var (
2424
Type:"user_role",
2525
}
2626

27+
ResourceUserPasswordRole=Object{
28+
Type:"user_password",
29+
}
30+
2731
// ResourceWildcard represents all resource types
2832
ResourceWildcard=Object{
2933
Type:WildcardSymbol,

‎coderd/users.go

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,36 @@ func (api *api) putUserSuspend(rw http.ResponseWriter, r *http.Request) {
360360
httpapi.Write(rw,http.StatusOK,convertUser(suspendedUser,organizations))
361361
}
362362

363+
func (api*api)putUserPassword(rw http.ResponseWriter,r*http.Request) {
364+
var (
365+
user=httpmw.UserParam(r)
366+
params codersdk.UpdateUserPasswordRequest
367+
)
368+
if!httpapi.Read(rw,r,&params) {
369+
return
370+
}
371+
372+
hashedPassword,err:=userpassword.Hash(params.Password)
373+
iferr!=nil {
374+
httpapi.Write(rw,http.StatusInternalServerError, httpapi.Response{
375+
Message:fmt.Sprintf("hash password: %s",err.Error()),
376+
})
377+
return
378+
}
379+
err=api.Database.UpdateUserHashedPassword(r.Context(), database.UpdateUserHashedPasswordParams{
380+
ID:user.ID,
381+
HashedPassword: []byte(hashedPassword),
382+
})
383+
iferr!=nil {
384+
httpapi.Write(rw,http.StatusInternalServerError, httpapi.Response{
385+
Message:fmt.Sprintf("put user password: %s",err.Error()),
386+
})
387+
return
388+
}
389+
390+
httpapi.Write(rw,http.StatusNoContent,nil)
391+
}
392+
363393
func (api*api)userRoles(rw http.ResponseWriter,r*http.Request) {
364394
user:=httpmw.UserParam(r)
365395

@@ -577,7 +607,6 @@ func (api *api) postLogin(rw http.ResponseWriter, r *http.Request) {
577607
}
578608

579609
// If the user doesn't exist, it will be a default struct.
580-
581610
equal,err:=userpassword.Compare(string(user.HashedPassword),loginWithPassword.Password)
582611
iferr!=nil {
583612
httpapi.Write(rw,http.StatusInternalServerError, httpapi.Response{

‎coderd/users_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,44 @@ func TestUpdateUserProfile(t *testing.T) {
287287
})
288288
}
289289

290+
funcTestUpdateUserPassword(t*testing.T) {
291+
t.Parallel()
292+
293+
t.Run("MemberCantUpdateAdminPassword",func(t*testing.T) {
294+
t.Parallel()
295+
client:=coderdtest.New(t,nil)
296+
admin:=coderdtest.CreateFirstUser(t,client)
297+
member:=coderdtest.CreateAnotherUser(t,client,admin.OrganizationID)
298+
err:=member.UpdateUserPassword(context.Background(),admin.UserID, codersdk.UpdateUserPasswordRequest{
299+
Password:"newpassword",
300+
})
301+
require.Error(t,err,"member should not be able to update admin password")
302+
})
303+
304+
t.Run("AdminCanUpdateMemberPassword",func(t*testing.T) {
305+
t.Parallel()
306+
client:=coderdtest.New(t,nil)
307+
admin:=coderdtest.CreateFirstUser(t,client)
308+
member,err:=client.CreateUser(context.Background(), codersdk.CreateUserRequest{
309+
Email:"coder@coder.com",
310+
Username:"coder",
311+
Password:"password",
312+
OrganizationID:admin.OrganizationID,
313+
})
314+
require.NoError(t,err,"create member")
315+
err=client.UpdateUserPassword(context.Background(),member.ID, codersdk.UpdateUserPasswordRequest{
316+
Password:"newpassword",
317+
})
318+
require.NoError(t,err,"admin should be able to update member password")
319+
// Check if the member can login using the new password
320+
_,err=client.LoginWithPassword(context.Background(), codersdk.LoginWithPasswordRequest{
321+
Email:"coder@coder.com",
322+
Password:"newpassword",
323+
})
324+
require.NoError(t,err,"member should login successfully with the new password")
325+
})
326+
}
327+
290328
funcTestGrantRoles(t*testing.T) {
291329
t.Parallel()
292330
t.Run("UpdateIncorrectRoles",func(t*testing.T) {

‎codersdk/users.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ type UpdateUserProfileRequest struct {
7272
Usernamestring`json:"username" validate:"required,username"`
7373
}
7474

75+
typeUpdateUserPasswordRequeststruct {
76+
Passwordstring`json:"password" validate:"required"`
77+
}
78+
7579
typeUpdateRolesstruct {
7680
Roles []string`json:"roles" validate:"required"`
7781
}
@@ -181,6 +185,20 @@ func (c *Client) SuspendUser(ctx context.Context, userID uuid.UUID) (User, error
181185
returnuser,json.NewDecoder(res.Body).Decode(&user)
182186
}
183187

188+
// UpdateUserPassword updates a user password.
189+
// It calls PUT /users/{user}/password
190+
func (c*Client)UpdateUserPassword(ctx context.Context,userID uuid.UUID,reqUpdateUserPasswordRequest)error {
191+
res,err:=c.request(ctx,http.MethodPut,fmt.Sprintf("/api/v2/users/%s/password",uuidOrMe(userID)),req)
192+
iferr!=nil {
193+
returnerr
194+
}
195+
deferres.Body.Close()
196+
ifres.StatusCode!=http.StatusNoContent {
197+
returnreadBodyAsError(res)
198+
}
199+
returnnil
200+
}
201+
184202
// UpdateUserRoles grants the userID the specified roles.
185203
// Include ALL roles the user has.
186204
func (c*Client)UpdateUserRoles(ctx context.Context,userID uuid.UUID,reqUpdateRoles) (User,error) {

‎site/src/api/typesGenerated.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export interface AgentGitSSHKey {
1212
readonlyprivate_key:string
1313
}
1414

15-
// From codersdk/users.go:105:6
15+
// From codersdk/users.go:109:6
1616
exportinterfaceAuthMethods{
1717
readonlypassword:boolean
1818
readonlygithub:boolean
@@ -44,7 +44,7 @@ export interface CreateFirstUserResponse {
4444
readonlyorganization_id:string
4545
}
4646

47-
// From codersdk/users.go:100:6
47+
// From codersdk/users.go:104:6
4848
exportinterfaceCreateOrganizationRequest{
4949
readonlyname:string
5050
}
@@ -101,7 +101,7 @@ export interface CreateWorkspaceRequest {
101101
readonlyparameter_values:CreateParameterRequest[]
102102
}
103103

104-
// From codersdk/users.go:96:6
104+
// From codersdk/users.go:100:6
105105
exportinterfaceGenerateAPIKeyResponse{
106106
readonlykey:string
107107
}
@@ -119,13 +119,13 @@ export interface GoogleInstanceIdentityToken {
119119
readonlyjson_web_token:string
120120
}
121121

122-
// From codersdk/users.go:85:6
122+
// From codersdk/users.go:89:6
123123
exportinterfaceLoginWithPasswordRequest{
124124
readonlyemail:string
125125
readonlypassword:string
126126
}
127127

128-
// From codersdk/users.go:91:6
128+
// From codersdk/users.go:95:6
129129
exportinterfaceLoginWithPasswordResponse{
130130
readonlysession_token:string
131131
}
@@ -255,11 +255,16 @@ export interface UpdateActiveTemplateVersion {
255255
readonlyid:string
256256
}
257257

258-
// From codersdk/users.go:75:6
258+
// From codersdk/users.go:79:6
259259
exportinterfaceUpdateRoles{
260260
readonlyroles:string[]
261261
}
262262

263+
// From codersdk/users.go:75:6
264+
exportinterfaceUpdateUserPasswordRequest{
265+
readonlypassword:string
266+
}
267+
263268
// From codersdk/users.go:70:6
264269
exportinterfaceUpdateUserProfileRequest{
265270
readonlyemail:string
@@ -291,7 +296,7 @@ export interface User {
291296
readonlyorganization_ids:string[]
292297
}
293298

294-
// From codersdk/users.go:79:6
299+
// From codersdk/users.go:83:6
295300
exportinterfaceUserRoles{
296301
readonlyroles:string[]
297302
readonlyorganization_roles:Record<string,string[]>

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp