mirror of
https://github.com/goharbor/harbor.git
synced 2025-01-03 14:37:44 +01:00
Merge pull request #7463 from reasonerjt/regen-cli-secret
Provide API to generate CLI secret
This commit is contained in:
commit
5cd3c039a9
@ -940,6 +940,44 @@ 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.
|
||||
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.
|
||||
parameters:
|
||||
- name: user_id
|
||||
in: path
|
||||
type: integer
|
||||
format: int
|
||||
required: true
|
||||
description: User ID
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
'200':
|
||||
description: The secret is successfully generated.
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
secret:
|
||||
type: string
|
||||
description: The new secret
|
||||
'400':
|
||||
description: Invalid user ID. Or user is not onboarded via OIDC authentication.
|
||||
'401':
|
||||
description: User need to log in first.
|
||||
'403':
|
||||
description: Non-admin user can only generate the cli secret of himself.
|
||||
'404':
|
||||
description: User ID does not exist.
|
||||
'412':
|
||||
description: The auth mode of the system is not "oidc_auth", or the user is not onboarded via OIDC AuthN.
|
||||
'500':
|
||||
description: Unexpected internal errors.
|
||||
|
||||
/repositories:
|
||||
get:
|
||||
summary: Get repositories accompany with relevant project and repo name.
|
||||
|
@ -38,7 +38,7 @@ CREATE TABLE oidc_user (
|
||||
UNIQUE (subiss)
|
||||
);
|
||||
|
||||
CREATE TRIGGER odic_user_update_time_at_modtime BEFORE UPDATE ON oidc_user FOR EACH ROW EXECUTE PROCEDURE update_update_time_at_column();
|
||||
CREATE TRIGGER oidc_user_update_time_at_modtime BEFORE UPDATE ON oidc_user FOR EACH ROW EXECUTE PROCEDURE update_update_time_at_column();
|
||||
|
||||
/*add master role*/
|
||||
INSERT INTO role (role_code, name) VALUES ('DRWS', 'master');
|
||||
|
@ -92,10 +92,17 @@ func GetOIDCUserByUserID(userID int) (*models.OIDCUser, error) {
|
||||
return &oidcUsers[0], nil
|
||||
}
|
||||
|
||||
// UpdateOIDCUser ...
|
||||
// UpdateOIDCUser updates the OIDCUser based on the input parm, only the column "secret" and "token" can be updated
|
||||
func UpdateOIDCUser(oidcUser *models.OIDCUser) error {
|
||||
oidcUser.UpdateTime = time.Now()
|
||||
_, err := GetOrmer().Update(oidcUser)
|
||||
cols := []string{"secret", "token"}
|
||||
_, err := GetOrmer().Update(oidcUser, cols...)
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateOIDCUserSecret updates the secret of the OIDC User. The secret in the input parm should be encrypted before
|
||||
// calling this func
|
||||
func UpdateOIDCUserSecret(oidcUser *models.OIDCUser) error {
|
||||
_, err := GetOrmer().Update(oidcUser, "secret")
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -80,15 +80,13 @@ func TestOIDCUserMetaDaoMethods(t *testing.T) {
|
||||
ID: ou111.ID,
|
||||
UserID: ou111.UserID,
|
||||
SubIss: "newSub",
|
||||
Secret: "newSecret",
|
||||
}
|
||||
require.Nil(t, UpdateOIDCUser(meta3))
|
||||
oidcUser1Update, err := GetOIDCUserByID(ou111.ID)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, "newSub", oidcUser1Update.SubIss)
|
||||
|
||||
user, err := GetUserBySubIss("new", "Sub")
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, "user111", user.Username)
|
||||
assert.Equal(t, "QWE123123RT1", oidcUser1Update.SubIss)
|
||||
assert.Equal(t, "newSecret", oidcUser1Update.Secret)
|
||||
|
||||
// clear data
|
||||
defer func() {
|
||||
|
@ -38,6 +38,7 @@ type UserAPI struct {
|
||||
SelfRegistration bool
|
||||
IsAdmin bool
|
||||
AuthMode string
|
||||
secretKey string
|
||||
}
|
||||
|
||||
type passwordReq struct {
|
||||
@ -50,6 +51,10 @@ type userSearch struct {
|
||||
Username string `json:"username"`
|
||||
}
|
||||
|
||||
type secretResp struct {
|
||||
Secret string `json:"secret"`
|
||||
}
|
||||
|
||||
// Prepare validates the URL and parms
|
||||
func (ua *UserAPI) Prepare() {
|
||||
ua.BaseController.Prepare()
|
||||
@ -61,6 +66,15 @@ func (ua *UserAPI) Prepare() {
|
||||
}
|
||||
|
||||
ua.AuthMode = mode
|
||||
if mode == common.OIDCAuth {
|
||||
key, err := config.SecretKey()
|
||||
if err != nil {
|
||||
log.Errorf("failed to get secret key: %v", err)
|
||||
ua.SendInternalServerError(fmt.Errorf("failed to get secret key: %v", err))
|
||||
return
|
||||
}
|
||||
ua.secretKey = key
|
||||
}
|
||||
|
||||
self, err := config.SelfRegistration()
|
||||
if err != nil {
|
||||
@ -475,17 +489,53 @@ func (ua *UserAPI) ListUserPermissions() {
|
||||
return
|
||||
}
|
||||
|
||||
func (ua *UserAPI) getOIDCUserInfo() (*models.OIDCUser, error) {
|
||||
key, err := config.SecretKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// GenCLISecret generates a new CLI secret and replace the old one
|
||||
func (ua *UserAPI) GenCLISecret() {
|
||||
if ua.AuthMode != common.OIDCAuth {
|
||||
ua.SendPreconditionFailedError(errors.New("the auth mode has to be oidc auth"))
|
||||
return
|
||||
}
|
||||
if ua.userID != ua.currentUserID && !ua.IsAdmin {
|
||||
ua.SendForbiddenError(errors.New(""))
|
||||
return
|
||||
}
|
||||
oidcData, err := dao.GetOIDCUserByUserID(ua.userID)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to get OIDC User meta for user, id: %d, error: %v", ua.userID, err)
|
||||
ua.SendInternalServerError(errors.New("failed to get OIDC meta data for user"))
|
||||
return
|
||||
}
|
||||
if oidcData == nil {
|
||||
log.Errorf("User is not onboarded via OIDC AuthN, user id: %d", ua.userID)
|
||||
ua.SendPreconditionFailedError(errors.New("user is not onboarded via OIDC AuthN"))
|
||||
return
|
||||
}
|
||||
|
||||
sec := utils.GenerateRandomString()
|
||||
encSec, err := utils.ReversibleEncrypt(sec, ua.secretKey)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to encrypt secret, error: %v", err)
|
||||
ua.SendInternalServerError(errors.New("failed to encrypt secret"))
|
||||
return
|
||||
}
|
||||
oidcData.Secret = encSec
|
||||
err = dao.UpdateOIDCUserSecret(oidcData)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to update secret in DB, error: %v", err)
|
||||
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) {
|
||||
o, err := dao.GetOIDCUserByUserID(ua.userID)
|
||||
if err != nil || o == nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(o.Secret) > 0 {
|
||||
p, err := utils.ReversibleDecrypt(o.Secret, key)
|
||||
p, err := utils.ReversibleDecrypt(o.Secret, ua.secretKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -53,6 +53,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/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")
|
||||
|
Loading…
Reference in New Issue
Block a user