Unverified Commit 40d80f82 authored by Wang Yan's avatar Wang Yan Committed by GitHub
Browse files

Merge pull request #9368 from reasonerjt/set-cli-secret-api

API for user to set the CLI secret
parents d7375992 53a13e16
......@@ -959,13 +959,13 @@ paths:
description: User ID does not exist.
'500':
description: Unexpected internal errors.
'/users/{user_id}/gen_cli_secret':
post:
summary: Generate new CLI secret for a user.
'/users/{user_id}/cli_secret':
put:
summary: Set CLI secret for a user.
description: |
This endpoint let user generate a new CLI secret for himself. This API only works when auth mode is set to 'OIDC'.
Once this API returns with successful status, the old secret will be invalid, as there will be only one CLI secret
for a user. The new secret will be returned in the response.
for a user.
parameters:
- name: user_id
in: path
......@@ -973,19 +973,23 @@ paths:
format: int
required: true
description: User ID
tags:
- Products
responses:
'200':
description: The secret is successfully generated.
- name: input_secret
in: body
description: JSON object that includes the new secret
required: true
schema:
type: object
properties:
secret:
type: string
description: The new secret
tags:
- Products
responses:
'200':
description: The secret is successfully updated
'400':
description: Invalid user ID. Or user is not onboarded via OIDC authentication.
description: Invalid user ID. Or user is not onboarded via OIDC authentication. Or the secret does not meet the standard.
'401':
description: User need to log in first.
'403':
......
......@@ -52,7 +52,7 @@ type userSearch struct {
Username string `json:"username"`
}
type secretResp struct {
type secretReq struct {
Secret string `json:"secret"`
}
......@@ -405,8 +405,8 @@ func (ua *UserAPI) ChangePassword() {
return
}
if len(req.NewPassword) == 0 {
ua.SendBadRequestError(errors.New("empty new_password"))
if err := validateSecret(req.NewPassword); err != nil {
ua.SendBadRequestError(err)
return
}
......@@ -512,8 +512,8 @@ func (ua *UserAPI) ListUserPermissions() {
return
}
// GenCLISecret generates a new CLI secret and replace the old one
func (ua *UserAPI) GenCLISecret() {
// SetCLISecret handles request PUT /api/users/:id/cli_secret to update the CLI secret of the user
func (ua *UserAPI) SetCLISecret() {
if ua.AuthMode != common.OIDCAuth {
ua.SendPreconditionFailedError(errors.New("the auth mode has to be oidc auth"))
return
......@@ -534,8 +534,17 @@ func (ua *UserAPI) GenCLISecret() {
return
}
sec := utils.GenerateRandomString()
encSec, err := utils.ReversibleEncrypt(sec, ua.secretKey)
s := &secretReq{}
if err := ua.DecodeJSONReq(s); err != nil {
ua.SendBadRequestError(err)
return
}
if err := validateSecret(s.Secret); err != nil {
ua.SendBadRequestError(err)
return
}
encSec, err := utils.ReversibleEncrypt(s.Secret, ua.secretKey)
if err != nil {
log.Errorf("Failed to encrypt secret, error: %v", err)
ua.SendInternalServerError(errors.New("failed to encrypt secret"))
......@@ -548,8 +557,6 @@ func (ua *UserAPI) GenCLISecret() {
ua.SendInternalServerError(errors.New("failed to update secret in DB"))
return
}
ua.Data["json"] = secretResp{sec}
ua.ServeJSON()
}
func (ua *UserAPI) getOIDCUserInfo() (*models.OIDCUser, error) {
......@@ -588,12 +595,24 @@ func validate(user models.User) error {
if utils.IsContainIllegalChar(user.Username, []string{",", "~", "#", "$", "%"}) {
return fmt.Errorf("username contains illegal characters")
}
if utils.IsIllegalLength(user.Password, 8, 20) {
return fmt.Errorf("password with illegal length")
if err := validateSecret(user.Password); err != nil {
return err
}
return commonValidate(user)
}
func validateSecret(in string) error {
hasLower := regexp.MustCompile(`[a-z]`)
hasUpper := regexp.MustCompile(`[A-Z]`)
hasNumber := regexp.MustCompile(`[0-9]`)
if len(in) >= 8 && hasLower.MatchString(in) && hasUpper.MatchString(in) && hasNumber.MatchString(in) {
return nil
}
return errors.New("the password or secret must longer than 8 chars with at least 1 uppercase letter, 1 lowercase letter and 1 number")
}
// commonValidate validates email, realname, comment information when user register or change their profile
func commonValidate(user models.User) error {
......
......@@ -380,8 +380,8 @@ func buildChangeUserPasswordURL(id int) string {
func TestUsersUpdatePassword(t *testing.T) {
fmt.Println("Testing Update User Password")
oldPassword := "old_password"
newPassword := "new_password"
oldPassword := "old_Passw0rd"
newPassword := "new_Passw0rd"
user01 := models.User{
Username: "user01_for_testing_change_password",
......@@ -515,7 +515,7 @@ func TestUsersUpdatePassword(t *testing.T) {
method: http.MethodPut,
url: buildChangeUserPasswordURL(user01.UserID),
bodyJSON: &passwordReq{
NewPassword: "another_new_password",
NewPassword: "another_new_Passw0rd",
},
credential: admin,
},
......@@ -642,3 +642,13 @@ func TestUsersCurrentPermissions(t *testing.T) {
assert.Nil(err)
assert.Equal(int(403), httpStatusCode, "httpStatusCode should be 403")
}
func TestValidateSecret(t *testing.T) {
assert.NotNil(t, validateSecret(""))
assert.NotNil(t, validateSecret("12345678"))
assert.NotNil(t, validateSecret("passw0rd"))
assert.NotNil(t, validateSecret("PASSW0RD"))
assert.NotNil(t, validateSecret("Sh0rt"))
assert.Nil(t, validateSecret("Passw0rd"))
assert.Nil(t, validateSecret("Thisis1Valid_password"))
}
......@@ -52,7 +52,7 @@ func initRouters() {
beego.Router("/api/users/:id([0-9]+)/password", &api.UserAPI{}, "put:ChangePassword")
beego.Router("/api/users/:id/permissions", &api.UserAPI{}, "get:ListUserPermissions")
beego.Router("/api/users/:id/sysadmin", &api.UserAPI{}, "put:ToggleUserAdminRole")
beego.Router("/api/users/:id/gen_cli_secret", &api.UserAPI{}, "post:GenCLISecret")
beego.Router("/api/users/:id/cli_secret", &api.UserAPI{}, "put:SetCLISecret")
beego.Router("/api/usergroups/?:ugid([0-9]+)", &api.UserGroupAPI{})
beego.Router("/api/ldap/ping", &api.LdapAPI{}, "post:Ping")
beego.Router("/api/ldap/users/search", &api.LdapAPI{}, "get:Search")
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment