Put user info into session (#4885)

Fix the following issues.
1) GroupList is not found in SecurityContext user info
2) Retrieve multiple memberof information from LDAP.
3) If user is in two groups with guest, administrator role separately, display the max privilege role.
This commit is contained in:
stone 2018-05-17 16:23:51 +08:00 committed by Daniel Jiang
parent 6a7ba4609f
commit d3930ae17c
6 changed files with 68 additions and 21 deletions

View File

@ -292,8 +292,10 @@ func GetRolesByLDAPGroup(projectID int64, groupDNCondition string) ([]int, error
return roles, nil
}
o := GetOrmer()
//Because an LDAP user can be memberof multiple groups,
//the role is in descent order (1-admin, 2-developer, 3-guest), use min to select the max privilege role.
sql := fmt.Sprintf(
`select pm.role from project_member pm
`select min(pm.role) from project_member pm
left join user_group ug on pm.entity_type = 'g' and pm.entity_id = ug.id
where ug.ldap_group_dn in ( %s ) and pm.project_id = ? `,
groupDNCondition)
@ -302,5 +304,9 @@ func GetRolesByLDAPGroup(projectID int64, groupDNCondition string) ([]int, error
log.Warningf("Error in GetRolesByLDAPGroup, error: %v", err)
return nil, err
}
//If there is no row selected, the min returns an empty row, to avoid return 0 as role
if len(roles) == 1 && roles[0] == 0 {
return []int{}, nil
}
return roles, nil
}

View File

@ -202,7 +202,10 @@ func (session *Session) SearchUser(username string) ([]models.LdapUser, error) {
case "email":
u.Email = val
case "memberof":
groupDNList = append(groupDNList, val)
for _, dnItem := range attr.Values {
groupDNList = append(groupDNList, strings.TrimSpace(dnItem))
log.Debugf("Found memberof %v", dnItem)
}
}
u.GroupDNList = groupDNList
}

View File

@ -59,6 +59,8 @@ func (l *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
ldapUsers, err := ldapSession.SearchUser(p)
log.Debugf("Found ldap user %+v", ldapUsers[0])
if err != nil {
log.Warningf("ldap search fail: %v", err)
return nil, err

View File

@ -69,10 +69,7 @@ func (cc *CommonController) Login() {
if user == nil {
cc.CustomAbort(http.StatusUnauthorized, "")
}
cc.SetSession("userId", user.UserID)
cc.SetSession("username", user.Username)
cc.SetSession("isSysAdmin", user.HasAdminRole)
cc.SetSession("user", *user)
}
// LogOut Habor UI

View File

@ -215,7 +215,6 @@ func (b *basicAuthReqCtxModifier) Modify(ctx *beegoctx.Context) bool {
pm := config.GlobalProjectMgr
log.Debug("creating local database security context...")
securCtx := local.NewSecurityContext(user, pm)
setSecurCtxAndPM(ctx.Request, securCtx, pm)
return true
}
@ -223,24 +222,25 @@ func (b *basicAuthReqCtxModifier) Modify(ctx *beegoctx.Context) bool {
type sessionReqCtxModifier struct{}
func (s *sessionReqCtxModifier) Modify(ctx *beegoctx.Context) bool {
username := ctx.Input.Session("username")
if username == nil {
var user models.User
userInterface := ctx.Input.Session("user")
if userInterface == nil {
log.Debug("can not get user information from session")
return false
}
log.Debug("got user information from session")
user := &models.User{
Username: username.(string),
user, ok := userInterface.(models.User)
if !ok {
log.Info("can not get user information from session")
return false
}
isSysAdmin := ctx.Input.Session("isSysAdmin")
if isSysAdmin != nil && isSysAdmin.(bool) {
user.HasAdminRole = true
}
log.Debug("Getting user %+v", user)
log.Debug("using local database project manager")
pm := config.GlobalProjectMgr
log.Debug("creating local database security context...")
securCtx := local.NewSecurityContext(user, pm)
securCtx := local.NewSecurityContext(&user, pm)
setSecurCtxAndPM(ctx.Request, securCtx, pm)

View File

@ -30,6 +30,7 @@ import (
"github.com/astaxie/beego/session"
"github.com/stretchr/testify/assert"
"github.com/vmware/harbor/src/common/dao"
"github.com/vmware/harbor/src/common/models"
commonsecret "github.com/vmware/harbor/src/common/secret"
"github.com/vmware/harbor/src/common/security"
"github.com/vmware/harbor/src/common/security/local"
@ -146,6 +147,12 @@ func TestBasicAuthReqCtxModifier(t *testing.T) {
}
func TestSessionReqCtxModifier(t *testing.T) {
user := models.User{
Username: "admin",
UserID: 1,
Email: "admin@example.com",
HasAdminRole: true,
}
req, err := http.NewRequest(http.MethodGet,
"http://127.0.0.1/api/projects/", nil)
if err != nil {
@ -155,10 +162,7 @@ func TestSessionReqCtxModifier(t *testing.T) {
if err != nil {
t.Fatalf("failed to create session store: %v", err)
}
if err = store.Set("username", "admin"); err != nil {
t.Fatalf("failed to set session: %v", err)
}
if err = store.Set("isSysAdmin", true); err != nil {
if err = store.Set("user", user); err != nil {
t.Fatalf("failed to set session: %v", err)
}
@ -184,6 +188,41 @@ func TestSessionReqCtxModifier(t *testing.T) {
assert.Equal(t, "admin", s.GetUsername())
assert.True(t, s.IsSysAdmin())
assert.NotNil(t, projectManager(ctx))
}
func TestSessionReqCtxModifierFailed(t *testing.T) {
user := "admin"
req, err := http.NewRequest(http.MethodGet,
"http://127.0.0.1/api/projects/", nil)
if err != nil {
t.Fatalf("failed to create request: %v", req)
}
store, err := beego.GlobalSessions.SessionStart(httptest.NewRecorder(), req)
if err != nil {
t.Fatalf("failed to create session store: %v", err)
}
if err = store.Set("user", user); err != nil {
t.Fatalf("failed to set session: %v", err)
}
req, err = http.NewRequest(http.MethodGet,
"http://127.0.0.1/api/projects/", nil)
if err != nil {
t.Fatalf("failed to create request: %v", req)
}
addSessionIDToCookie(req, store.SessionID())
ctx, err := newContext(req)
if err != nil {
t.Fatalf("failed to crate context: %v", err)
}
modifier := &sessionReqCtxModifier{}
modified := modifier.Modify(ctx)
assert.False(t, modified)
}
// TODO add test case