mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-29 05:35:43 +01:00
fix: use ctx from http request for middlewares (#15523)
1. Use ctx from http request for the readonly middleware. 2. Refactor the AuthenticateHelper to let it get orm from ctx of the http request. 3. Change to use ctx from http request for oidc and authproxy http handlers. Signed-off-by: He Weiwei <hweiwei@vmware.com>
This commit is contained in:
parent
383635e970
commit
06f2414d1c
@ -1,13 +1,27 @@
|
|||||||
|
// 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 gc
|
package gc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/goharbor/harbor/src/lib/config"
|
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/controller/quota"
|
"github.com/goharbor/harbor/src/controller/quota"
|
||||||
"github.com/goharbor/harbor/src/jobservice/job"
|
"github.com/goharbor/harbor/src/jobservice/job"
|
||||||
|
"github.com/goharbor/harbor/src/lib/config"
|
||||||
"github.com/goharbor/harbor/src/lib/log"
|
"github.com/goharbor/harbor/src/lib/log"
|
||||||
"github.com/goharbor/harbor/src/lib/orm"
|
"github.com/goharbor/harbor/src/lib/orm"
|
||||||
"github.com/goharbor/harbor/src/pkg/scheduler"
|
"github.com/goharbor/harbor/src/pkg/scheduler"
|
||||||
@ -30,7 +44,7 @@ func gcCallback(ctx context.Context, p string) error {
|
|||||||
if err := json.Unmarshal([]byte(p), param); err != nil {
|
if err := json.Unmarshal([]byte(p), param); err != nil {
|
||||||
return fmt.Errorf("failed to unmarshal the param: %v", err)
|
return fmt.Errorf("failed to unmarshal the param: %v", err)
|
||||||
}
|
}
|
||||||
_, err := Ctl.Start(orm.Context(), *param, task.ExecutionTriggerSchedule)
|
_, err := Ctl.Start(ctx, *param, task.ExecutionTriggerSchedule)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ package member
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/common"
|
"github.com/goharbor/harbor/src/common"
|
||||||
"github.com/goharbor/harbor/src/core/auth"
|
"github.com/goharbor/harbor/src/core/auth"
|
||||||
"github.com/goharbor/harbor/src/lib/errors"
|
"github.com/goharbor/harbor/src/lib/errors"
|
||||||
@ -142,7 +143,7 @@ func (c *controller) Create(ctx context.Context, projectNameOrID interface{}, re
|
|||||||
if u != nil {
|
if u != nil {
|
||||||
userID = u.UserID
|
userID = u.UserID
|
||||||
} else {
|
} else {
|
||||||
userID, err = auth.SearchAndOnBoardUser(req.MemberUser.Username)
|
userID, err = auth.SearchAndOnBoardUser(ctx, req.MemberUser.Username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@ -160,7 +161,7 @@ func (c *controller) Create(ctx context.Context, projectNameOrID interface{}, re
|
|||||||
member.EntityType = common.GroupMember
|
member.EntityType = common.GroupMember
|
||||||
} else {
|
} else {
|
||||||
// If groupname provided, use the provided groupname to name this group
|
// If groupname provided, use the provided groupname to name this group
|
||||||
groupID, err := auth.SearchAndOnBoardGroup(req.MemberGroup.LdapGroupDN, req.MemberGroup.GroupName)
|
groupID, err := auth.SearchAndOnBoardGroup(ctx, req.MemberGroup.LdapGroupDN, req.MemberGroup.GroupName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@ -174,7 +175,7 @@ func (c *controller) Create(ctx context.Context, projectNameOrID interface{}, re
|
|||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
if len(ugs) == 0 {
|
if len(ugs) == 0 {
|
||||||
groupID, err := auth.SearchAndOnBoardGroup(req.MemberGroup.GroupName, "")
|
groupID, err := auth.SearchAndOnBoardGroup(ctx, req.MemberGroup.GroupName, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ package usergroup
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/common"
|
"github.com/goharbor/harbor/src/common"
|
||||||
"github.com/goharbor/harbor/src/core/auth"
|
"github.com/goharbor/harbor/src/core/auth"
|
||||||
"github.com/goharbor/harbor/src/lib/errors"
|
"github.com/goharbor/harbor/src/lib/errors"
|
||||||
@ -87,7 +88,7 @@ func (c *controller) Update(ctx context.Context, id int, groupName string) error
|
|||||||
|
|
||||||
func (c *controller) Create(ctx context.Context, group model.UserGroup) (int, error) {
|
func (c *controller) Create(ctx context.Context, group model.UserGroup) (int, error) {
|
||||||
if group.GroupType == common.LDAPGroupType {
|
if group.GroupType == common.LDAPGroupType {
|
||||||
ldapGroup, err := auth.SearchGroup(group.LdapGroupDN)
|
ldapGroup, err := auth.SearchGroup(ctx, group.LdapGroupDN)
|
||||||
if err == ldap.ErrNotFound || ldapGroup == nil {
|
if err == ldap.ErrNotFound || ldapGroup == nil {
|
||||||
return 0, errors.BadRequestError(nil).WithMessage("LDAP Group DN is not found: DN:%v", group.LdapGroupDN)
|
return 0, errors.BadRequestError(nil).WithMessage("LDAP Group DN is not found: DN:%v", group.LdapGroupDN)
|
||||||
}
|
}
|
||||||
|
@ -14,11 +14,12 @@
|
|||||||
package auth
|
package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goharbor/harbor/src/pkg/usergroup/model"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/common/models"
|
"github.com/goharbor/harbor/src/common/models"
|
||||||
|
"github.com/goharbor/harbor/src/pkg/usergroup/model"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -45,7 +46,7 @@ func TestLock(t *testing.T) {
|
|||||||
func TestDefaultAuthenticate(t *testing.T) {
|
func TestDefaultAuthenticate(t *testing.T) {
|
||||||
authHelper := DefaultAuthenticateHelper{}
|
authHelper := DefaultAuthenticateHelper{}
|
||||||
m := models.AuthModel{}
|
m := models.AuthModel{}
|
||||||
user, err := authHelper.Authenticate(m)
|
user, err := authHelper.Authenticate(context.TODO(), m)
|
||||||
if user != nil || err == nil {
|
if user != nil || err == nil {
|
||||||
t.Fatal("Default implementation should return nil")
|
t.Fatal("Default implementation should return nil")
|
||||||
}
|
}
|
||||||
@ -54,7 +55,7 @@ func TestDefaultAuthenticate(t *testing.T) {
|
|||||||
func TestDefaultOnBoardUser(t *testing.T) {
|
func TestDefaultOnBoardUser(t *testing.T) {
|
||||||
user := &models.User{}
|
user := &models.User{}
|
||||||
authHelper := DefaultAuthenticateHelper{}
|
authHelper := DefaultAuthenticateHelper{}
|
||||||
err := authHelper.OnBoardUser(user)
|
err := authHelper.OnBoardUser(context.TODO(), user)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("Default implementation should return error")
|
t.Fatal("Default implementation should return error")
|
||||||
}
|
}
|
||||||
@ -62,17 +63,17 @@ func TestDefaultOnBoardUser(t *testing.T) {
|
|||||||
|
|
||||||
func TestDefaultMethods(t *testing.T) {
|
func TestDefaultMethods(t *testing.T) {
|
||||||
authHelper := DefaultAuthenticateHelper{}
|
authHelper := DefaultAuthenticateHelper{}
|
||||||
_, err := authHelper.SearchUser("sample")
|
_, err := authHelper.SearchUser(context.TODO(), "sample")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("Default implementation should return error")
|
t.Fatal("Default implementation should return error")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = authHelper.SearchGroup("sample")
|
_, err = authHelper.SearchGroup(context.TODO(), "sample")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("Default implementation should return error")
|
t.Fatal("Default implementation should return error")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = authHelper.OnBoardGroup(&model.UserGroup{}, "sample")
|
err = authHelper.OnBoardGroup(context.TODO(), &model.UserGroup{}, "sample")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("Default implementation should return error")
|
t.Fatal("Default implementation should return error")
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,6 @@ import (
|
|||||||
"github.com/goharbor/harbor/src/lib/config"
|
"github.com/goharbor/harbor/src/lib/config"
|
||||||
libErrors "github.com/goharbor/harbor/src/lib/errors"
|
libErrors "github.com/goharbor/harbor/src/lib/errors"
|
||||||
"github.com/goharbor/harbor/src/lib/log"
|
"github.com/goharbor/harbor/src/lib/log"
|
||||||
"github.com/goharbor/harbor/src/lib/orm"
|
|
||||||
"github.com/goharbor/harbor/src/pkg/user"
|
"github.com/goharbor/harbor/src/pkg/user"
|
||||||
"github.com/goharbor/harbor/src/pkg/usergroup/model"
|
"github.com/goharbor/harbor/src/pkg/usergroup/model"
|
||||||
)
|
)
|
||||||
@ -69,19 +68,19 @@ func NewErrAuth(msg string) ErrAuth {
|
|||||||
type AuthenticateHelper interface {
|
type AuthenticateHelper interface {
|
||||||
// Authenticate authenticate the user based on data in m. Only when the error returned is an instance
|
// Authenticate authenticate the user based on data in m. Only when the error returned is an instance
|
||||||
// of ErrAuth, it will be considered a bad credentials, other errors will be treated as server side error.
|
// of ErrAuth, it will be considered a bad credentials, other errors will be treated as server side error.
|
||||||
Authenticate(m models.AuthModel) (*models.User, error)
|
Authenticate(ctx context.Context, m models.AuthModel) (*models.User, error)
|
||||||
// OnBoardUser will check if a user exists in user table, if not insert the user and
|
// OnBoardUser will check if a user exists in user table, if not insert the user and
|
||||||
// put the id in the pointer of user model, if it does exist, fill in the user model based
|
// put the id in the pointer of user model, if it does exist, fill in the user model based
|
||||||
// on the data record of the user
|
// on the data record of the user
|
||||||
OnBoardUser(u *models.User) error
|
OnBoardUser(ctx context.Context, u *models.User) error
|
||||||
// OnBoardGroup Create a group in harbor DB, if altGroupName is not empty, take the altGroupName as groupName in harbor DB.
|
// OnBoardGroup Create a group in harbor DB, if altGroupName is not empty, take the altGroupName as groupName in harbor DB.
|
||||||
OnBoardGroup(g *model.UserGroup, altGroupName string) error
|
OnBoardGroup(ctx context.Context, g *model.UserGroup, altGroupName string) error
|
||||||
// SearchUser Get user information from account repository
|
// SearchUser Get user information from account repository
|
||||||
SearchUser(username string) (*models.User, error)
|
SearchUser(ctx context.Context, username string) (*models.User, error)
|
||||||
// SearchGroup Search a group based on specific authentication
|
// SearchGroup Search a group based on specific authentication
|
||||||
SearchGroup(groupDN string) (*model.UserGroup, error)
|
SearchGroup(ctx context.Context, groupDN string) (*model.UserGroup, error)
|
||||||
// PostAuthenticate Update user information after authenticate, such as Onboard or sync info etc
|
// PostAuthenticate Update user information after authenticate, such as Onboard or sync info etc
|
||||||
PostAuthenticate(u *models.User) error
|
PostAuthenticate(ctx context.Context, u *models.User) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultAuthenticateHelper - default AuthenticateHelper implementation
|
// DefaultAuthenticateHelper - default AuthenticateHelper implementation
|
||||||
@ -89,35 +88,35 @@ type DefaultAuthenticateHelper struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Authenticate ...
|
// Authenticate ...
|
||||||
func (d *DefaultAuthenticateHelper) Authenticate(m models.AuthModel) (*models.User, error) {
|
func (d *DefaultAuthenticateHelper) Authenticate(ctx context.Context, m models.AuthModel) (*models.User, error) {
|
||||||
return nil, ErrNotSupported
|
return nil, ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnBoardUser will check if a user exists in user table, if not insert the user and
|
// OnBoardUser will check if a user exists in user table, if not insert the user and
|
||||||
// put the id in the pointer of user model, if it does exist, fill in the user model based
|
// put the id in the pointer of user model, if it does exist, fill in the user model based
|
||||||
// on the data record of the user
|
// on the data record of the user
|
||||||
func (d *DefaultAuthenticateHelper) OnBoardUser(u *models.User) error {
|
func (d *DefaultAuthenticateHelper) OnBoardUser(ctx context.Context, u *models.User) error {
|
||||||
return ErrNotSupported
|
return ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchUser - Get user information from account repository
|
// SearchUser - Get user information from account repository
|
||||||
func (d *DefaultAuthenticateHelper) SearchUser(username string) (*models.User, error) {
|
func (d *DefaultAuthenticateHelper) SearchUser(ctx context.Context, username string) (*models.User, error) {
|
||||||
log.Errorf("Not support searching user, username: %s", username)
|
log.Errorf("Not support searching user, username: %s", username)
|
||||||
return nil, libErrors.NotFoundError(ErrNotSupported).WithMessage("%s not found", username)
|
return nil, libErrors.NotFoundError(ErrNotSupported).WithMessage("%s not found", username)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PostAuthenticate - Update user information after authenticate, such as OnBoard or sync info etc
|
// PostAuthenticate - Update user information after authenticate, such as OnBoard or sync info etc
|
||||||
func (d *DefaultAuthenticateHelper) PostAuthenticate(u *models.User) error {
|
func (d *DefaultAuthenticateHelper) PostAuthenticate(ctx context.Context, u *models.User) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnBoardGroup - OnBoardGroup, it will set the ID of the user group, if altGroupName is not empty, take the altGroupName as groupName in harbor DB.
|
// OnBoardGroup - OnBoardGroup, it will set the ID of the user group, if altGroupName is not empty, take the altGroupName as groupName in harbor DB.
|
||||||
func (d *DefaultAuthenticateHelper) OnBoardGroup(u *model.UserGroup, altGroupName string) error {
|
func (d *DefaultAuthenticateHelper) OnBoardGroup(ctx context.Context, u *model.UserGroup, altGroupName string) error {
|
||||||
return ErrNotSupported
|
return ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchGroup - Search ldap group by group key, groupKey is the unique attribute of group in authenticator, for LDAP, the key is group DN
|
// SearchGroup - Search ldap group by group key, groupKey is the unique attribute of group in authenticator, for LDAP, the key is group DN
|
||||||
func (d *DefaultAuthenticateHelper) SearchGroup(groupKey string) (*model.UserGroup, error) {
|
func (d *DefaultAuthenticateHelper) SearchGroup(ctx context.Context, groupKey string) (*model.UserGroup, error) {
|
||||||
log.Errorf("Not support searching group, group key: %s", groupKey)
|
log.Errorf("Not support searching group, group key: %s", groupKey)
|
||||||
return nil, libErrors.NotFoundError(ErrNotSupported).WithMessage("%s not found", groupKey)
|
return nil, libErrors.NotFoundError(ErrNotSupported).WithMessage("%s not found", groupKey)
|
||||||
}
|
}
|
||||||
@ -135,8 +134,7 @@ func Register(name string, h AuthenticateHelper) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Login authenticates user credentials based on setting.
|
// Login authenticates user credentials based on setting.
|
||||||
func Login(m models.AuthModel) (*models.User, error) {
|
func Login(ctx context.Context, m models.AuthModel) (*models.User, error) {
|
||||||
ctx := orm.Context()
|
|
||||||
authMode, err := config.AuthMode(ctx)
|
authMode, err := config.AuthMode(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -154,7 +152,7 @@ func Login(m models.AuthModel) (*models.User, error) {
|
|||||||
log.Debugf("%s is locked due to login failure, login failed", m.Principal)
|
log.Debugf("%s is locked due to login failure, login failed", m.Principal)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
user, err := authenticator.Authenticate(m)
|
user, err := authenticator.Authenticate(ctx, m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if _, ok = err.(ErrAuth); ok {
|
if _, ok = err.(ErrAuth); ok {
|
||||||
log.Debugf("Login failed, locking %s, and sleep for %v", m.Principal, frozenTime)
|
log.Debugf("Login failed, locking %s, and sleep for %v", m.Principal, frozenTime)
|
||||||
@ -163,12 +161,12 @@ func Login(m models.AuthModel) (*models.User, error) {
|
|||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
err = authenticator.PostAuthenticate(user)
|
err = authenticator.PostAuthenticate(ctx, user)
|
||||||
return user, err
|
return user, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getHelper() (AuthenticateHelper, error) {
|
func getHelper(ctx context.Context) (AuthenticateHelper, error) {
|
||||||
authMode, err := config.AuthMode(orm.Context())
|
authMode, err := config.AuthMode(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -181,52 +179,52 @@ func getHelper() (AuthenticateHelper, error) {
|
|||||||
|
|
||||||
// OnBoardUser will check if a user exists in user table, if not insert the user and
|
// OnBoardUser will check if a user exists in user table, if not insert the user and
|
||||||
// put the id in the pointer of user model, if it does exist, return the user's profile.
|
// put the id in the pointer of user model, if it does exist, return the user's profile.
|
||||||
func OnBoardUser(user *models.User) error {
|
func OnBoardUser(ctx context.Context, user *models.User) error {
|
||||||
log.Debugf("OnBoardUser, user %+v", user)
|
log.Debugf("OnBoardUser, user %+v", user)
|
||||||
helper, err := getHelper()
|
helper, err := getHelper(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return helper.OnBoardUser(user)
|
return helper.OnBoardUser(ctx, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchUser --
|
// SearchUser --
|
||||||
func SearchUser(username string) (*models.User, error) {
|
func SearchUser(ctx context.Context, username string) (*models.User, error) {
|
||||||
helper, err := getHelper()
|
helper, err := getHelper(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return helper.SearchUser(username)
|
return helper.SearchUser(ctx, username)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnBoardGroup - Create a user group in harbor db, if altGroupName is not empty, take the altGroupName as groupName in harbor DB
|
// OnBoardGroup - Create a user group in harbor db, if altGroupName is not empty, take the altGroupName as groupName in harbor DB
|
||||||
func OnBoardGroup(userGroup *model.UserGroup, altGroupName string) error {
|
func OnBoardGroup(ctx context.Context, userGroup *model.UserGroup, altGroupName string) error {
|
||||||
helper, err := getHelper()
|
helper, err := getHelper(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return helper.OnBoardGroup(userGroup, altGroupName)
|
return helper.OnBoardGroup(ctx, userGroup, altGroupName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchGroup -- Search group in authenticator, groupKey is the unique attribute of group in authenticator, for LDAP, the key is group DN
|
// SearchGroup -- Search group in authenticator, groupKey is the unique attribute of group in authenticator, for LDAP, the key is group DN
|
||||||
func SearchGroup(groupKey string) (*model.UserGroup, error) {
|
func SearchGroup(ctx context.Context, groupKey string) (*model.UserGroup, error) {
|
||||||
helper, err := getHelper()
|
helper, err := getHelper(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return helper.SearchGroup(groupKey)
|
return helper.SearchGroup(ctx, groupKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchAndOnBoardUser ... Search user and OnBoard user, if user exist, return the ID of current user.
|
// SearchAndOnBoardUser ... Search user and OnBoard user, if user exist, return the ID of current user.
|
||||||
func SearchAndOnBoardUser(username string) (int, error) {
|
func SearchAndOnBoardUser(ctx context.Context, username string) (int, error) {
|
||||||
user, err := SearchUser(username)
|
user, err := SearchUser(ctx, username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
if user == nil {
|
if user == nil {
|
||||||
return 0, libErrors.NotFoundError(nil).WithMessage(fmt.Sprintf("user %s is not found", username))
|
return 0, libErrors.NotFoundError(nil).WithMessage(fmt.Sprintf("user %s is not found", username))
|
||||||
}
|
}
|
||||||
err = OnBoardUser(user)
|
err = OnBoardUser(ctx, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@ -234,8 +232,8 @@ func SearchAndOnBoardUser(username string) (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SearchAndOnBoardGroup ... if altGroupName is not empty, take the altGroupName as groupName in harbor DB
|
// SearchAndOnBoardGroup ... if altGroupName is not empty, take the altGroupName as groupName in harbor DB
|
||||||
func SearchAndOnBoardGroup(groupKey, altGroupName string) (int, error) {
|
func SearchAndOnBoardGroup(ctx context.Context, groupKey, altGroupName string) (int, error) {
|
||||||
userGroup, err := SearchGroup(groupKey)
|
userGroup, err := SearchGroup(ctx, groupKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@ -243,18 +241,18 @@ func SearchAndOnBoardGroup(groupKey, altGroupName string) (int, error) {
|
|||||||
return 0, ErrorGroupNotExist
|
return 0, ErrorGroupNotExist
|
||||||
}
|
}
|
||||||
if userGroup != nil {
|
if userGroup != nil {
|
||||||
err = OnBoardGroup(userGroup, altGroupName)
|
err = OnBoardGroup(ctx, userGroup, altGroupName)
|
||||||
}
|
}
|
||||||
return userGroup.ID, err
|
return userGroup.ID, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// PostAuthenticate -
|
// PostAuthenticate -
|
||||||
func PostAuthenticate(u *models.User) error {
|
func PostAuthenticate(ctx context.Context, u *models.User) error {
|
||||||
helper, err := getHelper()
|
helper, err := getHelper(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return helper.PostAuthenticate(u)
|
return helper.PostAuthenticate(ctx, u)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsSuperUser checks if the user is super user(conventionally id == 1) of Harbor
|
// IsSuperUser checks if the user is super user(conventionally id == 1) of Harbor
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
package authproxy
|
package authproxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@ -26,20 +27,18 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/jobservice/logger"
|
|
||||||
"github.com/goharbor/harbor/src/lib/config"
|
|
||||||
cfgModels "github.com/goharbor/harbor/src/lib/config/models"
|
|
||||||
harborErrors "github.com/goharbor/harbor/src/lib/errors"
|
|
||||||
"github.com/goharbor/harbor/src/lib/orm"
|
|
||||||
"github.com/goharbor/harbor/src/pkg/usergroup/model"
|
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/common"
|
"github.com/goharbor/harbor/src/common"
|
||||||
"github.com/goharbor/harbor/src/common/models"
|
"github.com/goharbor/harbor/src/common/models"
|
||||||
"github.com/goharbor/harbor/src/controller/usergroup"
|
"github.com/goharbor/harbor/src/controller/usergroup"
|
||||||
"github.com/goharbor/harbor/src/core/auth"
|
"github.com/goharbor/harbor/src/core/auth"
|
||||||
|
"github.com/goharbor/harbor/src/jobservice/logger"
|
||||||
|
"github.com/goharbor/harbor/src/lib/config"
|
||||||
|
cfgModels "github.com/goharbor/harbor/src/lib/config/models"
|
||||||
|
harborErrors "github.com/goharbor/harbor/src/lib/errors"
|
||||||
"github.com/goharbor/harbor/src/lib/log"
|
"github.com/goharbor/harbor/src/lib/log"
|
||||||
"github.com/goharbor/harbor/src/pkg/authproxy"
|
"github.com/goharbor/harbor/src/pkg/authproxy"
|
||||||
"github.com/goharbor/harbor/src/pkg/user"
|
"github.com/goharbor/harbor/src/pkg/user"
|
||||||
|
"github.com/goharbor/harbor/src/pkg/usergroup/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
const refreshDuration = 2 * time.Second
|
const refreshDuration = 2 * time.Second
|
||||||
@ -67,8 +66,8 @@ type session struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Authenticate issues http POST request to Endpoint if it returns 200 the authentication is considered success.
|
// Authenticate issues http POST request to Endpoint if it returns 200 the authentication is considered success.
|
||||||
func (a *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
|
func (a *Auth) Authenticate(ctx context.Context, m models.AuthModel) (*models.User, error) {
|
||||||
err := a.ensure()
|
err := a.ensure(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if a.Endpoint == "" {
|
if a.Endpoint == "" {
|
||||||
return nil, fmt.Errorf("failed to initialize HTTP Auth Proxy Authenticator, error: %v", err)
|
return nil, fmt.Errorf("failed to initialize HTTP Auth Proxy Authenticator, error: %v", err)
|
||||||
@ -96,7 +95,7 @@ func (a *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, auth.NewErrAuth(fmt.Sprintf("failed to read session %v", err))
|
return nil, auth.NewErrAuth(fmt.Sprintf("failed to read session %v", err))
|
||||||
}
|
}
|
||||||
user, err := a.tokenReview(s.SessionID)
|
user, err := a.tokenReview(ctx, s.SessionID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, auth.NewErrAuth(fmt.Sprintf("failed to do token review, error: %v", err))
|
return nil, auth.NewErrAuth(fmt.Sprintf("failed to do token review, error: %v", err))
|
||||||
}
|
}
|
||||||
@ -112,8 +111,8 @@ func (a *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Auth) tokenReview(sessionID string) (*models.User, error) {
|
func (a *Auth) tokenReview(ctx context.Context, sessionID string) (*models.User, error) {
|
||||||
httpAuthProxySetting, err := config.HTTPAuthProxySetting(orm.Context())
|
httpAuthProxySetting, err := config.HTTPAuthProxySetting(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -129,26 +128,26 @@ func (a *Auth) tokenReview(sessionID string) (*models.User, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// VerifyToken reviews the token to generate the user model
|
// VerifyToken reviews the token to generate the user model
|
||||||
func (a *Auth) VerifyToken(token string) (*models.User, error) {
|
func (a *Auth) VerifyToken(ctx context.Context, token string) (*models.User, error) {
|
||||||
if err := a.ensure(); err != nil {
|
if err := a.ensure(ctx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return a.tokenReview(token)
|
return a.tokenReview(ctx, token)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnBoardUser delegates to dao pkg to insert/update data in DB.
|
// OnBoardUser delegates to dao pkg to insert/update data in DB.
|
||||||
func (a *Auth) OnBoardUser(u *models.User) error {
|
func (a *Auth) OnBoardUser(ctx context.Context, u *models.User) error {
|
||||||
return a.userMgr.Onboard(orm.Context(), u)
|
return a.userMgr.Onboard(ctx, u)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PostAuthenticate generates the user model and on board the user.
|
// PostAuthenticate generates the user model and on board the user.
|
||||||
func (a *Auth) PostAuthenticate(u *models.User) error {
|
func (a *Auth) PostAuthenticate(ctx context.Context, u *models.User) error {
|
||||||
_, err := a.userMgr.GetByName(orm.Context(), u.Username)
|
_, err := a.userMgr.GetByName(ctx, u.Username)
|
||||||
if harborErrors.IsNotFoundErr(err) {
|
if harborErrors.IsNotFoundErr(err) {
|
||||||
if err2 := a.fillInModel(u); err2 != nil {
|
if err2 := a.fillInModel(u); err2 != nil {
|
||||||
return err2
|
return err2
|
||||||
}
|
}
|
||||||
return a.OnBoardUser(u)
|
return a.OnBoardUser(ctx, u)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -159,8 +158,8 @@ func (a *Auth) PostAuthenticate(u *models.User) error {
|
|||||||
// SearchUser returns nil as authproxy does not have such capability.
|
// SearchUser returns nil as authproxy does not have such capability.
|
||||||
// When SkipSearch is set it always return the default model,
|
// When SkipSearch is set it always return the default model,
|
||||||
// the username will be switch to lowercase if it's configured as case-insensitive
|
// the username will be switch to lowercase if it's configured as case-insensitive
|
||||||
func (a *Auth) SearchUser(username string) (*models.User, error) {
|
func (a *Auth) SearchUser(ctx context.Context, username string) (*models.User, error) {
|
||||||
err := a.ensure()
|
err := a.ensure(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warningf("Failed to refresh configuration for HTTP Auth Proxy Authenticator, error: %v, the default settings will be used", err)
|
log.Warningf("Failed to refresh configuration for HTTP Auth Proxy Authenticator, error: %v, the default settings will be used", err)
|
||||||
}
|
}
|
||||||
@ -175,8 +174,8 @@ func (a *Auth) SearchUser(username string) (*models.User, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SearchGroup search group exist in the authentication provider, for HTTP auth, if SkipSearch is true, it assume this group exist in authentication provider.
|
// SearchGroup search group exist in the authentication provider, for HTTP auth, if SkipSearch is true, it assume this group exist in authentication provider.
|
||||||
func (a *Auth) SearchGroup(groupKey string) (*model.UserGroup, error) {
|
func (a *Auth) SearchGroup(ctx context.Context, groupKey string) (*model.UserGroup, error) {
|
||||||
err := a.ensure()
|
err := a.ensure(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warningf("Failed to refresh configuration for HTTP Auth Proxy Authenticator, error: %v, the default settings will be used", err)
|
log.Warningf("Failed to refresh configuration for HTTP Auth Proxy Authenticator, error: %v, the default settings will be used", err)
|
||||||
}
|
}
|
||||||
@ -192,13 +191,13 @@ func (a *Auth) SearchGroup(groupKey string) (*model.UserGroup, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OnBoardGroup create user group entity in Harbor DB, altGroupName is not used.
|
// OnBoardGroup create user group entity in Harbor DB, altGroupName is not used.
|
||||||
func (a *Auth) OnBoardGroup(u *model.UserGroup, altGroupName string) error {
|
func (a *Auth) OnBoardGroup(ctx context.Context, u *model.UserGroup, altGroupName string) error {
|
||||||
// if group name provided, on board the user group
|
// if group name provided, on board the user group
|
||||||
if len(u.GroupName) == 0 {
|
if len(u.GroupName) == 0 {
|
||||||
return errors.New("should provide a group name")
|
return errors.New("should provide a group name")
|
||||||
}
|
}
|
||||||
u.GroupType = common.HTTPGroupType
|
u.GroupType = common.HTTPGroupType
|
||||||
err := usergroup.Ctl.Ensure(orm.Context(), u)
|
err := usergroup.Ctl.Ensure(ctx, u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -218,14 +217,14 @@ func (a *Auth) fillInModel(u *models.User) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Auth) ensure() error {
|
func (a *Auth) ensure(ctx context.Context) error {
|
||||||
a.Lock()
|
a.Lock()
|
||||||
defer a.Unlock()
|
defer a.Unlock()
|
||||||
if a.client == nil {
|
if a.client == nil {
|
||||||
a.client = &http.Client{}
|
a.client = &http.Client{}
|
||||||
}
|
}
|
||||||
if time.Now().Sub(a.settingTimeStamp) >= refreshDuration {
|
if time.Now().Sub(a.settingTimeStamp) >= refreshDuration {
|
||||||
setting, err := config.HTTPAuthProxySetting(orm.Context())
|
setting, err := config.HTTPAuthProxySetting(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,7 @@ func TestAuth_Authenticate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
for _, c := range suite {
|
for _, c := range suite {
|
||||||
r, e := a.Authenticate(c.input)
|
r, e := a.Authenticate(orm.Context(), c.input)
|
||||||
if c.expect.err == nil {
|
if c.expect.err == nil {
|
||||||
assert.Nil(e)
|
assert.Nil(e)
|
||||||
assert.Equal(c.expect.user, *r)
|
assert.Equal(c.expect.user, *r)
|
||||||
@ -185,7 +185,7 @@ func TestAuth_PostAuthenticate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, c := range suite {
|
for _, c := range suite {
|
||||||
a.PostAuthenticate(c.input)
|
a.PostAuthenticate(orm.Context(), c.input)
|
||||||
assert.Equal(t, c.expect.Username, c.input.Username)
|
assert.Equal(t, c.expect.Username, c.input.Username)
|
||||||
assert.Equal(t, c.expect.Email, c.input.Email)
|
assert.Equal(t, c.expect.Email, c.input.Email)
|
||||||
assert.Equal(t, c.expect.Realname, c.input.Realname)
|
assert.Equal(t, c.expect.Realname, c.input.Realname)
|
||||||
@ -199,7 +199,7 @@ func TestAuth_OnBoardGroup(t *testing.T) {
|
|||||||
GroupName: "OnBoardTest",
|
GroupName: "OnBoardTest",
|
||||||
GroupType: common.HTTPGroupType,
|
GroupType: common.HTTPGroupType,
|
||||||
}
|
}
|
||||||
a.OnBoardGroup(input, "")
|
a.OnBoardGroup(orm.Context(), input, "")
|
||||||
|
|
||||||
assert.True(t, input.ID > 0, "The OnBoardGroup should have a valid group ID")
|
assert.True(t, input.ID > 0, "The OnBoardGroup should have a valid group ID")
|
||||||
g, er := usergroup.Mgr.Get(orm.Context(), input.ID)
|
g, er := usergroup.Mgr.Get(orm.Context(), input.ID)
|
||||||
@ -207,7 +207,7 @@ func TestAuth_OnBoardGroup(t *testing.T) {
|
|||||||
assert.Equal(t, "OnBoardTest", g.GroupName)
|
assert.Equal(t, "OnBoardTest", g.GroupName)
|
||||||
|
|
||||||
emptyGroup := &model.UserGroup{}
|
emptyGroup := &model.UserGroup{}
|
||||||
err := a.OnBoardGroup(emptyGroup, "")
|
err := a.OnBoardGroup(orm.Context(), emptyGroup, "")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatal("Empty user group should failed to OnBoard")
|
t.Fatal("Empty user group should failed to OnBoard")
|
||||||
}
|
}
|
||||||
|
@ -15,11 +15,12 @@
|
|||||||
package db
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/common"
|
"github.com/goharbor/harbor/src/common"
|
||||||
"github.com/goharbor/harbor/src/common/models"
|
"github.com/goharbor/harbor/src/common/models"
|
||||||
"github.com/goharbor/harbor/src/core/auth"
|
"github.com/goharbor/harbor/src/core/auth"
|
||||||
"github.com/goharbor/harbor/src/lib/errors"
|
"github.com/goharbor/harbor/src/lib/errors"
|
||||||
"github.com/goharbor/harbor/src/lib/orm"
|
|
||||||
"github.com/goharbor/harbor/src/pkg/user"
|
"github.com/goharbor/harbor/src/pkg/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -30,8 +31,8 @@ type Auth struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Authenticate calls dao to authenticate user.
|
// Authenticate calls dao to authenticate user.
|
||||||
func (d *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
|
func (d *Auth) Authenticate(ctx context.Context, m models.AuthModel) (*models.User, error) {
|
||||||
u, err := d.userMgr.MatchLocalPassword(orm.Context(), m.Principal, m.Password)
|
u, err := d.userMgr.MatchLocalPassword(ctx, m.Principal, m.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -42,8 +43,8 @@ func (d *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SearchUser - Check if user exist in local db
|
// SearchUser - Check if user exist in local db
|
||||||
func (d *Auth) SearchUser(username string) (*models.User, error) {
|
func (d *Auth) SearchUser(ctx context.Context, username string) (*models.User, error) {
|
||||||
u, err := d.userMgr.GetByName(orm.Context(), username)
|
u, err := d.userMgr.GetByName(ctx, username)
|
||||||
if errors.IsNotFoundErr(err) {
|
if errors.IsNotFoundErr(err) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
@ -53,7 +54,7 @@ func (d *Auth) SearchUser(username string) (*models.User, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OnBoardUser -
|
// OnBoardUser -
|
||||||
func (d *Auth) OnBoardUser(u *models.User) error {
|
func (d *Auth) OnBoardUser(ctx context.Context, u *models.User) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,23 +14,15 @@
|
|||||||
package db
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/common/models"
|
"github.com/goharbor/harbor/src/common/models"
|
||||||
"github.com/goharbor/harbor/src/common/utils/test"
|
|
||||||
"github.com/goharbor/harbor/src/testing/mock"
|
"github.com/goharbor/harbor/src/testing/mock"
|
||||||
testinguserpkg "github.com/goharbor/harbor/src/testing/pkg/user"
|
testinguserpkg "github.com/goharbor/harbor/src/testing/pkg/user"
|
||||||
|
|
||||||
testifymock "github.com/stretchr/testify/mock"
|
testifymock "github.com/stretchr/testify/mock"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
|
||||||
test.InitDatabaseFromEnv()
|
|
||||||
retCode := m.Run()
|
|
||||||
os.Exit(retCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSearchUser(t *testing.T) {
|
func TestSearchUser(t *testing.T) {
|
||||||
user := &models.User{
|
user := &models.User{
|
||||||
UserID: 123,
|
UserID: 123,
|
||||||
@ -49,7 +41,7 @@ func TestSearchUser(t *testing.T) {
|
|||||||
return name == "existuser"
|
return name == "existuser"
|
||||||
})).Return(user, nil)
|
})).Return(user, nil)
|
||||||
|
|
||||||
newUser, err := auth.SearchUser("existuser")
|
newUser, err := auth.SearchUser(context.TODO(), "existuser")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to search user, error %v", err)
|
t.Fatalf("Failed to search user, error %v", err)
|
||||||
}
|
}
|
||||||
|
@ -20,25 +20,21 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
goldap "github.com/go-ldap/ldap/v3"
|
||||||
|
"github.com/goharbor/harbor/src/common"
|
||||||
|
"github.com/goharbor/harbor/src/common/models"
|
||||||
|
"github.com/goharbor/harbor/src/common/utils"
|
||||||
|
ldapCtl "github.com/goharbor/harbor/src/controller/ldap"
|
||||||
|
ugCtl "github.com/goharbor/harbor/src/controller/usergroup"
|
||||||
|
"github.com/goharbor/harbor/src/core/auth"
|
||||||
"github.com/goharbor/harbor/src/lib/config"
|
"github.com/goharbor/harbor/src/lib/config"
|
||||||
"github.com/goharbor/harbor/src/lib/errors"
|
"github.com/goharbor/harbor/src/lib/errors"
|
||||||
"github.com/goharbor/harbor/src/lib/orm"
|
"github.com/goharbor/harbor/src/lib/log"
|
||||||
"github.com/goharbor/harbor/src/lib/q"
|
"github.com/goharbor/harbor/src/lib/q"
|
||||||
|
"github.com/goharbor/harbor/src/pkg/ldap"
|
||||||
"github.com/goharbor/harbor/src/pkg/ldap/model"
|
"github.com/goharbor/harbor/src/pkg/ldap/model"
|
||||||
"github.com/goharbor/harbor/src/pkg/user"
|
"github.com/goharbor/harbor/src/pkg/user"
|
||||||
ugModel "github.com/goharbor/harbor/src/pkg/usergroup/model"
|
ugModel "github.com/goharbor/harbor/src/pkg/usergroup/model"
|
||||||
|
|
||||||
goldap "github.com/go-ldap/ldap/v3"
|
|
||||||
"github.com/goharbor/harbor/src/common"
|
|
||||||
"github.com/goharbor/harbor/src/common/utils"
|
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/common/models"
|
|
||||||
ldapCtl "github.com/goharbor/harbor/src/controller/ldap"
|
|
||||||
ugCtl "github.com/goharbor/harbor/src/controller/usergroup"
|
|
||||||
"github.com/goharbor/harbor/src/pkg/ldap"
|
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/core/auth"
|
|
||||||
"github.com/goharbor/harbor/src/lib/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Auth implements AuthenticateHelper interface to authenticate against LDAP
|
// Auth implements AuthenticateHelper interface to authenticate against LDAP
|
||||||
@ -50,8 +46,7 @@ type Auth struct {
|
|||||||
// Authenticate checks user's credential against LDAP based on basedn template and LDAP URL,
|
// Authenticate checks user's credential against LDAP based on basedn template and LDAP URL,
|
||||||
// if the check is successful a dummy record will be inserted into DB, such that this user can
|
// if the check is successful a dummy record will be inserted into DB, such that this user can
|
||||||
// be associated to other entities in the system.
|
// be associated to other entities in the system.
|
||||||
func (l *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
|
func (l *Auth) Authenticate(ctx context.Context, m models.AuthModel) (*models.User, error) {
|
||||||
ctx := orm.Context()
|
|
||||||
p := m.Principal
|
p := m.Principal
|
||||||
if len(strings.TrimSpace(p)) == 0 {
|
if len(strings.TrimSpace(p)) == 0 {
|
||||||
log.Debugf("LDAP authentication failed for empty user id.")
|
log.Debugf("LDAP authentication failed for empty user id.")
|
||||||
@ -135,7 +130,7 @@ func (l *Auth) attachLDAPGroup(ctx context.Context, ldapUsers []model.User, u *m
|
|||||||
}
|
}
|
||||||
userGroups = append(userGroups, ugModel.UserGroup{GroupName: lGroups[0].Name, LdapGroupDN: dn, GroupType: common.LDAPGroupType})
|
userGroups = append(userGroups, ugModel.UserGroup{GroupName: lGroups[0].Name, LdapGroupDN: dn, GroupType: common.LDAPGroupType})
|
||||||
}
|
}
|
||||||
u.GroupIDs, err = ugCtl.Ctl.Populate(orm.Context(), userGroups)
|
u.GroupIDs, err = ugCtl.Ctl.Populate(ctx, userGroups)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warningf("Failed to fetch ldap group configuration:%v", err)
|
log.Warningf("Failed to fetch ldap group configuration:%v", err)
|
||||||
}
|
}
|
||||||
@ -155,7 +150,7 @@ func (l *Auth) syncUserInfoFromDB(ctx context.Context, u *models.User) {
|
|||||||
|
|
||||||
// OnBoardUser will check if a user exists in user table, if not insert the user and
|
// OnBoardUser will check if a user exists in user table, if not insert the user and
|
||||||
// put the id in the pointer of user model, if it does exist, return the user's profile.
|
// put the id in the pointer of user model, if it does exist, return the user's profile.
|
||||||
func (l *Auth) OnBoardUser(u *models.User) error {
|
func (l *Auth) OnBoardUser(ctx context.Context, u *models.User) error {
|
||||||
if u.Email == "" {
|
if u.Email == "" {
|
||||||
if strings.Contains(u.Username, "@") {
|
if strings.Contains(u.Username, "@") {
|
||||||
u.Email = u.Username
|
u.Email = u.Username
|
||||||
@ -164,13 +159,13 @@ func (l *Auth) OnBoardUser(u *models.User) error {
|
|||||||
u.Password = "12345678AbC" // Password is not kept in local db
|
u.Password = "12345678AbC" // Password is not kept in local db
|
||||||
u.Comment = "from LDAP." // Source is from LDAP
|
u.Comment = "from LDAP." // Source is from LDAP
|
||||||
|
|
||||||
return l.userMgr.Onboard(orm.Context(), u)
|
return l.userMgr.Onboard(ctx, u)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchUser -- Search user in ldap
|
// SearchUser -- Search user in ldap
|
||||||
func (l *Auth) SearchUser(username string) (*models.User, error) {
|
func (l *Auth) SearchUser(ctx context.Context, username string) (*models.User, error) {
|
||||||
var user models.User
|
var user models.User
|
||||||
s, err := ldapCtl.Ctl.Session(orm.Context())
|
s, err := ldapCtl.Ctl.Session(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -201,11 +196,11 @@ func (l *Auth) SearchUser(username string) (*models.User, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SearchGroup -- Search group in ldap authenticator, groupKey is LDAP group DN.
|
// SearchGroup -- Search group in ldap authenticator, groupKey is LDAP group DN.
|
||||||
func (l *Auth) SearchGroup(groupKey string) (*ugModel.UserGroup, error) {
|
func (l *Auth) SearchGroup(ctx context.Context, groupKey string) (*ugModel.UserGroup, error) {
|
||||||
if _, err := goldap.ParseDN(groupKey); err != nil {
|
if _, err := goldap.ParseDN(groupKey); err != nil {
|
||||||
return nil, auth.ErrInvalidLDAPGroupDN
|
return nil, auth.ErrInvalidLDAPGroupDN
|
||||||
}
|
}
|
||||||
s, err := ldapCtl.Ctl.Session(orm.Context())
|
s, err := ldapCtl.Ctl.Session(ctx)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("can not load system ldap config: %v", err)
|
return nil, fmt.Errorf("can not load system ldap config: %v", err)
|
||||||
@ -234,8 +229,7 @@ func (l *Auth) SearchGroup(groupKey string) (*ugModel.UserGroup, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OnBoardGroup -- Create Group in harbor DB, if altGroupName is not empty, take the altGroupName as groupName in harbor DB.
|
// OnBoardGroup -- Create Group in harbor DB, if altGroupName is not empty, take the altGroupName as groupName in harbor DB.
|
||||||
func (l *Auth) OnBoardGroup(u *ugModel.UserGroup, altGroupName string) error {
|
func (l *Auth) OnBoardGroup(ctx context.Context, u *ugModel.UserGroup, altGroupName string) error {
|
||||||
ctx := orm.Context()
|
|
||||||
if _, err := goldap.ParseDN(u.LdapGroupDN); err != nil {
|
if _, err := goldap.ParseDN(u.LdapGroupDN); err != nil {
|
||||||
return auth.ErrInvalidLDAPGroupDN
|
return auth.ErrInvalidLDAPGroupDN
|
||||||
}
|
}
|
||||||
@ -255,9 +249,7 @@ func (l *Auth) OnBoardGroup(u *ugModel.UserGroup, altGroupName string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PostAuthenticate -- If user exist in harbor DB, sync email address, if not exist, call OnBoardUser
|
// PostAuthenticate -- If user exist in harbor DB, sync email address, if not exist, call OnBoardUser
|
||||||
func (l *Auth) PostAuthenticate(u *models.User) error {
|
func (l *Auth) PostAuthenticate(ctx context.Context, u *models.User) error {
|
||||||
|
|
||||||
ctx := orm.Context()
|
|
||||||
query := q.New(q.KeyWords{"Username": u.Username})
|
query := q.New(q.KeyWords{"Username": u.Username})
|
||||||
n, err := l.userMgr.Count(ctx, query)
|
n, err := l.userMgr.Count(ctx, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -288,7 +280,7 @@ func (l *Auth) PostAuthenticate(u *models.User) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err = auth.OnBoardUser(u)
|
err = auth.OnBoardUser(ctx, u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -14,28 +14,26 @@
|
|||||||
package ldap
|
package ldap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goharbor/harbor/src/pkg/project"
|
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/lib/config"
|
|
||||||
"github.com/goharbor/harbor/src/lib/orm"
|
|
||||||
_ "github.com/goharbor/harbor/src/pkg/config/db"
|
|
||||||
_ "github.com/goharbor/harbor/src/pkg/config/inmemory"
|
|
||||||
userpkg "github.com/goharbor/harbor/src/pkg/user"
|
|
||||||
"github.com/goharbor/harbor/src/pkg/usergroup"
|
|
||||||
ugModel "github.com/goharbor/harbor/src/pkg/usergroup/model"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/common"
|
"github.com/goharbor/harbor/src/common"
|
||||||
"github.com/goharbor/harbor/src/common/dao"
|
"github.com/goharbor/harbor/src/common/dao"
|
||||||
"github.com/goharbor/harbor/src/common/models"
|
"github.com/goharbor/harbor/src/common/models"
|
||||||
"github.com/goharbor/harbor/src/common/utils/test"
|
"github.com/goharbor/harbor/src/common/utils/test"
|
||||||
|
"github.com/goharbor/harbor/src/core/auth"
|
||||||
|
"github.com/goharbor/harbor/src/lib/config"
|
||||||
"github.com/goharbor/harbor/src/lib/log"
|
"github.com/goharbor/harbor/src/lib/log"
|
||||||
|
"github.com/goharbor/harbor/src/lib/orm"
|
||||||
|
_ "github.com/goharbor/harbor/src/pkg/config/db"
|
||||||
|
_ "github.com/goharbor/harbor/src/pkg/config/inmemory"
|
||||||
"github.com/goharbor/harbor/src/pkg/member"
|
"github.com/goharbor/harbor/src/pkg/member"
|
||||||
memberModels "github.com/goharbor/harbor/src/pkg/member/models"
|
memberModels "github.com/goharbor/harbor/src/pkg/member/models"
|
||||||
|
"github.com/goharbor/harbor/src/pkg/project"
|
||||||
"github.com/goharbor/harbor/src/core/auth"
|
userpkg "github.com/goharbor/harbor/src/pkg/user"
|
||||||
|
"github.com/goharbor/harbor/src/pkg/usergroup"
|
||||||
|
ugModel "github.com/goharbor/harbor/src/pkg/usergroup/model"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ldapTestConfig = map[string]interface{}{
|
var ldapTestConfig = map[string]interface{}{
|
||||||
@ -111,10 +109,12 @@ func TestMain(m *testing.M) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAuthenticate(t *testing.T) {
|
func TestAuthenticate(t *testing.T) {
|
||||||
|
ctx := orm.Context()
|
||||||
|
|
||||||
var person models.AuthModel
|
var person models.AuthModel
|
||||||
person.Principal = "test"
|
person.Principal = "test"
|
||||||
person.Password = "123456"
|
person.Password = "123456"
|
||||||
user, err := authHelper.Authenticate(person)
|
user, err := authHelper.Authenticate(ctx, person)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected ldap authenticate fail: %v", err)
|
t.Errorf("unexpected ldap authenticate fail: %v", err)
|
||||||
}
|
}
|
||||||
@ -123,14 +123,14 @@ func TestAuthenticate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
person.Principal = "test"
|
person.Principal = "test"
|
||||||
person.Password = "1"
|
person.Password = "1"
|
||||||
user, err = authHelper.Authenticate(person)
|
user, err = authHelper.Authenticate(ctx, person)
|
||||||
|
|
||||||
if _, ok := err.(auth.ErrAuth); !ok {
|
if _, ok := err.(auth.ErrAuth); !ok {
|
||||||
t.Errorf("Expected an ErrAuth on wrong password, but got: %v", err)
|
t.Errorf("Expected an ErrAuth on wrong password, but got: %v", err)
|
||||||
}
|
}
|
||||||
person.Principal = ""
|
person.Principal = ""
|
||||||
person.Password = ""
|
person.Password = ""
|
||||||
user, err = authHelper.Authenticate(person)
|
user, err = authHelper.Authenticate(ctx, person)
|
||||||
if _, ok := err.(auth.ErrAuth); !ok {
|
if _, ok := err.(auth.ErrAuth); !ok {
|
||||||
t.Errorf("Expected an ErrAuth on empty credentials, but got: %v", err)
|
t.Errorf("Expected an ErrAuth on empty credentials, but got: %v", err)
|
||||||
}
|
}
|
||||||
@ -139,7 +139,7 @@ func TestAuthenticate(t *testing.T) {
|
|||||||
Principal: "test",
|
Principal: "test",
|
||||||
Password: "123456",
|
Password: "123456",
|
||||||
}
|
}
|
||||||
user2, err := authHelper.Authenticate(person2)
|
user2, err := authHelper.Authenticate(ctx, person2)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected ldap error: %v", err)
|
t.Errorf("unexpected ldap error: %v", err)
|
||||||
@ -151,8 +151,10 @@ func TestAuthenticate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSearchUser(t *testing.T) {
|
func TestSearchUser(t *testing.T) {
|
||||||
|
ctx := orm.Context()
|
||||||
|
|
||||||
var username = "test"
|
var username = "test"
|
||||||
user, err := authHelper.SearchUser(username)
|
user, err := authHelper.SearchUser(ctx, username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Search user failed %v", err)
|
t.Errorf("Search user failed %v", err)
|
||||||
}
|
}
|
||||||
@ -161,10 +163,12 @@ func TestSearchUser(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
func TestAuthenticateWithAdmin(t *testing.T) {
|
func TestAuthenticateWithAdmin(t *testing.T) {
|
||||||
|
ctx := orm.Context()
|
||||||
|
|
||||||
var person models.AuthModel
|
var person models.AuthModel
|
||||||
person.Principal = "mike"
|
person.Principal = "mike"
|
||||||
person.Password = "zhu88jie"
|
person.Password = "zhu88jie"
|
||||||
user, err := authHelper.Authenticate(person)
|
user, err := authHelper.Authenticate(ctx, person)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected ldap authenticate fail: %v", err)
|
t.Errorf("unexpected ldap authenticate fail: %v", err)
|
||||||
}
|
}
|
||||||
@ -176,10 +180,12 @@ func TestAuthenticateWithAdmin(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
func TestAuthenticateWithoutAdmin(t *testing.T) {
|
func TestAuthenticateWithoutAdmin(t *testing.T) {
|
||||||
|
ctx := orm.Context()
|
||||||
|
|
||||||
var person models.AuthModel
|
var person models.AuthModel
|
||||||
person.Principal = "user001"
|
person.Principal = "user001"
|
||||||
person.Password = "Test1@34"
|
person.Password = "Test1@34"
|
||||||
user, err := authHelper.Authenticate(person)
|
user, err := authHelper.Authenticate(ctx, person)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected ldap authenticate fail: %v", err)
|
t.Errorf("unexpected ldap authenticate fail: %v", err)
|
||||||
}
|
}
|
||||||
@ -191,8 +197,10 @@ func TestAuthenticateWithoutAdmin(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
func TestSearchUser_02(t *testing.T) {
|
func TestSearchUser_02(t *testing.T) {
|
||||||
|
ctx := orm.Context()
|
||||||
|
|
||||||
var username = "nonexist"
|
var username = "nonexist"
|
||||||
user, _ := authHelper.SearchUser(username)
|
user, _ := authHelper.SearchUser(ctx, username)
|
||||||
if user != nil {
|
if user != nil {
|
||||||
t.Errorf("Should failed to search nonexist user")
|
t.Errorf("Should failed to search nonexist user")
|
||||||
}
|
}
|
||||||
@ -200,12 +208,14 @@ func TestSearchUser_02(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestOnBoardUser(t *testing.T) {
|
func TestOnBoardUser(t *testing.T) {
|
||||||
|
ctx := orm.Context()
|
||||||
|
|
||||||
user := &models.User{
|
user := &models.User{
|
||||||
Username: "sample",
|
Username: "sample",
|
||||||
Email: "sample@example.com",
|
Email: "sample@example.com",
|
||||||
Realname: "Sample",
|
Realname: "Sample",
|
||||||
}
|
}
|
||||||
err := authHelper.OnBoardUser(user)
|
err := authHelper.OnBoardUser(ctx, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Failed to onboard user")
|
t.Errorf("Failed to onboard user")
|
||||||
}
|
}
|
||||||
@ -216,11 +226,13 @@ func TestOnBoardUser(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestOnBoardUser_02(t *testing.T) {
|
func TestOnBoardUser_02(t *testing.T) {
|
||||||
|
ctx := orm.Context()
|
||||||
|
|
||||||
user := &models.User{
|
user := &models.User{
|
||||||
Username: "sample02",
|
Username: "sample02",
|
||||||
Realname: "Sample02",
|
Realname: "Sample02",
|
||||||
}
|
}
|
||||||
err := authHelper.OnBoardUser(user)
|
err := authHelper.OnBoardUser(ctx, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Failed to onboard user")
|
t.Errorf("Failed to onboard user")
|
||||||
}
|
}
|
||||||
@ -233,11 +245,13 @@ func TestOnBoardUser_02(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestOnBoardUser_03(t *testing.T) {
|
func TestOnBoardUser_03(t *testing.T) {
|
||||||
|
ctx := orm.Context()
|
||||||
|
|
||||||
user := &models.User{
|
user := &models.User{
|
||||||
Username: "sample03@example.com",
|
Username: "sample03@example.com",
|
||||||
Realname: "Sample03",
|
Realname: "Sample03",
|
||||||
}
|
}
|
||||||
err := authHelper.OnBoardUser(user)
|
err := authHelper.OnBoardUser(ctx, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Failed to onboard user")
|
t.Errorf("Failed to onboard user")
|
||||||
}
|
}
|
||||||
@ -250,13 +264,15 @@ func TestOnBoardUser_03(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAuthenticateHelperOnBoardUser(t *testing.T) {
|
func TestAuthenticateHelperOnBoardUser(t *testing.T) {
|
||||||
|
ctx := orm.Context()
|
||||||
|
|
||||||
user := models.User{
|
user := models.User{
|
||||||
Username: "test01",
|
Username: "test01",
|
||||||
Realname: "test01",
|
Realname: "test01",
|
||||||
Email: "test01@example.com",
|
Email: "test01@example.com",
|
||||||
}
|
}
|
||||||
|
|
||||||
err := auth.OnBoardUser(&user)
|
err := auth.OnBoardUser(ctx, &user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Failed to onboard user error: %v", err)
|
t.Errorf("Failed to onboard user error: %v", err)
|
||||||
}
|
}
|
||||||
@ -268,12 +284,14 @@ func TestAuthenticateHelperOnBoardUser(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestOnBoardGroup(t *testing.T) {
|
func TestOnBoardGroup(t *testing.T) {
|
||||||
|
ctx := orm.Context()
|
||||||
|
|
||||||
group := ugModel.UserGroup{
|
group := ugModel.UserGroup{
|
||||||
GroupName: "harbor_group2",
|
GroupName: "harbor_group2",
|
||||||
LdapGroupDN: "cn=harbor_group2,ou=groups,dc=example,dc=com",
|
LdapGroupDN: "cn=harbor_group2,ou=groups,dc=example,dc=com",
|
||||||
}
|
}
|
||||||
newGroupName := "group_name123"
|
newGroupName := "group_name123"
|
||||||
err := auth.OnBoardGroup(&group, newGroupName)
|
err := auth.OnBoardGroup(ctx, &group, newGroupName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Failed to OnBoardGroup, %+v", group)
|
t.Errorf("Failed to OnBoardGroup, %+v", group)
|
||||||
}
|
}
|
||||||
@ -283,8 +301,9 @@ func TestOnBoardGroup(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAuthenticateHelperSearchUser(t *testing.T) {
|
func TestAuthenticateHelperSearchUser(t *testing.T) {
|
||||||
|
ctx := orm.Context()
|
||||||
|
|
||||||
user, err := auth.SearchUser("test")
|
user, err := auth.SearchUser(ctx, "test")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("Failed to search user, test")
|
t.Error("Failed to search user, test")
|
||||||
}
|
}
|
||||||
@ -295,6 +314,7 @@ func TestAuthenticateHelperSearchUser(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPostAuthentication(t *testing.T) {
|
func TestPostAuthentication(t *testing.T) {
|
||||||
|
ctx := orm.Context()
|
||||||
|
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
user1 := &models.User{
|
user1 := &models.User{
|
||||||
@ -305,7 +325,7 @@ func TestPostAuthentication(t *testing.T) {
|
|||||||
|
|
||||||
queryUsername := "test003"
|
queryUsername := "test003"
|
||||||
|
|
||||||
err := auth.OnBoardUser(user1)
|
err := auth.OnBoardUser(ctx, user1)
|
||||||
assert.Nil(err)
|
assert.Nil(err)
|
||||||
|
|
||||||
user2 := &models.User{
|
user2 := &models.User{
|
||||||
@ -313,8 +333,8 @@ func TestPostAuthentication(t *testing.T) {
|
|||||||
Email: "234invalidmail@@@@@",
|
Email: "234invalidmail@@@@@",
|
||||||
}
|
}
|
||||||
|
|
||||||
auth.PostAuthenticate(user2)
|
auth.PostAuthenticate(ctx, user2)
|
||||||
ctx := orm.Context()
|
|
||||||
dbUser, err := userpkg.Mgr.GetByName(ctx, queryUsername)
|
dbUser, err := userpkg.Mgr.GetByName(ctx, queryUsername)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to get user, error %v", err)
|
t.Fatalf("Failed to get user, error %v", err)
|
||||||
@ -325,7 +345,7 @@ func TestPostAuthentication(t *testing.T) {
|
|||||||
Username: "test003",
|
Username: "test003",
|
||||||
}
|
}
|
||||||
|
|
||||||
auth.PostAuthenticate(user3)
|
auth.PostAuthenticate(ctx, user3)
|
||||||
dbUser, err = userpkg.Mgr.GetByName(ctx, queryUsername)
|
dbUser, err = userpkg.Mgr.GetByName(ctx, queryUsername)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to get user, error %v", err)
|
t.Fatalf("Failed to get user, error %v", err)
|
||||||
@ -337,7 +357,7 @@ func TestPostAuthentication(t *testing.T) {
|
|||||||
Email: "test003@example.com",
|
Email: "test003@example.com",
|
||||||
}
|
}
|
||||||
|
|
||||||
auth.PostAuthenticate(user4)
|
auth.PostAuthenticate(ctx, user4)
|
||||||
dbUser, err = userpkg.Mgr.GetByName(ctx, queryUsername)
|
dbUser, err = userpkg.Mgr.GetByName(ctx, queryUsername)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to get user, error %v", err)
|
t.Fatalf("Failed to get user, error %v", err)
|
||||||
@ -347,7 +367,9 @@ func TestPostAuthentication(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSearchAndOnBoardUser(t *testing.T) {
|
func TestSearchAndOnBoardUser(t *testing.T) {
|
||||||
userID, err := auth.SearchAndOnBoardUser("mike02")
|
ctx := orm.Context()
|
||||||
|
|
||||||
|
userID, err := auth.SearchAndOnBoardUser(ctx, "mike02")
|
||||||
defer dao.CleanUser(int64(userID))
|
defer dao.CleanUser(int64(userID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Error occurred when SearchAndOnBoardUser: %v", err)
|
t.Errorf("Error occurred when SearchAndOnBoardUser: %v", err)
|
||||||
@ -363,7 +385,7 @@ func TestAddProjectMemberWithLdapUser(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Error occurred when GetProjectByName: %v", err)
|
t.Errorf("Error occurred when GetProjectByName: %v", err)
|
||||||
}
|
}
|
||||||
userID, err := auth.SearchAndOnBoardUser("mike")
|
userID, err := auth.SearchAndOnBoardUser(ctx, "mike")
|
||||||
member := memberModels.Member{
|
member := memberModels.Member{
|
||||||
ProjectID: currentProject.ProjectID,
|
ProjectID: currentProject.ProjectID,
|
||||||
EntityType: common.UserMember,
|
EntityType: common.UserMember,
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
package oidc
|
package oidc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/common"
|
"github.com/goharbor/harbor/src/common"
|
||||||
"github.com/goharbor/harbor/src/core/auth"
|
"github.com/goharbor/harbor/src/core/auth"
|
||||||
"github.com/goharbor/harbor/src/lib/orm"
|
|
||||||
"github.com/goharbor/harbor/src/pkg/usergroup"
|
"github.com/goharbor/harbor/src/pkg/usergroup"
|
||||||
"github.com/goharbor/harbor/src/pkg/usergroup/model"
|
"github.com/goharbor/harbor/src/pkg/usergroup/model"
|
||||||
)
|
)
|
||||||
@ -15,7 +16,7 @@ type Auth struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SearchGroup is skipped in OIDC mode, so it makes sure any group will be onboarded.
|
// SearchGroup is skipped in OIDC mode, so it makes sure any group will be onboarded.
|
||||||
func (a *Auth) SearchGroup(groupKey string) (*model.UserGroup, error) {
|
func (a *Auth) SearchGroup(ctx context.Context, groupKey string) (*model.UserGroup, error) {
|
||||||
return &model.UserGroup{
|
return &model.UserGroup{
|
||||||
GroupName: groupKey,
|
GroupName: groupKey,
|
||||||
GroupType: common.OIDCGroupType,
|
GroupType: common.OIDCGroupType,
|
||||||
@ -23,12 +24,12 @@ func (a *Auth) SearchGroup(groupKey string) (*model.UserGroup, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OnBoardGroup create user group entity in Harbor DB, altGroupName is not used.
|
// OnBoardGroup create user group entity in Harbor DB, altGroupName is not used.
|
||||||
func (a *Auth) OnBoardGroup(u *model.UserGroup, altGroupName string) error {
|
func (a *Auth) OnBoardGroup(ctx context.Context, u *model.UserGroup, altGroupName string) error {
|
||||||
// if group name provided, on board the user group
|
// if group name provided, on board the user group
|
||||||
if len(u.GroupName) == 0 || u.GroupType != common.OIDCGroupType {
|
if len(u.GroupName) == 0 || u.GroupType != common.OIDCGroupType {
|
||||||
return fmt.Errorf("invalid input group for OIDC mode: %v", *u)
|
return fmt.Errorf("invalid input group for OIDC mode: %v", *u)
|
||||||
}
|
}
|
||||||
return usergroup.Mgr.Onboard(orm.Context(), u)
|
return usergroup.Mgr.Onboard(ctx, u)
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
package oidc
|
package oidc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/common"
|
"github.com/goharbor/harbor/src/common"
|
||||||
"github.com/goharbor/harbor/src/pkg/usergroup/model"
|
"github.com/goharbor/harbor/src/pkg/usergroup/model"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
@ -15,7 +17,7 @@ func TestMain(m *testing.M) {
|
|||||||
|
|
||||||
func TestAuth_SearchGroup(t *testing.T) {
|
func TestAuth_SearchGroup(t *testing.T) {
|
||||||
a := Auth{}
|
a := Auth{}
|
||||||
res, err := a.SearchGroup("grp")
|
res, err := a.SearchGroup(context.TODO(), "grp")
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, model.UserGroup{GroupName: "grp", GroupType: common.OIDCGroupType}, *res)
|
assert.Equal(t, model.UserGroup{GroupName: "grp", GroupType: common.OIDCGroupType}, *res)
|
||||||
}
|
}
|
||||||
@ -23,9 +25,9 @@ func TestAuth_SearchGroup(t *testing.T) {
|
|||||||
func TestAuth_OnBoardGroup(t *testing.T) {
|
func TestAuth_OnBoardGroup(t *testing.T) {
|
||||||
a := Auth{}
|
a := Auth{}
|
||||||
g1 := &model.UserGroup{GroupName: "", GroupType: common.OIDCGroupType}
|
g1 := &model.UserGroup{GroupName: "", GroupType: common.OIDCGroupType}
|
||||||
err1 := a.OnBoardGroup(g1, "")
|
err1 := a.OnBoardGroup(context.TODO(), g1, "")
|
||||||
assert.NotNil(t, err1)
|
assert.NotNil(t, err1)
|
||||||
g2 := &model.UserGroup{GroupName: "group", GroupType: common.LDAPGroupType}
|
g2 := &model.UserGroup{GroupName: "group", GroupType: common.LDAPGroupType}
|
||||||
err2 := a.OnBoardGroup(g2, "")
|
err2 := a.OnBoardGroup(context.TODO(), g2, "")
|
||||||
assert.NotNil(t, err2)
|
assert.NotNil(t, err2)
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
package uaa
|
package uaa
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
@ -27,7 +28,6 @@ import (
|
|||||||
"github.com/goharbor/harbor/src/lib/config"
|
"github.com/goharbor/harbor/src/lib/config"
|
||||||
"github.com/goharbor/harbor/src/lib/errors"
|
"github.com/goharbor/harbor/src/lib/errors"
|
||||||
"github.com/goharbor/harbor/src/lib/log"
|
"github.com/goharbor/harbor/src/lib/log"
|
||||||
"github.com/goharbor/harbor/src/lib/orm"
|
|
||||||
userpkg "github.com/goharbor/harbor/src/pkg/user"
|
userpkg "github.com/goharbor/harbor/src/pkg/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -40,8 +40,8 @@ type Auth struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Authenticate ...
|
// Authenticate ...
|
||||||
func (u *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
|
func (u *Auth) Authenticate(ctx context.Context, m models.AuthModel) (*models.User, error) {
|
||||||
if err := u.ensureClient(); err != nil {
|
if err := u.ensureClient(ctx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
t, err := u.client.PasswordAuth(m.Principal, m.Password)
|
t, err := u.client.PasswordAuth(m.Principal, m.Password)
|
||||||
@ -63,7 +63,7 @@ func (u *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
|
|||||||
|
|
||||||
// OnBoardUser will check if a user exists in user table, if not insert the user and
|
// OnBoardUser will check if a user exists in user table, if not insert the user and
|
||||||
// put the id in the pointer of user model, if it does exist, return the user's profile.
|
// put the id in the pointer of user model, if it does exist, return the user's profile.
|
||||||
func (u *Auth) OnBoardUser(user *models.User) error {
|
func (u *Auth) OnBoardUser(ctx context.Context, user *models.User) error {
|
||||||
user.Username = strings.TrimSpace(user.Username)
|
user.Username = strings.TrimSpace(user.Username)
|
||||||
if len(user.Username) == 0 {
|
if len(user.Username) == 0 {
|
||||||
return fmt.Errorf("the Username is empty")
|
return fmt.Errorf("the Username is empty")
|
||||||
@ -73,7 +73,7 @@ func (u *Auth) OnBoardUser(user *models.User) error {
|
|||||||
}
|
}
|
||||||
fillEmailRealName(user)
|
fillEmailRealName(user)
|
||||||
user.Comment = "From UAA"
|
user.Comment = "From UAA"
|
||||||
return u.userMgr.Onboard(orm.Context(), user)
|
return u.userMgr.Onboard(ctx, user)
|
||||||
}
|
}
|
||||||
|
|
||||||
func fillEmailRealName(user *models.User) {
|
func fillEmailRealName(user *models.User) {
|
||||||
@ -86,11 +86,10 @@ func fillEmailRealName(user *models.User) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PostAuthenticate will check if user exists in DB, if not on Board user, if he does, update the profile.
|
// PostAuthenticate will check if user exists in DB, if not on Board user, if he does, update the profile.
|
||||||
func (u *Auth) PostAuthenticate(user *models.User) error {
|
func (u *Auth) PostAuthenticate(ctx context.Context, user *models.User) error {
|
||||||
ctx := orm.Context()
|
|
||||||
dbUser, err := u.userMgr.GetByName(ctx, user.Username)
|
dbUser, err := u.userMgr.GetByName(ctx, user.Username)
|
||||||
if errors.IsNotFoundErr(err) {
|
if errors.IsNotFoundErr(err) {
|
||||||
return u.OnBoardUser(user)
|
return u.OnBoardUser(ctx, user)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -104,8 +103,8 @@ func (u *Auth) PostAuthenticate(user *models.User) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SearchUser search user on uaa server, transform it to Harbor's user model
|
// SearchUser search user on uaa server, transform it to Harbor's user model
|
||||||
func (u *Auth) SearchUser(username string) (*models.User, error) {
|
func (u *Auth) SearchUser(ctx context.Context, username string) (*models.User, error) {
|
||||||
if err := u.ensureClient(); err != nil {
|
if err := u.ensureClient(ctx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
l, err := u.client.SearchUser(username)
|
l, err := u.client.SearchUser(username)
|
||||||
@ -129,9 +128,9 @@ func (u *Auth) SearchUser(username string) (*models.User, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Auth) ensureClient() error {
|
func (u *Auth) ensureClient(ctx context.Context) error {
|
||||||
var cfg *uaa.ClientConfig
|
var cfg *uaa.ClientConfig
|
||||||
UAASettings, err := config.UAASettings(orm.Context())
|
UAASettings, err := config.UAASettings(ctx)
|
||||||
// log.Debugf("Uaa settings: %+v", UAASettings)
|
// log.Debugf("Uaa settings: %+v", UAASettings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warningf("Failed to get UAA setting from Admin Server, error: %v", err)
|
log.Warningf("Failed to get UAA setting from Admin Server, error: %v", err)
|
||||||
|
@ -59,13 +59,14 @@ func TestMain(m *testing.M) {
|
|||||||
func TestEnsureClient(t *testing.T) {
|
func TestEnsureClient(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
auth := Auth{client: nil}
|
auth := Auth{client: nil}
|
||||||
err := auth.ensureClient()
|
err := auth.ensureClient(orm.Context())
|
||||||
assert.Nil(err)
|
assert.Nil(err)
|
||||||
assert.NotNil(auth.client)
|
assert.NotNil(auth.client)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAuthenticate(t *testing.T) {
|
func TestAuthenticate(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
ctx := orm.Context()
|
||||||
client := &uaa.FakeClient{
|
client := &uaa.FakeClient{
|
||||||
Username: "user1",
|
Username: "user1",
|
||||||
Password: "password1",
|
Password: "password1",
|
||||||
@ -78,7 +79,7 @@ func TestAuthenticate(t *testing.T) {
|
|||||||
Principal: "user1",
|
Principal: "user1",
|
||||||
Password: "password1",
|
Password: "password1",
|
||||||
}
|
}
|
||||||
u1, err1 := auth.Authenticate(m1)
|
u1, err1 := auth.Authenticate(ctx, m1)
|
||||||
assert.Nil(err1)
|
assert.Nil(err1)
|
||||||
assert.NotNil(u1)
|
assert.NotNil(u1)
|
||||||
assert.Equal("fake@fake.com", u1.Email)
|
assert.Equal("fake@fake.com", u1.Email)
|
||||||
@ -86,7 +87,7 @@ func TestAuthenticate(t *testing.T) {
|
|||||||
Principal: "wrong",
|
Principal: "wrong",
|
||||||
Password: "wrong",
|
Password: "wrong",
|
||||||
}
|
}
|
||||||
u2, err2 := auth.Authenticate(m2)
|
u2, err2 := auth.Authenticate(ctx, m2)
|
||||||
assert.NotNil(err2)
|
assert.NotNil(err2)
|
||||||
assert.Nil(u2)
|
assert.Nil(u2)
|
||||||
err3 := dao.ClearTable(models.UserTable)
|
err3 := dao.ClearTable(models.UserTable)
|
||||||
@ -102,14 +103,14 @@ func TestOnBoardUser(t *testing.T) {
|
|||||||
um1 := &models.User{
|
um1 := &models.User{
|
||||||
Username: " ",
|
Username: " ",
|
||||||
}
|
}
|
||||||
err1 := auth.OnBoardUser(um1)
|
err1 := auth.OnBoardUser(ctx, um1)
|
||||||
assert.NotNil(err1)
|
assert.NotNil(err1)
|
||||||
um2 := &models.User{
|
um2 := &models.User{
|
||||||
Username: "test ",
|
Username: "test ",
|
||||||
}
|
}
|
||||||
user2, _ := auth.userMgr.GetByName(ctx, "test")
|
user2, _ := auth.userMgr.GetByName(ctx, "test")
|
||||||
assert.Nil(user2)
|
assert.Nil(user2)
|
||||||
err2 := auth.OnBoardUser(um2)
|
err2 := auth.OnBoardUser(ctx, um2)
|
||||||
assert.Nil(err2)
|
assert.Nil(err2)
|
||||||
user, _ := auth.userMgr.GetByName(ctx, "test")
|
user, _ := auth.userMgr.GetByName(ctx, "test")
|
||||||
assert.Equal("test", user.Realname)
|
assert.Equal("test", user.Realname)
|
||||||
@ -121,24 +122,24 @@ func TestOnBoardUser(t *testing.T) {
|
|||||||
|
|
||||||
func TestPostAuthenticate(t *testing.T) {
|
func TestPostAuthenticate(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
ctx := orm.Context()
|
||||||
auth := Auth{
|
auth := Auth{
|
||||||
userMgr: userpkg.New(),
|
userMgr: userpkg.New(),
|
||||||
}
|
}
|
||||||
um := &models.User{
|
um := &models.User{
|
||||||
Username: "test",
|
Username: "test",
|
||||||
}
|
}
|
||||||
err := auth.PostAuthenticate(um)
|
err := auth.PostAuthenticate(ctx, um)
|
||||||
// need a new user model to simulate a login case...
|
// need a new user model to simulate a login case...
|
||||||
um2 := &models.User{
|
um2 := &models.User{
|
||||||
Username: "test",
|
Username: "test",
|
||||||
}
|
}
|
||||||
ctx := orm.Context()
|
|
||||||
assert.Nil(err)
|
assert.Nil(err)
|
||||||
user, _ := auth.userMgr.GetByName(ctx, "test")
|
user, _ := auth.userMgr.GetByName(ctx, "test")
|
||||||
assert.Equal("", user.Email)
|
assert.Equal("", user.Email)
|
||||||
um2.Email = "newEmail@new.com"
|
um2.Email = "newEmail@new.com"
|
||||||
um2.Realname = "newName"
|
um2.Realname = "newName"
|
||||||
err2 := auth.PostAuthenticate(um2)
|
err2 := auth.PostAuthenticate(ctx, um2)
|
||||||
assert.Equal(user.UserID, um2.UserID)
|
assert.Equal(user.UserID, um2.UserID)
|
||||||
assert.Nil(err2)
|
assert.Nil(err2)
|
||||||
user2, _ := auth.userMgr.GetByName(ctx, "test")
|
user2, _ := auth.userMgr.GetByName(ctx, "test")
|
||||||
@ -148,7 +149,7 @@ func TestPostAuthenticate(t *testing.T) {
|
|||||||
um3 := &models.User{
|
um3 := &models.User{
|
||||||
Username: "test",
|
Username: "test",
|
||||||
}
|
}
|
||||||
err3 := auth.PostAuthenticate(um3)
|
err3 := auth.PostAuthenticate(ctx, um3)
|
||||||
assert.Nil(err3)
|
assert.Nil(err3)
|
||||||
user3, _ := auth.userMgr.GetByName(ctx, "test")
|
user3, _ := auth.userMgr.GetByName(ctx, "test")
|
||||||
assert.Equal(user3.UserID, um3.UserID)
|
assert.Equal(user3.UserID, um3.UserID)
|
||||||
@ -160,19 +161,20 @@ func TestPostAuthenticate(t *testing.T) {
|
|||||||
|
|
||||||
func TestSearchUser(t *testing.T) {
|
func TestSearchUser(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
ctx := orm.Context()
|
||||||
client := &uaa.FakeClient{
|
client := &uaa.FakeClient{
|
||||||
Username: "user1",
|
Username: "user1",
|
||||||
Password: "password1",
|
Password: "password1",
|
||||||
}
|
}
|
||||||
auth := Auth{client: client}
|
auth := Auth{client: client}
|
||||||
_, err0 := auth.SearchUser("error")
|
_, err0 := auth.SearchUser(ctx, "error")
|
||||||
assert.NotNil(err0)
|
assert.NotNil(err0)
|
||||||
u1, err1 := auth.SearchUser("one")
|
u1, err1 := auth.SearchUser(ctx, "one")
|
||||||
assert.Nil(err1)
|
assert.Nil(err1)
|
||||||
assert.Equal("one@email.com", u1.Email)
|
assert.Equal("one@email.com", u1.Email)
|
||||||
_, err2 := auth.SearchUser("two")
|
_, err2 := auth.SearchUser(ctx, "two")
|
||||||
assert.NotNil(err2)
|
assert.NotNil(err2)
|
||||||
user3, err3 := auth.SearchUser("none")
|
user3, err3 := auth.SearchUser(ctx, "none")
|
||||||
assert.Nil(user3)
|
assert.Nil(user3)
|
||||||
assert.Nil(err3)
|
assert.Nil(err3)
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,12 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/goharbor/harbor/src/lib/config"
|
|
||||||
"github.com/goharbor/harbor/src/lib/orm"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/common"
|
"github.com/goharbor/harbor/src/common"
|
||||||
"github.com/goharbor/harbor/src/core/api"
|
"github.com/goharbor/harbor/src/core/api"
|
||||||
"github.com/goharbor/harbor/src/core/auth/authproxy"
|
"github.com/goharbor/harbor/src/core/auth/authproxy"
|
||||||
|
"github.com/goharbor/harbor/src/lib/config"
|
||||||
"github.com/goharbor/harbor/src/lib/log"
|
"github.com/goharbor/harbor/src/lib/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -26,7 +25,7 @@ type AuthProxyController struct {
|
|||||||
|
|
||||||
// Prepare checks the auth mode and fail early
|
// Prepare checks the auth mode and fail early
|
||||||
func (apc *AuthProxyController) Prepare() {
|
func (apc *AuthProxyController) Prepare() {
|
||||||
am, err := config.AuthMode(orm.Context())
|
am, err := config.AuthMode(apc.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apc.SendInternalServerError(err)
|
apc.SendInternalServerError(err)
|
||||||
return
|
return
|
||||||
@ -45,13 +44,13 @@ func (apc *AuthProxyController) HandleRedirect() {
|
|||||||
apc.Ctx.Redirect(http.StatusMovedPermanently, "/")
|
apc.Ctx.Redirect(http.StatusMovedPermanently, "/")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
u, err := helper.VerifyToken(token)
|
u, err := helper.VerifyToken(apc.Context(), token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed to verify token, error: %v", err)
|
log.Errorf("Failed to verify token, error: %v", err)
|
||||||
apc.Ctx.Redirect(http.StatusMovedPermanently, "/")
|
apc.Ctx.Redirect(http.StatusMovedPermanently, "/")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := helper.PostAuthenticate(u); err != nil {
|
if err := helper.PostAuthenticate(apc.Context(), u); err != nil {
|
||||||
log.Errorf("Failed to onboard user, error: %v", err)
|
log.Errorf("Failed to onboard user, error: %v", err)
|
||||||
apc.Ctx.Redirect(http.StatusMovedPermanently, "/")
|
apc.Ctx.Redirect(http.StatusMovedPermanently, "/")
|
||||||
return
|
return
|
||||||
|
@ -21,7 +21,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
o "github.com/astaxie/beego/orm"
|
|
||||||
"github.com/beego/i18n"
|
"github.com/beego/i18n"
|
||||||
"github.com/goharbor/harbor/src/common"
|
"github.com/goharbor/harbor/src/common"
|
||||||
"github.com/goharbor/harbor/src/common/models"
|
"github.com/goharbor/harbor/src/common/models"
|
||||||
@ -32,7 +31,6 @@ import (
|
|||||||
"github.com/goharbor/harbor/src/lib"
|
"github.com/goharbor/harbor/src/lib"
|
||||||
"github.com/goharbor/harbor/src/lib/config"
|
"github.com/goharbor/harbor/src/lib/config"
|
||||||
"github.com/goharbor/harbor/src/lib/log"
|
"github.com/goharbor/harbor/src/lib/log"
|
||||||
"github.com/goharbor/harbor/src/lib/orm"
|
|
||||||
"github.com/goharbor/harbor/src/lib/q"
|
"github.com/goharbor/harbor/src/lib/q"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -97,7 +95,7 @@ func (cc *CommonController) Login() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := auth.Login(models.AuthModel{
|
user, err := auth.Login(cc.Context(), models.AuthModel{
|
||||||
Principal: principal,
|
Principal: principal,
|
||||||
Password: password,
|
Password: password,
|
||||||
})
|
})
|
||||||
@ -119,7 +117,7 @@ func (cc *CommonController) LogOut() {
|
|||||||
|
|
||||||
// UserExists checks if user exists when user input value in sign in form.
|
// UserExists checks if user exists when user input value in sign in form.
|
||||||
func (cc *CommonController) UserExists() {
|
func (cc *CommonController) UserExists() {
|
||||||
ctx := orm.NewContext(cc.Ctx.Request.Context(), o.NewOrm())
|
ctx := cc.Context()
|
||||||
flag, err := config.SelfRegistration(ctx)
|
flag, err := config.SelfRegistration(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed to get the status of self registration flag, error: %v, disabling user existence check", err)
|
log.Errorf("Failed to get the status of self registration flag, error: %v, disabling user existence check", err)
|
||||||
|
@ -29,7 +29,6 @@ import (
|
|||||||
"github.com/goharbor/harbor/src/lib/config"
|
"github.com/goharbor/harbor/src/lib/config"
|
||||||
"github.com/goharbor/harbor/src/lib/errors"
|
"github.com/goharbor/harbor/src/lib/errors"
|
||||||
"github.com/goharbor/harbor/src/lib/log"
|
"github.com/goharbor/harbor/src/lib/log"
|
||||||
"github.com/goharbor/harbor/src/lib/orm"
|
|
||||||
"github.com/goharbor/harbor/src/pkg/oidc"
|
"github.com/goharbor/harbor/src/pkg/oidc"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -49,7 +48,7 @@ type onboardReq struct {
|
|||||||
|
|
||||||
// Prepare include public code path for call request handler of OIDCController
|
// Prepare include public code path for call request handler of OIDCController
|
||||||
func (oc *OIDCController) Prepare() {
|
func (oc *OIDCController) Prepare() {
|
||||||
if mode, _ := config.AuthMode(orm.Context()); mode != common.OIDCAuth {
|
if mode, _ := config.AuthMode(oc.Context()); mode != common.OIDCAuth {
|
||||||
oc.SendPreconditionFailedError(fmt.Errorf("auth mode: %s is not OIDC based", mode))
|
oc.SendPreconditionFailedError(fmt.Errorf("auth mode: %s is not OIDC based", mode))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package ldap
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
goldap "github.com/go-ldap/ldap/v3"
|
goldap "github.com/go-ldap/ldap/v3"
|
||||||
"github.com/goharbor/harbor/src/common/models"
|
"github.com/goharbor/harbor/src/common/models"
|
||||||
"github.com/goharbor/harbor/src/core/auth"
|
"github.com/goharbor/harbor/src/core/auth"
|
||||||
@ -104,7 +105,7 @@ func (m *manager) ImportUser(ctx context.Context, sess *Session, ldapImportUsers
|
|||||||
user.Username = ldapUsers[0].Username
|
user.Username = ldapUsers[0].Username
|
||||||
user.Realname = ldapUsers[0].Realname
|
user.Realname = ldapUsers[0].Realname
|
||||||
user.Email = ldapUsers[0].Email
|
user.Email = ldapUsers[0].Email
|
||||||
err = auth.OnBoardUser(&user)
|
err = auth.OnBoardUser(ctx, &user)
|
||||||
|
|
||||||
if err != nil || user.UserID <= 0 {
|
if err != nil || user.UserID <= 0 {
|
||||||
u.UID = tempUID
|
u.UID = tempUID
|
||||||
|
@ -15,12 +15,11 @@
|
|||||||
package readonly
|
package readonly
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goharbor/harbor/src/lib/config"
|
|
||||||
lib_http "github.com/goharbor/harbor/src/lib/http"
|
|
||||||
"github.com/goharbor/harbor/src/lib/orm"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/goharbor/harbor/src/lib/config"
|
||||||
"github.com/goharbor/harbor/src/lib/errors"
|
"github.com/goharbor/harbor/src/lib/errors"
|
||||||
|
lib_http "github.com/goharbor/harbor/src/lib/http"
|
||||||
"github.com/goharbor/harbor/src/server/middleware"
|
"github.com/goharbor/harbor/src/server/middleware"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -34,7 +33,7 @@ var (
|
|||||||
// DefaultConfig default readonly config
|
// DefaultConfig default readonly config
|
||||||
DefaultConfig = Config{
|
DefaultConfig = Config{
|
||||||
ReadOnly: func(r *http.Request) bool {
|
ReadOnly: func(r *http.Request) bool {
|
||||||
return config.ReadOnly(orm.Context())
|
return config.ReadOnly(r.Context())
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,10 @@ package repoproxy
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/common/security"
|
"github.com/goharbor/harbor/src/common/security"
|
||||||
"github.com/goharbor/harbor/src/common/security/proxycachesecret"
|
"github.com/goharbor/harbor/src/common/security/proxycachesecret"
|
||||||
"github.com/goharbor/harbor/src/controller/project"
|
"github.com/goharbor/harbor/src/controller/project"
|
||||||
@ -30,9 +34,6 @@ import (
|
|||||||
proModels "github.com/goharbor/harbor/src/pkg/project/models"
|
proModels "github.com/goharbor/harbor/src/pkg/project/models"
|
||||||
"github.com/goharbor/harbor/src/pkg/reg/model"
|
"github.com/goharbor/harbor/src/pkg/reg/model"
|
||||||
"github.com/goharbor/harbor/src/server/middleware"
|
"github.com/goharbor/harbor/src/server/middleware"
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -59,7 +60,7 @@ func handleBlob(w http.ResponseWriter, r *http.Request, next http.Handler) error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !canProxy(p) || proxyCtl.UseLocalBlob(ctx, art) {
|
if !canProxy(r.Context(), p) || proxyCtl.UseLocalBlob(ctx, art) {
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -111,7 +112,7 @@ func handleManifest(w http.ResponseWriter, r *http.Request, next http.Handler) e
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !canProxy(p) {
|
if !canProxy(r.Context(), p) {
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -173,11 +174,11 @@ func proxyManifestGet(ctx context.Context, w http.ResponseWriter, ctl proxy.Cont
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func canProxy(p *proModels.Project) bool {
|
func canProxy(ctx context.Context, p *proModels.Project) bool {
|
||||||
if p.RegistryID < 1 {
|
if p.RegistryID < 1 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
reg, err := registry.Ctl.Get(orm.Context(), p.RegistryID)
|
reg, err := registry.Ctl.Get(ctx, p.RegistryID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to get registry, error:%v", err)
|
log.Errorf("failed to get registry, error:%v", err)
|
||||||
return false
|
return false
|
||||||
|
@ -26,7 +26,6 @@ import (
|
|||||||
"github.com/goharbor/harbor/src/lib/config"
|
"github.com/goharbor/harbor/src/lib/config"
|
||||||
"github.com/goharbor/harbor/src/lib/errors"
|
"github.com/goharbor/harbor/src/lib/errors"
|
||||||
"github.com/goharbor/harbor/src/lib/log"
|
"github.com/goharbor/harbor/src/lib/log"
|
||||||
"github.com/goharbor/harbor/src/lib/orm"
|
|
||||||
"github.com/goharbor/harbor/src/pkg/authproxy"
|
"github.com/goharbor/harbor/src/pkg/authproxy"
|
||||||
pkguser "github.com/goharbor/harbor/src/pkg/user"
|
pkguser "github.com/goharbor/harbor/src/pkg/user"
|
||||||
)
|
)
|
||||||
@ -51,7 +50,7 @@ func (a *authProxy) Generate(req *http.Request) security.Context {
|
|||||||
log.Errorf("user name %s doesn't meet the auth proxy name pattern", proxyUserName)
|
log.Errorf("user name %s doesn't meet the auth proxy name pattern", proxyUserName)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
httpAuthProxyConf, err := config.HTTPAuthProxySetting(orm.Context())
|
httpAuthProxyConf, err := config.HTTPAuthProxySetting(req.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to get auth proxy settings: %v", err)
|
log.Errorf("failed to get auth proxy settings: %v", err)
|
||||||
return nil
|
return nil
|
||||||
@ -68,7 +67,7 @@ func (a *authProxy) Generate(req *http.Request) security.Context {
|
|||||||
user, err := pkguser.Mgr.GetByName(req.Context(), rawUserName)
|
user, err := pkguser.Mgr.GetByName(req.Context(), rawUserName)
|
||||||
if errors.IsNotFoundErr(err) {
|
if errors.IsNotFoundErr(err) {
|
||||||
// onboard user if it's not yet onboarded.
|
// onboard user if it's not yet onboarded.
|
||||||
uid, err2 := auth.SearchAndOnBoardUser(rawUserName)
|
uid, err2 := auth.SearchAndOnBoardUser(req.Context(), rawUserName)
|
||||||
if err2 != nil {
|
if err2 != nil {
|
||||||
log.Errorf("failed to search and onboard user %s: %v", rawUserName, err)
|
log.Errorf("failed to search and onboard user %s: %v", rawUserName, err)
|
||||||
return nil
|
return nil
|
||||||
|
@ -17,8 +17,13 @@ package security
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/common"
|
"github.com/goharbor/harbor/src/common"
|
||||||
"github.com/goharbor/harbor/src/common/utils/test"
|
|
||||||
_ "github.com/goharbor/harbor/src/core/auth/authproxy"
|
_ "github.com/goharbor/harbor/src/core/auth/authproxy"
|
||||||
"github.com/goharbor/harbor/src/lib"
|
"github.com/goharbor/harbor/src/lib"
|
||||||
"github.com/goharbor/harbor/src/lib/config"
|
"github.com/goharbor/harbor/src/lib/config"
|
||||||
@ -28,17 +33,11 @@ import (
|
|||||||
_ "github.com/goharbor/harbor/src/pkg/config/inmemory"
|
_ "github.com/goharbor/harbor/src/pkg/config/inmemory"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"io/ioutil"
|
|
||||||
"k8s.io/api/authentication/v1beta1"
|
"k8s.io/api/authentication/v1beta1"
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"net/url"
|
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAuthProxy(t *testing.T) {
|
func TestAuthProxy(t *testing.T) {
|
||||||
config.Init()
|
config.Init()
|
||||||
test.InitDatabaseFromEnv()
|
|
||||||
authProxy := &authProxy{}
|
authProxy := &authProxy{}
|
||||||
|
|
||||||
server, err := newAuthProxyTestServer()
|
server, err := newAuthProxyTestServer()
|
||||||
|
@ -32,7 +32,7 @@ func (b *basicAuth) Generate(req *http.Request) security.Context {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
user, err := auth.Login(models.AuthModel{
|
user, err := auth.Login(req.Context(), models.AuthModel{
|
||||||
Principal: username,
|
Principal: username,
|
||||||
Password: password,
|
Password: password,
|
||||||
})
|
})
|
||||||
|
@ -15,11 +15,13 @@
|
|||||||
package security
|
package security
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_ "github.com/goharbor/harbor/src/core/auth/db"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
_ "github.com/goharbor/harbor/src/core/auth/db"
|
||||||
|
"github.com/goharbor/harbor/src/lib/orm"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBasicAuth(t *testing.T) {
|
func TestBasicAuth(t *testing.T) {
|
||||||
@ -27,6 +29,7 @@ func TestBasicAuth(t *testing.T) {
|
|||||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1/api/projects/", nil)
|
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1/api/projects/", nil)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
req.SetBasicAuth("admin", "Harbor12345")
|
req.SetBasicAuth("admin", "Harbor12345")
|
||||||
|
req = req.WithContext(orm.Context())
|
||||||
ctx := basicAuth.Generate(req)
|
ctx := basicAuth.Generate(req)
|
||||||
assert.NotNil(t, ctx)
|
assert.NotNil(t, ctx)
|
||||||
}
|
}
|
||||||
|
@ -15,12 +15,11 @@
|
|||||||
package security
|
package security
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/goharbor/harbor/src/lib/config"
|
|
||||||
"github.com/goharbor/harbor/src/lib/orm"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/common/security"
|
"github.com/goharbor/harbor/src/common/security"
|
||||||
"github.com/goharbor/harbor/src/lib"
|
"github.com/goharbor/harbor/src/lib"
|
||||||
|
"github.com/goharbor/harbor/src/lib/config"
|
||||||
"github.com/goharbor/harbor/src/lib/log"
|
"github.com/goharbor/harbor/src/lib/log"
|
||||||
"github.com/goharbor/harbor/src/server/middleware"
|
"github.com/goharbor/harbor/src/server/middleware"
|
||||||
)
|
)
|
||||||
@ -48,7 +47,7 @@ type generator interface {
|
|||||||
func Middleware(skippers ...middleware.Skipper) func(http.Handler) http.Handler {
|
func Middleware(skippers ...middleware.Skipper) func(http.Handler) http.Handler {
|
||||||
return middleware.New(func(w http.ResponseWriter, r *http.Request, next http.Handler) {
|
return middleware.New(func(w http.ResponseWriter, r *http.Request, next http.Handler) {
|
||||||
log := log.G(r.Context())
|
log := log.G(r.Context())
|
||||||
mode, err := config.AuthMode(orm.Context())
|
mode, err := config.AuthMode(r.Context())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
r = r.WithContext(lib.WithAuthMode(r.Context(), mode))
|
r = r.WithContext(lib.WithAuthMode(r.Context(), mode))
|
||||||
} else {
|
} else {
|
||||||
|
@ -15,13 +15,21 @@
|
|||||||
package security
|
package security
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"github.com/goharbor/harbor/src/common/security"
|
"github.com/goharbor/harbor/src/common/security"
|
||||||
|
"github.com/goharbor/harbor/src/common/utils/test"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
test.InitDatabaseFromEnv()
|
||||||
|
os.Exit(m.Run())
|
||||||
|
}
|
||||||
|
|
||||||
func TestSecurity(t *testing.T) {
|
func TestSecurity(t *testing.T) {
|
||||||
var ctx security.Context
|
var ctx security.Context
|
||||||
var exist bool
|
var exist bool
|
||||||
|
Loading…
Reference in New Issue
Block a user