Merge pull request #3870 from stonezdj/ldap_syncuser2

Sync user email in ldap #3663
This commit is contained in:
Daniel Jiang 2018-01-04 13:28:51 +08:00 committed by GitHub
commit 8e5115c832
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 170 additions and 50 deletions

View File

@ -46,7 +46,7 @@ func TestAuthModeCanBeModified(t *testing.T) {
t.Fatalf("failed to register user: %v", err)
}
defer func(id int64) {
if err := deleteUser(id); err != nil {
if err := CleanUser(id); err != nil {
t.Fatalf("failed to delete user %d: %v", id, err)
}
}(id)
@ -68,4 +68,4 @@ func TestAuthModeCanBeModified(t *testing.T) {
t.Errorf("unexpected result: %t != %t", flag, false)
}
}
}
}

View File

@ -258,9 +258,12 @@ func DeleteUser(userID int) error {
}
// ChangeUserProfile ...
func ChangeUserProfile(user models.User) error {
func ChangeUserProfile(user models.User, cols ...string) error {
o := GetOrmer()
if _, err := o.Update(&user, "Email", "Realname", "Comment"); err != nil {
if len(cols) == 0 {
cols = []string{"Email", "Realname", "Comment"}
}
if _, err := o.Update(&user, cols...); err != nil {
log.Errorf("update user failed, error: %v", err)
return err
}
@ -290,3 +293,12 @@ func OnBoardUser(u *models.User) error {
}
return nil
}
//CleanUser - Clean this user information from DB
func CleanUser(id int64) error {
if _, err := GetOrmer().QueryTable(&models.User{}).
Filter("UserID", id).Delete(); err != nil {
return err
}
return nil
}

View File

@ -39,7 +39,7 @@ func TestDeleteUser(t *testing.T) {
t.Fatalf("failed to register user: %v", err)
}
defer func(id int64) {
if err := deleteUser(id); err != nil {
if err := CleanUser(id); err != nil {
t.Fatalf("failed to delete user %d: %v", id, err)
}
}(id)
@ -88,13 +88,5 @@ func TestOnBoardUser(t *testing.T) {
err = OnBoardUser(u)
assert.Nil(err)
assert.True(u.UserID == id)
deleteUser(int64(id))
}
func deleteUser(id int64) error {
if _, err := GetOrmer().QueryTable(&models.User{}).
Filter("UserID", id).Delete(); err != nil {
return err
}
return nil
CleanUser(int64(id))
}

View File

@ -39,6 +39,34 @@ type AuthenticateHelper interface {
OnBoardUser(u *models.User) error
// Get user information from account repository
SearchUser(username string) (*models.User, error)
// Update user information after authenticate, such as Onboard or sync info etc
PostAuthenticate(u *models.User) error
}
// DefaultAuthenticateHelper - default AuthenticateHelper implementation
type DefaultAuthenticateHelper struct {
}
// Authenticate ...
func (d *DefaultAuthenticateHelper) Authenticate(m models.AuthModel) (*models.User, error) {
return nil, nil
}
// 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
// on the data record of the user
func (d *DefaultAuthenticateHelper) OnBoardUser(u *models.User) error {
return nil
}
//SearchUser - Get user information from account repository
func (d *DefaultAuthenticateHelper) SearchUser(username string) (*models.User, error) {
return nil, nil
}
//PostAuthenticate - Update user information after authenticate, such as Onboard or sync info etc
func (d *DefaultAuthenticateHelper) PostAuthenticate(u *models.User) error {
return nil
}
var registry = make(map[string]AuthenticateHelper)
@ -79,6 +107,9 @@ func Login(m models.AuthModel) (*models.User, error) {
lock.Lock(m.Principal)
time.Sleep(frozenTime)
}
authenticator.PostAuthenticate(user)
return user, err
}
@ -112,3 +143,12 @@ func SearchUser(username string) (*models.User, error) {
}
return helper.SearchUser(username)
}
// PostAuthenticate -
func PostAuthenticate(u *models.User) error {
helper, err := getHelper()
if err != nil {
return err
}
return helper.PostAuthenticate(u)
}

View File

@ -21,7 +21,9 @@ import (
)
// Auth implements Authenticator interface to authenticate user against DB.
type Auth struct{}
type Auth struct {
auth.DefaultAuthenticateHelper
}
// Authenticate calls dao to authenticate user.
func (d *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
@ -32,12 +34,6 @@ func (d *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
return u, nil
}
// OnBoardUser - Dummy implementation when auth_mod is db_auth
func (d *Auth) OnBoardUser(user *models.User) error {
//No need to create user in local database
return nil
}
// SearchUser - Check if user exist in local db
func (d *Auth) SearchUser(username string) (*models.User, error) {
var queryCondition = models.User{

View File

@ -16,6 +16,7 @@ package ldap
import (
"fmt"
"regexp"
"strings"
"github.com/vmware/harbor/src/common/dao"
@ -26,7 +27,9 @@ import (
)
// Auth implements AuthenticateHelper interface to authenticate against LDAP
type Auth struct{}
type Auth struct {
auth.DefaultAuthenticateHelper
}
// 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
@ -68,7 +71,7 @@ func (l *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
u := models.User{}
u.Username = ldapUsers[0].Username
u.Email = ldapUsers[0].Email
u.Email = strings.TrimSpace(ldapUsers[0].Email)
u.Realname = ldapUsers[0].Realname
dn := ldapUsers[0].DN
@ -78,34 +81,7 @@ func (l *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
log.Warningf("Failed to bind user, username: %s, dn: %s, error: %v", u.Username, dn, err)
return nil, nil
}
exist, err := dao.UserExists(u, "username")
if err != nil {
return nil, err
}
if exist {
currentUser, err := dao.GetUser(u)
if err != nil {
return nil, err
}
u.UserID = currentUser.UserID
u.HasAdminRole = currentUser.HasAdminRole
} else {
var user models.User
user.Username = ldapUsers[0].Username
user.Email = ldapUsers[0].Email
user.Realname = ldapUsers[0].Realname
err = auth.OnBoardUser(&user)
if err != nil || user.UserID <= 0 {
log.Errorf("Can't import user %s, error: %v", ldapUsers[0].Username, err)
return nil, fmt.Errorf("can't import user %s, error: %v", ldapUsers[0].Username, err)
}
u.UserID = user.UserID
}
return &u, nil
}
// OnBoardUser will check if a user exists in user table, if not insert the user and
@ -153,6 +129,52 @@ func (l *Auth) SearchUser(username string) (*models.User, error) {
return &user, nil
}
//PostAuthenticate -- If user exist in harbor DB, sync email address, if not exist, call OnBoardUser
func (l *Auth) PostAuthenticate(u *models.User) error {
exist, err := dao.UserExists(*u, "username")
if err != nil {
return err
}
if exist {
queryCondition := models.User{
Username: u.Username,
}
dbUser, err := dao.GetUser(queryCondition)
if err != nil {
return err
}
if dbUser == nil {
fmt.Printf("User not found in DB %+v", u)
return nil
}
u.UserID = dbUser.UserID
u.HasAdminRole = dbUser.HasAdminRole
if dbUser.Email != u.Email {
Re := regexp.MustCompile(`^[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,4}$`)
if !Re.MatchString(u.Email) {
log.Debugf("Not a valid email address: %v, skip to sync", u.Email)
} else {
dao.ChangeUserProfile(*u, "Email")
}
u.Email = dbUser.Email
}
return nil
}
err = auth.OnBoardUser(u)
if err != nil {
return err
}
if u.UserID <= 0 {
return fmt.Errorf("Can not OnBoardUser %v", u)
}
return nil
}
func init() {
auth.Register("ldap_auth", &Auth{})
}

View File

@ -19,6 +19,7 @@ import (
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/vmware/harbor/src/common"
"github.com/vmware/harbor/src/common/dao"
"github.com/vmware/harbor/src/common/models"
@ -204,3 +205,59 @@ func TestAuthenticateHelperSearchUser(t *testing.T) {
t.Error("Failed to search user test")
}
}
func TestPostAuthentication(t *testing.T) {
assert := assert.New(t)
user1 := &models.User{
Username: "test003",
Email: "test003@vmware.com",
Realname: "test003",
}
queryCondition := models.User{
Username: "test003",
Realname: "test003",
}
err := auth.OnBoardUser(user1)
assert.Nil(err)
user2 := &models.User{
Username: "test003",
Email: "234invalidmail@@@@@",
}
auth.PostAuthenticate(user2)
dbUser, err := dao.GetUser(queryCondition)
if err != nil {
t.Fatalf("Failed to get user, error %v", err)
}
assert.EqualValues("test003@vmware.com", dbUser.Email)
user3 := &models.User{
Username: "test003",
}
auth.PostAuthenticate(user3)
dbUser, err = dao.GetUser(queryCondition)
if err != nil {
t.Fatalf("Failed to get user, error %v", err)
}
assert.EqualValues("test003@vmware.com", dbUser.Email)
user4 := &models.User{
Username: "test003",
Email: "test003@example.com",
}
auth.PostAuthenticate(user4)
dbUser, err = dao.GetUser(queryCondition)
if err != nil {
t.Fatalf("Failed to get user, error %v", err)
}
assert.EqualValues("test003@example.com", dbUser.Email)
dao.CleanUser(int64(dbUser.UserID))
}

View File

@ -48,6 +48,7 @@ func CreateClient() (uaa.Client, error) {
type Auth struct {
sync.Mutex
client uaa.Client
auth.DefaultAuthenticateHelper
}
//Authenticate ...