mirror of https://github.com/goharbor/harbor.git
203 lines
7.2 KiB
Go
203 lines
7.2 KiB
Go
// Copyright Project Harbor Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package user
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/goharbor/harbor/src/common"
|
|
commonmodels "github.com/goharbor/harbor/src/common/models"
|
|
"github.com/goharbor/harbor/src/common/security"
|
|
"github.com/goharbor/harbor/src/common/security/local"
|
|
"github.com/goharbor/harbor/src/lib"
|
|
"github.com/goharbor/harbor/src/lib/errors"
|
|
"github.com/goharbor/harbor/src/lib/q"
|
|
"github.com/goharbor/harbor/src/pkg/member"
|
|
"github.com/goharbor/harbor/src/pkg/oidc"
|
|
"github.com/goharbor/harbor/src/pkg/user"
|
|
"github.com/goharbor/harbor/src/pkg/user/models"
|
|
)
|
|
|
|
var (
|
|
// Ctl is a global user controller instance
|
|
Ctl = NewController()
|
|
)
|
|
|
|
// Controller provides functions to support API/middleware for user management and query
|
|
type Controller interface {
|
|
// SetSysAdmin ...
|
|
SetSysAdmin(ctx context.Context, id int, adminFlag bool) error
|
|
// VerifyPassword ...
|
|
VerifyPassword(ctx context.Context, usernameOrEmail string, password string) (bool, error)
|
|
// UpdatePassword ...
|
|
UpdatePassword(ctx context.Context, id int, password string) error
|
|
// List ...
|
|
List(ctx context.Context, query *q.Query, options ...models.Option) ([]*commonmodels.User, error)
|
|
// Create ...
|
|
Create(ctx context.Context, u *commonmodels.User) (int, error)
|
|
// Count ...
|
|
Count(ctx context.Context, query *q.Query) (int64, error)
|
|
// Get ...
|
|
Get(ctx context.Context, id int, opt *Option) (*commonmodels.User, error)
|
|
// GetByName gets the user model by username, it only supports getting the basic and does not support opt
|
|
GetByName(ctx context.Context, username string) (*commonmodels.User, error)
|
|
// GetBySubIss gets the user model by subject and issuer, the result will contain the basic user model and does not support opt
|
|
GetBySubIss(ctx context.Context, sub, iss string) (*commonmodels.User, error)
|
|
// Delete ...
|
|
Delete(ctx context.Context, id int) error
|
|
// UpdateProfile update the profile based on the ID and data in the model in parm, only a subset of attributes in the model
|
|
// will be update, see the implementation of manager.
|
|
UpdateProfile(ctx context.Context, u *commonmodels.User, cols ...string) error
|
|
// SetCliSecret sets the OIDC CLI secret for a user
|
|
SetCliSecret(ctx context.Context, id int, secret string) error
|
|
// UpdateOIDCMeta updates the OIDC metadata of a user, if the cols are not provided, by default the field of token and secret will be updated
|
|
UpdateOIDCMeta(ctx context.Context, ou *commonmodels.OIDCUser, cols ...string) error
|
|
// OnboardOIDCUser inserts the record for basic user info and the oidc metadata
|
|
// if the onboard process is successful the input parm of user model will be populated with user id
|
|
OnboardOIDCUser(ctx context.Context, u *commonmodels.User) error
|
|
}
|
|
|
|
// NewController ...
|
|
func NewController() Controller {
|
|
return &controller{
|
|
mgr: user.New(),
|
|
oidcMetaMgr: oidc.NewMetaMgr(),
|
|
memberMgr: member.Mgr,
|
|
}
|
|
}
|
|
|
|
// Option option for getting User info
|
|
type Option struct {
|
|
WithOIDCInfo bool
|
|
}
|
|
|
|
type controller struct {
|
|
mgr user.Manager
|
|
oidcMetaMgr oidc.MetaManager
|
|
memberMgr member.Manager
|
|
}
|
|
|
|
func (c *controller) UpdateOIDCMeta(ctx context.Context, ou *commonmodels.OIDCUser, cols ...string) error {
|
|
defaultCols := []string{"secret", "token"}
|
|
if cols == nil || len(cols) == 0 {
|
|
cols = defaultCols
|
|
}
|
|
return c.oidcMetaMgr.Update(ctx, ou, cols...)
|
|
}
|
|
|
|
func (c *controller) OnboardOIDCUser(ctx context.Context, u *commonmodels.User) error {
|
|
if u == nil {
|
|
return errors.BadRequestError(nil).WithMessage("user model is nil")
|
|
}
|
|
if u.OIDCUserMeta == nil {
|
|
return errors.BadRequestError(nil).WithMessage("OIDC meta of the user model is empty")
|
|
}
|
|
uid, err := c.mgr.Create(ctx, u)
|
|
if err != nil {
|
|
return errors.Wrap(err, "failed to create user record")
|
|
}
|
|
u.UserID = uid
|
|
u.OIDCUserMeta.UserID = uid
|
|
|
|
mid, err2 := c.oidcMetaMgr.Create(ctx, u.OIDCUserMeta)
|
|
if err2 != nil {
|
|
return errors.Wrap(err2, "failed to create OIDC metadata record")
|
|
}
|
|
u.OIDCUserMeta.ID = int64(mid)
|
|
return nil
|
|
}
|
|
|
|
func (c *controller) GetBySubIss(ctx context.Context, sub, iss string) (*commonmodels.User, error) {
|
|
oidcMeta, err := c.oidcMetaMgr.GetBySubIss(ctx, sub, iss)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return c.Get(ctx, oidcMeta.UserID, nil)
|
|
}
|
|
|
|
func (c *controller) GetByName(ctx context.Context, username string) (*commonmodels.User, error) {
|
|
return c.mgr.GetByName(ctx, username)
|
|
}
|
|
|
|
func (c *controller) SetCliSecret(ctx context.Context, id int, secret string) error {
|
|
return c.oidcMetaMgr.SetCliSecretByUserID(ctx, id, secret)
|
|
}
|
|
|
|
func (c *controller) Create(ctx context.Context, u *commonmodels.User) (int, error) {
|
|
return c.mgr.Create(ctx, u)
|
|
}
|
|
|
|
func (c *controller) UpdateProfile(ctx context.Context, u *commonmodels.User, cols ...string) error {
|
|
return c.mgr.UpdateProfile(ctx, u, cols...)
|
|
}
|
|
|
|
func (c *controller) Get(ctx context.Context, id int, opt *Option) (*commonmodels.User, error) {
|
|
u, err := c.mgr.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
sctx, _ := security.FromContext(ctx)
|
|
lsc, ok := sctx.(*local.SecurityContext)
|
|
if ok && lsc.User() != nil && lsc.User().UserID == id {
|
|
u.AdminRoleInAuth = lsc.User().AdminRoleInAuth
|
|
}
|
|
if opt != nil && opt.WithOIDCInfo {
|
|
oidcMeta, err := c.oidcMetaMgr.GetByUserID(ctx, id)
|
|
if err != nil {
|
|
return nil, errors.UnknownError(err)
|
|
}
|
|
u.OIDCUserMeta = oidcMeta
|
|
}
|
|
return u, nil
|
|
}
|
|
|
|
func (c *controller) Count(ctx context.Context, query *q.Query) (int64, error) {
|
|
return c.mgr.Count(ctx, query)
|
|
}
|
|
|
|
func (c *controller) Delete(ctx context.Context, id int) error {
|
|
// cleanup project member with the user
|
|
if err := c.memberMgr.DeleteMemberByUserID(ctx, id); err != nil {
|
|
return errors.UnknownError(err).WithMessage("delete user failed, user id: %v, cannot delete project user member, error:%v", id, err)
|
|
}
|
|
// delete oidc metadata under the user
|
|
if lib.GetAuthMode(ctx) == common.OIDCAuth {
|
|
if err := c.oidcMetaMgr.DeleteByUserID(ctx, id); err != nil {
|
|
return errors.UnknownError(err).WithMessage("delete user failed, user id: %v, cannot delete oidc user, error:%v", id, err)
|
|
}
|
|
}
|
|
return c.mgr.Delete(ctx, id)
|
|
}
|
|
|
|
func (c *controller) List(ctx context.Context, query *q.Query, options ...models.Option) ([]*commonmodels.User, error) {
|
|
return c.mgr.List(ctx, query, options...)
|
|
}
|
|
|
|
func (c *controller) UpdatePassword(ctx context.Context, id int, password string) error {
|
|
return c.mgr.UpdatePassword(ctx, id, password)
|
|
}
|
|
|
|
func (c *controller) VerifyPassword(ctx context.Context, usernameOrEmail, password string) (bool, error) {
|
|
rec, err := c.mgr.MatchLocalPassword(ctx, usernameOrEmail, password)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return rec != nil, nil
|
|
}
|
|
|
|
func (c *controller) SetSysAdmin(ctx context.Context, id int, adminFlag bool) error {
|
|
return c.mgr.SetSysAdminFlag(ctx, id, adminFlag)
|
|
}
|