mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-19 10:46:58 +08:00
fix: misc bugfixes.
This commit is contained in:
@@ -47,13 +47,10 @@ type SLDAPIdpConfigOptions struct {
|
||||
Url string `json:"url,omitempty" help:"LDAP server URL" required:"true"`
|
||||
Suffix string `json:"suffix,omitempty" required:"true"`
|
||||
QueryScope string `json:"query_scope,omitempty" help:"Query scope, either one or sub" choices:"one|sub"`
|
||||
// PageSize int `json:"page_size,omitzero" help:"Page size, default 20" default:"20"`
|
||||
|
||||
User string `json:"user,omitempty"`
|
||||
Password string `json:"password,omitempty"`
|
||||
|
||||
AutoCreateProject bool `json:"auto_create_project,omitfalse"`
|
||||
ImportDomain bool `json:"import_domain,omitfalse"`
|
||||
|
||||
DomainTreeDN string `json:"domain_tree_dn,omitempty" help:"Domain tree root node dn(distinguished name)"`
|
||||
DomainFilter string `json:"domain_filter,omitempty"`
|
||||
DomainObjectclass string `json:"domain_objectclass,omitempty"`
|
||||
|
||||
@@ -59,6 +59,7 @@ const (
|
||||
IdentityDriverStatusConnected = "connected"
|
||||
IdentityDriverStatusDisconnected = "disconnected"
|
||||
IdentityDriverStatusDeleting = "deleting"
|
||||
IdentityDriverStatusDeleteFailed = "delete_fail"
|
||||
|
||||
IdentityProviderSyncLocal = "local"
|
||||
IdentityProviderSyncFull = "full"
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
"yunion.io/x/onecloud/pkg/util/rbacutils"
|
||||
"yunion.io/x/onecloud/pkg/util/stringutils2"
|
||||
)
|
||||
|
||||
func FetchJointByIds(manager IJointModelManager, masterId, slaveId string, query jsonutils.JSONObject) (IJointModel, error) {
|
||||
@@ -127,6 +128,9 @@ func FetchByName(manager IModelManager, userCred mcclient.IIdentityProvider, idS
|
||||
}
|
||||
|
||||
func FetchByIdOrName(manager IModelManager, userCred mcclient.IIdentityProvider, idStr string) (IModel, error) {
|
||||
if stringutils2.IsUtf8(idStr) {
|
||||
return FetchByName(manager, userCred, idStr)
|
||||
}
|
||||
obj, err := FetchById(manager, idStr)
|
||||
if err == sql.ErrNoRows {
|
||||
return FetchByName(manager, userCred, idStr)
|
||||
|
||||
@@ -32,6 +32,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/mcclient/auth"
|
||||
"yunion.io/x/onecloud/pkg/mcclient/modules"
|
||||
"yunion.io/x/onecloud/pkg/util/httputils"
|
||||
"yunion.io/x/onecloud/pkg/util/stringutils2"
|
||||
)
|
||||
|
||||
type STenantCacheManager struct {
|
||||
@@ -123,10 +124,14 @@ func (manager *STenantCacheManager) fetchTenant(ctx context.Context, idStr strin
|
||||
|
||||
func (manager *STenantCacheManager) FetchTenantByIdOrName(ctx context.Context, idStr string) (*STenant, error) {
|
||||
return manager.fetchTenant(ctx, idStr, false, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
|
||||
return q.Filter(sqlchemy.OR(
|
||||
sqlchemy.Equals(q.Field("id"), idStr),
|
||||
sqlchemy.Equals(q.Field("name"), idStr),
|
||||
))
|
||||
if stringutils2.IsUtf8(idStr) {
|
||||
return q.Equals("name", idStr)
|
||||
} else {
|
||||
return q.Filter(sqlchemy.OR(
|
||||
sqlchemy.Equals(q.Field("id"), idStr),
|
||||
sqlchemy.Equals(q.Field("name"), idStr),
|
||||
))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -167,10 +172,14 @@ func (manager *STenantCacheManager) fetchTenantFromKeystone(ctx context.Context,
|
||||
|
||||
func (manager *STenantCacheManager) FetchDomainByIdOrName(ctx context.Context, idStr string) (*STenant, error) {
|
||||
return manager.fetchTenant(ctx, idStr, true, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
|
||||
return q.Filter(sqlchemy.OR(
|
||||
sqlchemy.Equals(q.Field("id"), idStr),
|
||||
sqlchemy.Equals(q.Field("name"), idStr),
|
||||
))
|
||||
if stringutils2.IsUtf8(idStr) {
|
||||
return q.Equals("name", idStr)
|
||||
} else {
|
||||
return q.Filter(sqlchemy.OR(
|
||||
sqlchemy.Equals(q.Field("id"), idStr),
|
||||
sqlchemy.Equals(q.Field("name"), idStr),
|
||||
))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -34,12 +34,12 @@ func GetDriverClass(drv string) IIdentityBackendClass {
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetDriver(driver string, idpId, idpName, template string, conf api.TIdentityProviderConfigs) (IIdentityBackend, error) {
|
||||
func GetDriver(driver string, idpId, idpName, template, targetDomainId string, autoCreateProject bool, conf api.TIdentityProviderConfigs) (IIdentityBackend, error) {
|
||||
drvCls := GetDriverClass(driver)
|
||||
if drvCls == nil {
|
||||
return nil, ErrNoSuchDriver
|
||||
}
|
||||
return drvCls.NewDriver(idpId, idpName, template, conf)
|
||||
return drvCls.NewDriver(idpId, idpName, template, targetDomainId, autoCreateProject, conf)
|
||||
}
|
||||
|
||||
type SBaseIdentityDriver struct {
|
||||
@@ -49,17 +49,22 @@ type SBaseIdentityDriver struct {
|
||||
IdpId string
|
||||
IdpName string
|
||||
Template string
|
||||
|
||||
TargetDomainId string
|
||||
AutoCreateProject bool
|
||||
}
|
||||
|
||||
func (base *SBaseIdentityDriver) IIdentityBackend() IIdentityBackend {
|
||||
return base.GetVirtualObject().(IIdentityBackend)
|
||||
}
|
||||
|
||||
func NewBaseIdentityDriver(idpId, idpName, template string, conf api.TIdentityProviderConfigs) (SBaseIdentityDriver, error) {
|
||||
func NewBaseIdentityDriver(idpId, idpName, template, targetDomainId string, autoCreateProject bool, conf api.TIdentityProviderConfigs) (SBaseIdentityDriver, error) {
|
||||
drv := SBaseIdentityDriver{}
|
||||
drv.IdpId = idpId
|
||||
drv.IdpName = idpName
|
||||
drv.Template = template
|
||||
drv.TargetDomainId = targetDomainId
|
||||
drv.AutoCreateProject = autoCreateProject
|
||||
drv.Config = conf
|
||||
return drv, nil
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ type IIdentityBackendClass interface {
|
||||
SingletonInstance() bool
|
||||
SyncMethod() string
|
||||
Name() string
|
||||
NewDriver(idpId, idpName, template string, conf api.TIdentityProviderConfigs) (IIdentityBackend, error)
|
||||
NewDriver(idpId, idpName, template, targetDomainId string, autoCreateProject bool, conf api.TIdentityProviderConfigs) (IIdentityBackend, error)
|
||||
}
|
||||
|
||||
type IIdentityBackend interface {
|
||||
|
||||
@@ -29,8 +29,8 @@ func (self *SLDAPDriverClass) SyncMethod() string {
|
||||
return api.IdentityProviderSyncFull
|
||||
}
|
||||
|
||||
func (self *SLDAPDriverClass) NewDriver(idpId, idpName, template string, conf api.TIdentityProviderConfigs) (driver.IIdentityBackend, error) {
|
||||
return NewLDAPDriver(idpId, idpName, template, conf)
|
||||
func (self *SLDAPDriverClass) NewDriver(idpId, idpName, template, targetDomainId string, autoCreateProject bool, conf api.TIdentityProviderConfigs) (driver.IIdentityBackend, error) {
|
||||
return NewLDAPDriver(idpId, idpName, template, targetDomainId, autoCreateProject, conf)
|
||||
}
|
||||
|
||||
func (self *SLDAPDriverClass) Name() string {
|
||||
|
||||
@@ -21,10 +21,9 @@ import (
|
||||
|
||||
"gopkg.in/ldap.v3"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/identity"
|
||||
@@ -40,8 +39,8 @@ type SLDAPDriver struct {
|
||||
ldapConfig *api.SLDAPIdpConfigOptions
|
||||
}
|
||||
|
||||
func NewLDAPDriver(idpId, idpName, template string, conf api.TIdentityProviderConfigs) (driver.IIdentityBackend, error) {
|
||||
base, err := driver.NewBaseIdentityDriver(idpId, idpName, template, conf)
|
||||
func NewLDAPDriver(idpId, idpName, template, targetDomainId string, autoCreateProject bool, conf api.TIdentityProviderConfigs) (driver.IIdentityBackend, error) {
|
||||
base, err := driver.NewBaseIdentityDriver(idpId, idpName, template, targetDomainId, autoCreateProject, conf)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "NewBaseIdentityDriver")
|
||||
}
|
||||
@@ -242,12 +241,20 @@ func (self *SLDAPDriver) Authenticate(ctx context.Context, ident mcclient.SAuthe
|
||||
}
|
||||
|
||||
var userTreeDN string
|
||||
if self.ldapConfig.ImportDomain {
|
||||
if len(self.ldapConfig.DomainTreeDN) > 0 {
|
||||
// import domains
|
||||
idMap, err := models.IdmappingManager.FetchEntity(usrExt.DomainId, api.IdMappingEntityDomain)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "IdmappingManager.FetchEntity for domain")
|
||||
}
|
||||
userTreeDN = idMap.IdpEntityId
|
||||
entries, err := self.searchDomainEntries(cli, idMap.IdpEntityId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "self.searchDomainEntries")
|
||||
}
|
||||
if len(entries) == 0 {
|
||||
return nil, errors.Error("fail to find domain DN")
|
||||
}
|
||||
userTreeDN = entries[0].DN
|
||||
} else {
|
||||
userTreeDN = self.getUserTreeDN()
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/ldap.v3"
|
||||
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/tristate"
|
||||
@@ -46,7 +48,7 @@ func (self *SLDAPDriver) Sync(ctx context.Context) error {
|
||||
}
|
||||
defer cli.Close()
|
||||
|
||||
if self.ldapConfig.ImportDomain {
|
||||
if len(self.ldapConfig.DomainTreeDN) > 0 {
|
||||
return self.syncDomains(ctx, cli)
|
||||
} else {
|
||||
return self.syncSingleDomain(ctx, cli)
|
||||
@@ -54,10 +56,25 @@ func (self *SLDAPDriver) Sync(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (self *SLDAPDriver) syncSingleDomain(ctx context.Context, cli *ldaputils.SLDAPClient) error {
|
||||
domainInfo := SDomainInfo{DN: self.ldapConfig.Suffix, Id: api.DefaultRemoteDomainId, Name: self.IdpName}
|
||||
domain, err := self.syncDomainInfo(ctx, domainInfo)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "syncDomainInfo")
|
||||
var domain *models.SDomain
|
||||
if len(self.TargetDomainId) > 0 {
|
||||
targetDomain, err := models.DomainManager.FetchDomainById(self.TargetDomainId)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return errors.Wrap(err, "models.DomainManager.FetchDomainById")
|
||||
}
|
||||
if targetDomain == nil {
|
||||
log.Warningln("target domain not exist!")
|
||||
} else {
|
||||
domain = targetDomain
|
||||
}
|
||||
}
|
||||
if domain == nil {
|
||||
domainInfo := SDomainInfo{DN: self.ldapConfig.Suffix, Id: api.DefaultRemoteDomainId, Name: self.IdpName}
|
||||
newDomain, err := self.syncDomainInfo(ctx, domainInfo)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "syncDomainInfo")
|
||||
}
|
||||
domain = newDomain
|
||||
}
|
||||
userIdMap, err := self.syncUsers(ctx, cli, domain.Id, self.getUserTreeDN())
|
||||
if err != nil {
|
||||
@@ -70,14 +87,22 @@ func (self *SLDAPDriver) syncSingleDomain(ctx context.Context, cli *ldaputils.SL
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *SLDAPDriver) syncDomains(ctx context.Context, cli *ldaputils.SLDAPClient) error {
|
||||
entries, err := cli.Search(self.getDomainTreeDN(),
|
||||
func (self *SLDAPDriver) searchDomainEntries(cli *ldaputils.SLDAPClient, domainid string) ([]*ldap.Entry, error) {
|
||||
attrMap := make(map[string]string)
|
||||
if len(domainid) > 0 {
|
||||
attrMap[self.ldapConfig.DomainIdAttribute] = domainid
|
||||
}
|
||||
return cli.Search(self.getDomainTreeDN(),
|
||||
self.ldapConfig.DomainObjectclass,
|
||||
nil,
|
||||
attrMap,
|
||||
self.ldapConfig.DomainFilter,
|
||||
self.domainAttributeList(),
|
||||
self.domainQueryScope(),
|
||||
)
|
||||
}
|
||||
|
||||
func (self *SLDAPDriver) syncDomains(ctx context.Context, cli *ldaputils.SLDAPClient) error {
|
||||
entries, err := self.searchDomainEntries(cli, "")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "searchLDAP")
|
||||
}
|
||||
@@ -99,7 +124,7 @@ func (self *SLDAPDriver) syncDomains(ctx context.Context, cli *ldaputils.SLDAPCl
|
||||
}
|
||||
}
|
||||
// remove any obsolete domain Id_mappings
|
||||
err = models.IdmappingManager.DeleteAny(self.IdpId, api.IdMappingEntityDomain, domainLocalIds)
|
||||
err = models.IdmappingManager.DeleteAny(self.IdpId, api.IdMappingEntityDomain, domainLocalIds, nil)
|
||||
if err != nil {
|
||||
log.Errorf("delete remvoed remote domain fail %s", err)
|
||||
}
|
||||
@@ -155,7 +180,7 @@ func (self *SLDAPDriver) syncDomainInfo(ctx context.Context, info SDomainInfo) (
|
||||
return nil, errors.Wrap(err, "insert")
|
||||
}
|
||||
|
||||
if self.ldapConfig.AutoCreateProject {
|
||||
if self.AutoCreateProject {
|
||||
project := &models.SProject{}
|
||||
project.SetModelManager(models.ProjectManager, project)
|
||||
projectName := models.NormalizeProjectName(fmt.Sprintf("%s_default_project", info.Name))
|
||||
@@ -205,9 +230,15 @@ func (self *SLDAPDriver) syncUsers(ctx context.Context, cli *ldaputils.SLDAPClie
|
||||
userIdMap[userInfo.DN] = userId
|
||||
}
|
||||
}
|
||||
err = models.IdmappingManager.DeleteAny(self.IdpId, api.IdMappingEntityUser, userLocalIds)
|
||||
deleteUsrIds, err := models.UserManager.FetchUserLocalIdsInDomain(domainId, userLocalIds)
|
||||
if err != nil {
|
||||
log.Errorf("delete removed remote user fail %s", err)
|
||||
return nil, errors.Wrap(err, "models.UserManager.FetchUserIdsInDomain")
|
||||
}
|
||||
if len(deleteUsrIds) > 0 {
|
||||
err = models.IdmappingManager.DeleteAny(self.IdpId, api.IdMappingEntityUser, nil, deleteUsrIds)
|
||||
if err != nil {
|
||||
log.Errorf("delete removed remote user fail %s", err)
|
||||
}
|
||||
}
|
||||
return userIdMap, nil
|
||||
}
|
||||
@@ -272,6 +303,8 @@ func (self *SLDAPDriver) syncUserDB(ctx context.Context, ui SUserInfo, domainId
|
||||
return "", errors.Wrap(err, "models.IdmappingManager.RegisterIdMap")
|
||||
}
|
||||
|
||||
log.Debugf("syncUserDB: %s", userId)
|
||||
|
||||
// insert nonlocal user
|
||||
err = registerNonlocalUser(ctx, ui, userId, domainId)
|
||||
if err != nil {
|
||||
@@ -301,9 +334,15 @@ func (self *SLDAPDriver) syncGroups(ctx context.Context, cli *ldaputils.SLDAPCli
|
||||
return errors.Wrap(err, "syncGroupDB")
|
||||
}
|
||||
}
|
||||
err = models.IdmappingManager.DeleteAny(self.IdpId, api.IdMappingEntityGroup, groupLocalIds)
|
||||
deleteGroupIds, err := models.GroupManager.FetchGroupLocalIdsInDomain(domainId, groupLocalIds)
|
||||
if err != nil {
|
||||
log.Errorf("delete removed remote group fail %s", err)
|
||||
return errors.Wrap(err, "models.GroupManager.FetchGroupIdsInDomain")
|
||||
}
|
||||
if len(groupLocalIds) > 0 {
|
||||
err = models.IdmappingManager.DeleteAny(self.IdpId, api.IdMappingEntityGroup, nil, deleteGroupIds)
|
||||
if err != nil {
|
||||
log.Errorf("delete removed remote group fail %s", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -20,8 +20,6 @@ import (
|
||||
|
||||
var (
|
||||
MicrosoftActiveDirectorySingleDomainTemplate = api.SLDAPIdpConfigOptions{
|
||||
ImportDomain: false,
|
||||
AutoCreateProject: true,
|
||||
UserObjectclass: "organizationalPerson",
|
||||
UserIdAttribute: "sAMAccountName",
|
||||
UserNameAttribute: "sAMAccountName",
|
||||
@@ -44,8 +42,6 @@ var (
|
||||
}
|
||||
|
||||
MicrosoftActiveDirectoryMultipleDomainTemplate = api.SLDAPIdpConfigOptions{
|
||||
ImportDomain: true,
|
||||
AutoCreateProject: true,
|
||||
DomainObjectclass: "organizationalUnit",
|
||||
DomainIdAttribute: "objectGUID",
|
||||
DomainNameAttribute: "name",
|
||||
@@ -72,8 +68,6 @@ var (
|
||||
}
|
||||
|
||||
OpenLdapSingleDomainTemplate = api.SLDAPIdpConfigOptions{
|
||||
ImportDomain: false,
|
||||
AutoCreateProject: true,
|
||||
UserObjectclass: "person",
|
||||
UserIdAttribute: "uid",
|
||||
UserNameAttribute: "uid",
|
||||
|
||||
@@ -29,8 +29,8 @@ func (self *SSQLDriverClass) SyncMethod() string {
|
||||
return api.IdentityProviderSyncLocal
|
||||
}
|
||||
|
||||
func (self *SSQLDriverClass) NewDriver(idpId, idpName, template string, conf api.TIdentityProviderConfigs) (driver.IIdentityBackend, error) {
|
||||
return NewSQLDriver(idpId, idpName, template, conf)
|
||||
func (self *SSQLDriverClass) NewDriver(idpId, idpName, template, targetDomainId string, autoCreateProject bool, conf api.TIdentityProviderConfigs) (driver.IIdentityBackend, error) {
|
||||
return NewSQLDriver(idpId, idpName, template, targetDomainId, autoCreateProject, conf)
|
||||
}
|
||||
|
||||
func (self *SSQLDriverClass) Name() string {
|
||||
|
||||
@@ -29,8 +29,8 @@ type SSQLDriver struct {
|
||||
driver.SBaseIdentityDriver
|
||||
}
|
||||
|
||||
func NewSQLDriver(idpId, idpName, template string, conf api.TIdentityProviderConfigs) (driver.IIdentityBackend, error) {
|
||||
base, err := driver.NewBaseIdentityDriver(idpId, idpName, template, conf)
|
||||
func NewSQLDriver(idpId, idpName, template, targetDomainId string, autoCreateProject bool, conf api.TIdentityProviderConfigs) (driver.IIdentityBackend, error) {
|
||||
base, err := driver.NewBaseIdentityDriver(idpId, idpName, template, targetDomainId, autoCreateProject, conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -153,10 +153,14 @@ func (manager *SDomainManager) FetchDomainByIdOrName(domain string) (*SDomain, e
|
||||
return nil, err
|
||||
}
|
||||
q := manager.Query().NotEquals("id", api.KeystoneDomainRoot)
|
||||
q = q.Filter(sqlchemy.OR(
|
||||
sqlchemy.Equals(q.Field("id"), domain),
|
||||
sqlchemy.Equals(q.Field("name"), domain),
|
||||
))
|
||||
if stringutils2.IsUtf8(domain) {
|
||||
q = q.Equals("name", domain)
|
||||
} else {
|
||||
q = q.Filter(sqlchemy.OR(
|
||||
sqlchemy.Equals(q.Field("id"), domain),
|
||||
sqlchemy.Equals(q.Field("name"), domain),
|
||||
))
|
||||
}
|
||||
err = q.First(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -205,6 +209,11 @@ func (domain *SDomain) GetGroupCount() (int, error) {
|
||||
return q.CountWithError()
|
||||
}
|
||||
|
||||
func (domain *SDomain) GetIdpCount() (int, error) {
|
||||
q := IdentityProviderManager.Query().Equals("target_domain_id", domain.Id)
|
||||
return q.CountWithError()
|
||||
}
|
||||
|
||||
func (domain *SDomain) ValidatePurgeCondition(ctx context.Context) error {
|
||||
if domain.Enabled.IsTrue() {
|
||||
return httperrors.NewInvalidStatusError("domain is enabled")
|
||||
@@ -301,6 +310,12 @@ func domainExtra(domain *SDomain, extra *jsonutils.JSONDict) *jsonutils.JSONDict
|
||||
extra.Add(jsonutils.NewInt(int64(grpCnt)), "group_count")
|
||||
prjCnt, _ := domain.GetProjectCount()
|
||||
extra.Add(jsonutils.NewInt(int64(prjCnt)), "project_count")
|
||||
roleCnt, _ := domain.GetRoleCount()
|
||||
extra.Add(jsonutils.NewInt(int64(roleCnt)), "role_count")
|
||||
policyCnt, _ := domain.GetPolicyCount()
|
||||
extra.Add(jsonutils.NewInt(int64(policyCnt)), "policy_count")
|
||||
idpCnt, _ := domain.GetIdpCount()
|
||||
extra.Add(jsonutils.NewInt(int64(idpCnt)), "idp_count")
|
||||
return extra
|
||||
}
|
||||
|
||||
|
||||
@@ -28,19 +28,20 @@ import (
|
||||
|
||||
func expandIdpAttributes(rows []*jsonutils.JSONDict, objs []db.IModel, fields stringutils2.SSortedStrings, entType string) []*jsonutils.JSONDict {
|
||||
if len(fields) == 0 || fields.Contains("idp_id") || fields.Contains("idp") || fields.Contains("idp_entity_id") || fields.Contains("idp_driver") {
|
||||
log.Debugf("objs %d", len(objs))
|
||||
idList := make([]string, len(objs))
|
||||
for i := range objs {
|
||||
idList = append(idList, objs[i].GetId())
|
||||
idList[i] = objs[i].GetId()
|
||||
}
|
||||
idps, err := fetchIdmappings(idList, entType)
|
||||
if err == nil && idps != nil {
|
||||
for i := range rows {
|
||||
if idp, ok := idps[objs[i].GetId()]; ok {
|
||||
if len(fields) == 0 || fields.Contains("idp_id") {
|
||||
rows[i].Set("idp_id", jsonutils.NewString(idp.Id))
|
||||
rows[i].Set("idp_id", jsonutils.NewString(idp.IdpId))
|
||||
}
|
||||
if len(fields) == 0 || fields.Contains("idp") {
|
||||
rows[i].Set("idp", jsonutils.NewString(idp.Name))
|
||||
rows[i].Set("idp", jsonutils.NewString(idp.IdpName))
|
||||
}
|
||||
if len(fields) == 0 || fields.Contains("idp_entity_id") {
|
||||
rows[i].Set("idp_entity_id", jsonutils.NewString(idp.EntityId))
|
||||
@@ -58,8 +59,8 @@ func expandIdpAttributes(rows []*jsonutils.JSONDict, objs []db.IModel, fields st
|
||||
}
|
||||
|
||||
type sIdpInfo struct {
|
||||
Id string
|
||||
Name string
|
||||
IdpId string
|
||||
IdpName string
|
||||
EntityId string
|
||||
Driver string
|
||||
PublicId string
|
||||
@@ -69,13 +70,13 @@ func fetchIdmappings(idList []string, resType string) (map[string]sIdpInfo, erro
|
||||
idmappings := IdmappingManager.Query().SubQuery()
|
||||
idps := IdentityProviderManager.Query().SubQuery()
|
||||
|
||||
q := idmappings.Query(idmappings.Field("domain_id", "id"),
|
||||
q := idmappings.Query(idmappings.Field("domain_id", "idp_id"),
|
||||
idmappings.Field("local_id", "entity_id"),
|
||||
idps.Field("name"),
|
||||
idps.Field("name", "idp_name"),
|
||||
idps.Field("driver"),
|
||||
idmappings.Field("public_id"),
|
||||
).Join(idps, sqlchemy.Equals(idps.Field("id"),
|
||||
idmappings.Field("domain_id")))
|
||||
)
|
||||
q = q.Join(idps, sqlchemy.Equals(idps.Field("id"), idmappings.Field("domain_id")))
|
||||
q = q.Filter(sqlchemy.In(idmappings.Field("public_id"), idList))
|
||||
q = q.Filter(sqlchemy.Equals(idmappings.Field("entity_type"), resType))
|
||||
|
||||
|
||||
@@ -274,3 +274,7 @@ func (manager *SGroupManager) FetchCustomizeColumns(ctx context.Context, userCre
|
||||
rows := manager.SIdentityBaseResourceManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields)
|
||||
return expandIdpAttributes(rows, objs, fields, api.IdMappingEntityGroup)
|
||||
}
|
||||
|
||||
func (manager *SGroupManager) FetchGroupLocalIdsInDomain(domainId string, excludes []string) ([]string, error) {
|
||||
return fetchLocalIdsInDomain(manager, domainId, excludes)
|
||||
}
|
||||
|
||||
@@ -125,10 +125,10 @@ func (manager *SIdmappingManager) FetchEntity(idStr string, entType string) (*SI
|
||||
}
|
||||
|
||||
func (manager *SIdmappingManager) deleteByIdpId(idpId string) error {
|
||||
return manager.DeleteAny(idpId, "", nil)
|
||||
return manager.DeleteAny(idpId, "", nil, nil)
|
||||
}
|
||||
|
||||
func (manager *SIdmappingManager) DeleteAny(idpId string, entityType string, excludeLocalIds []string) error {
|
||||
func (manager *SIdmappingManager) DeleteAny(idpId string, entityType string, excludeLocalIds []string, includeLocalIds []string) error {
|
||||
q := manager.Query().Equals("domain_id", idpId)
|
||||
if len(entityType) > 0 {
|
||||
q = q.Equals("entity_type", entityType)
|
||||
@@ -136,6 +136,9 @@ func (manager *SIdmappingManager) DeleteAny(idpId string, entityType string, exc
|
||||
if len(excludeLocalIds) > 0 {
|
||||
q = q.NotIn("local_id", excludeLocalIds)
|
||||
}
|
||||
if len(includeLocalIds) > 0 {
|
||||
q = q.In("local_id", includeLocalIds)
|
||||
}
|
||||
idmappings := make([]SIdmapping, 0)
|
||||
err := db.FetchModelObjects(manager, q, &idmappings)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
|
||||
@@ -19,10 +19,10 @@ import (
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/tristate"
|
||||
"yunion.io/x/sqlchemy"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/identity"
|
||||
@@ -73,6 +73,10 @@ type SIdentityProvider struct {
|
||||
Driver string `width:"32" charset:"ascii" nullable:"false" list:"admin" create:"admin_required"`
|
||||
Template string `width:"32" charset:"ascii" nullable:"true" list:"admin" create:"admin_optional"`
|
||||
|
||||
TargetDomainId string `width:"64" charset:"ascii" nullable:"true" list:"admin" create:"admin_optional" update:"admin"`
|
||||
|
||||
AutoCreateProject tristate.TriState `default:"true" nullable:"true" list:"admin" create:"admin_optional" update:"admin"`
|
||||
|
||||
ErrorCount int `list:"admin"`
|
||||
|
||||
SyncStatus string `width:"10" charset:"ascii" default:"idle" list:"admin"`
|
||||
@@ -300,6 +304,19 @@ func (manager *SIdentityProviderManager) ValidateCreateData(ctx context.Context,
|
||||
}
|
||||
}
|
||||
|
||||
targetDomainStr, _ := data.GetString("target_domain")
|
||||
if len(targetDomainStr) > 0 {
|
||||
domain, err := DomainManager.FetchDomainById(targetDomainStr)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, httperrors.NewResourceNotFoundError2(DomainManager.Keyword(), targetDomainStr)
|
||||
} else {
|
||||
return nil, httperrors.NewGeneralError(err)
|
||||
}
|
||||
}
|
||||
data.Set("target_domain_id", jsonutils.NewString(domain.Id))
|
||||
}
|
||||
|
||||
opts := api.TIdentityProviderConfigs{}
|
||||
err := data.Unmarshal(&opts, "config")
|
||||
if err != nil {
|
||||
@@ -408,6 +425,12 @@ func (self *SIdentityProvider) GetExtraDetails(ctx context.Context, userCred mcc
|
||||
func (self *SIdentityProvider) getMoreDetails(extra *jsonutils.JSONDict) *jsonutils.JSONDict {
|
||||
extra = db.FetchModelExtraCountProperties(self, extra)
|
||||
extra.Set("sync_interval_seconds", jsonutils.NewInt(int64(self.getSyncIntervalSeconds())))
|
||||
if len(self.TargetDomainId) > 0 {
|
||||
domain, _ := DomainManager.FetchDomainById(self.TargetDomainId)
|
||||
if domain != nil {
|
||||
extra.Set("target_domain", jsonutils.NewString(domain.Name))
|
||||
}
|
||||
}
|
||||
return extra
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ func submitIdpSyncTask(ctx context.Context, userCred mcclient.TokenCredential, i
|
||||
idp.MarkDisconnected(ctx, userCred)
|
||||
return
|
||||
}
|
||||
driver, err := driver.GetDriver(idp.Driver, idp.Id, idp.Name, idp.Template, conf)
|
||||
driver, err := driver.GetDriver(idp.Driver, idp.Id, idp.Name, idp.Template, idp.TargetDomainId, idp.AutoCreateProject.Bool(), conf)
|
||||
if err != nil {
|
||||
log.Errorf("GetDriver for idp %s fail %s", idp.Name, err)
|
||||
idp.MarkDisconnected(ctx, userCred)
|
||||
|
||||
@@ -656,3 +656,37 @@ func (manager *SUserManager) FetchCustomizeColumns(ctx context.Context, userCred
|
||||
rows := manager.SEnabledIdentityBaseResourceManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields)
|
||||
return expandIdpAttributes(rows, objs, fields, api.IdMappingEntityUser)
|
||||
}
|
||||
|
||||
func (manager *SUserManager) FetchUserLocalIdsInDomain(domainId string, excludes []string) ([]string, error) {
|
||||
return fetchLocalIdsInDomain(manager, domainId, excludes)
|
||||
}
|
||||
|
||||
func fetchLocalIdsInDomain(manager db.IModelManager, domainId string, excludes []string) ([]string, error) {
|
||||
idmappings := IdmappingManager.Query().SubQuery()
|
||||
users := manager.Query().SubQuery()
|
||||
q := idmappings.Query(idmappings.Field("local_id"))
|
||||
q = q.Join(users, sqlchemy.AND(
|
||||
sqlchemy.Equals(idmappings.Field("entity_type"), manager.Keyword()),
|
||||
sqlchemy.Equals(idmappings.Field("public_id"), users.Field("id")),
|
||||
))
|
||||
q = q.Filter(sqlchemy.Equals(users.Field("domain_id"), domainId))
|
||||
q = q.Filter(sqlchemy.NotIn(idmappings.Field("local_id"), excludes))
|
||||
rows, err := q.Rows()
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return nil, errors.Wrap(err, "query")
|
||||
}
|
||||
if rows == nil {
|
||||
return nil, nil
|
||||
}
|
||||
defer rows.Close()
|
||||
ret := make([]string, 0)
|
||||
for rows.Next() {
|
||||
var idStr string
|
||||
err = rows.Scan(&idStr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "scan")
|
||||
}
|
||||
ret = append(ret, idStr)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
|
||||
"yunion.io/x/jsonutils"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/identity"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
|
||||
"yunion.io/x/onecloud/pkg/keystone/models"
|
||||
@@ -39,6 +40,7 @@ func (self *IdentityProviderDeleteTask) OnInit(ctx context.Context, obj db.IStan
|
||||
|
||||
err := idp.Purge(ctx, self.UserCred)
|
||||
if err != nil {
|
||||
idp.SetStatus(self.UserCred, api.IdentityDriverStatusDeleteFailed, err.Error())
|
||||
self.SetStageFailed(ctx, fmt.Sprintf("purge failed %s", err))
|
||||
logclient.AddActionLogWithStartable(self, idp, logclient.ACT_DELETE, err, self.UserCred, false)
|
||||
return
|
||||
|
||||
@@ -140,7 +140,7 @@ func authUserByIdentity(ctx context.Context, ident mcclient.SAuthenticationIdent
|
||||
return nil, errors.Wrap(err, "GetConfig")
|
||||
}
|
||||
|
||||
backend, err := driver.GetDriver(idp.Driver, idp.Id, idp.Name, idp.Template, conf)
|
||||
backend, err := driver.GetDriver(idp.Driver, idp.Id, idp.Name, idp.Template, idp.TargetDomainId, idp.AutoCreateProject.Bool(), conf)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "driver.GetDriver")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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 stringutils2
|
||||
|
||||
func IsUtf8(str string) bool {
|
||||
for _, runeVal := range str {
|
||||
if runeVal > 0x7f {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright 2019 Yunion
|
||||
//
|
||||
// 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 stringutils2
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIsUtf8(t *testing.T) {
|
||||
cases := []struct {
|
||||
In string
|
||||
Want bool
|
||||
}{
|
||||
{"中文", true},
|
||||
{"this is eng", false},
|
||||
}
|
||||
for _, c := range cases {
|
||||
got := IsUtf8(c.In)
|
||||
if got != c.Want {
|
||||
t.Errorf("IsUtf8 %s got %v want %v", c.In, got, c.Want)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user