mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-08-30 17:13:08 +08:00
fix: keystone fernet setup bugs and other bugs (#1022)
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
// 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 identity
|
||||
|
||||
const (
|
||||
FernetKeyForToken = "token"
|
||||
FernetKeyForCredential = "credential"
|
||||
)
|
||||
@@ -52,6 +52,6 @@ func (manager *SDomainizedResourceBaseManager) FetchOwnerId(ctx context.Context,
|
||||
}
|
||||
|
||||
func (model *SDomainizedResourceBase) GetOwnerId() mcclient.IIdentityProvider {
|
||||
owner := SOwnerId{Domain: model.DomainId}
|
||||
owner := SOwnerId{DomainId: model.DomainId}
|
||||
return &owner
|
||||
}
|
||||
|
||||
@@ -82,7 +82,9 @@ type CommonOptions struct {
|
||||
|
||||
type DBOptions struct {
|
||||
SqlConnection string `help:"SQL connection string" alias:"connection"`
|
||||
AutoSyncTable bool `help:"Automatically synchronize table changes if differences are detected"`
|
||||
|
||||
AutoSyncTable bool `help:"Automatically synchronize table changes if differences are detected"`
|
||||
ExitAfterDBInit bool `help:"Exit program after db initialization" default:"false"`
|
||||
|
||||
GlobalVirtualResourceNamespace bool `help:"Per project namespace or global namespace for virtual resources" default:"false"`
|
||||
DebugSqlchemy bool `default:"false" help:"Print SQL executed by sqlchemy"`
|
||||
|
||||
@@ -271,7 +271,7 @@ func (manager *SPolicyManager) allowWithoutCache(scope rbacutils.TRbacScope, use
|
||||
policies, ok := manager.policies[scope]
|
||||
if !ok {
|
||||
log.Warningf("no policies fetched for scope %s", scope)
|
||||
return rbacutils.Deny
|
||||
// return rbacutils.Deny
|
||||
}
|
||||
findMatchRule := false
|
||||
findMatchPolicy := false
|
||||
|
||||
@@ -87,6 +87,11 @@ var (
|
||||
"policies",
|
||||
}
|
||||
|
||||
itsmSystemResources = []string{
|
||||
"process-definitions",
|
||||
}
|
||||
itsmDomainResources = []string{}
|
||||
|
||||
systemResources = map[string][]string{
|
||||
"compute": computeSystemResources,
|
||||
"notify": notifySystemResources,
|
||||
@@ -96,6 +101,7 @@ var (
|
||||
"yunionconf": yunionconfSystemResources,
|
||||
"log": logSystemResources,
|
||||
"identity": identitySystemResources,
|
||||
"itsm": itsmSystemResources,
|
||||
}
|
||||
|
||||
domainResources = map[string][]string{
|
||||
@@ -107,6 +113,7 @@ var (
|
||||
"yunionconf": yunionconfDomainResources,
|
||||
"log": logDomainResources,
|
||||
"identity": identityDomainResources,
|
||||
"itsm": itsmDomainResources,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -16,26 +16,9 @@ package keys
|
||||
|
||||
import (
|
||||
"yunion.io/x/onecloud/pkg/util/fernetool"
|
||||
"yunion.io/x/onecloud/pkg/util/fileutils2"
|
||||
)
|
||||
|
||||
var (
|
||||
TokenKeysManager = fernetool.SFernetKeyManager{}
|
||||
CredentialKeyManager = fernetool.SFernetKeyManager{}
|
||||
)
|
||||
|
||||
func Init(tokenKeyRepo, credKeyRepo string) error {
|
||||
err := TokenKeysManager.LoadKeys(tokenKeyRepo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if fileutils2.IsDir(credKeyRepo) {
|
||||
err = CredentialKeyManager.LoadKeys(credKeyRepo)
|
||||
} else {
|
||||
err = CredentialKeyManager.InitEmpty()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ type SDomain struct {
|
||||
// IdpId string `token:"parent_id" width:"64" charset:"ascii" index:"true" list:"admin"`
|
||||
|
||||
DomainId string `width:"64" charset:"ascii" default:"default" nullable:"false" index:"true"`
|
||||
ParentId string `width:"64" charset:"ascii"`
|
||||
}
|
||||
|
||||
func (manager *SDomainManager) InitializeData() error {
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
// 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 models
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/fernet/fernet-go"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/identity"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/keystone/keys"
|
||||
"yunion.io/x/onecloud/pkg/keystone/options"
|
||||
"yunion.io/x/onecloud/pkg/util/fileutils2"
|
||||
)
|
||||
|
||||
type SFernetKeyManager struct {
|
||||
db.SModelBaseManager
|
||||
}
|
||||
|
||||
var (
|
||||
FernetKeyManager *SFernetKeyManager
|
||||
)
|
||||
|
||||
func init() {
|
||||
FernetKeyManager = &SFernetKeyManager{
|
||||
SModelBaseManager: db.NewModelBaseManager(
|
||||
SFernetKey{},
|
||||
"fernetkey",
|
||||
"fernetkey",
|
||||
"fernetkeys",
|
||||
),
|
||||
}
|
||||
FernetKeyManager.SetVirtualObject(FernetKeyManager)
|
||||
}
|
||||
|
||||
type SFernetKey struct {
|
||||
db.SModelBase
|
||||
|
||||
Type string `width:"36" charset:"ascii" nullable:"false" primary:"true"`
|
||||
Index int `nullable:"false" primary:"true"`
|
||||
Key string `width:"64" charset:"ascii" nullable:"false"`
|
||||
}
|
||||
|
||||
func (manager *SFernetKeyManager) InitializeData() error {
|
||||
fkeys, err := manager.getKeys(api.FernetKeyForToken)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "manager.getKeys")
|
||||
}
|
||||
if len(fkeys) == 0 {
|
||||
fkeys, err = manager.setupKeys(api.FernetKeyForToken, options.Options.FernetKeyRepository)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "manager.setupKeys")
|
||||
}
|
||||
}
|
||||
keys.TokenKeysManager.SetKeys(fkeys)
|
||||
|
||||
if options.Options.SetupCredentialKeys {
|
||||
fkeys, err := manager.getKeys(api.FernetKeyForToken)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "manager.getKeys")
|
||||
}
|
||||
if len(fkeys) == 0 {
|
||||
fkeys, err = manager.setupKeys(api.FernetKeyForCredential, "")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "manager.setupKeys")
|
||||
}
|
||||
}
|
||||
keys.CredentialKeyManager.SetKeys(fkeys)
|
||||
} else {
|
||||
err = keys.CredentialKeyManager.InitEmpty()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "keys.TokenKeysManager.InitEmpty")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (manager *SFernetKeyManager) getKeys(keyType string) ([]*fernet.Key, error) {
|
||||
q := manager.Query().Equals("type", keyType).Asc("index")
|
||||
keys := make([]SFernetKey, 0)
|
||||
err := db.FetchModelObjects(manager, q, &keys)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return nil, errors.Wrap(err, "db.FetchModelObjects")
|
||||
}
|
||||
fkeys := make([]*fernet.Key, len(keys))
|
||||
for i := range keys {
|
||||
fkeys[i], err = fernet.DecodeKey(keys[i].Key)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fernet.DecodeKey")
|
||||
}
|
||||
}
|
||||
return fkeys, nil
|
||||
}
|
||||
|
||||
func (manager *SFernetKeyManager) setupKeys(keyType string, repoDir string) ([]*fernet.Key, error) {
|
||||
maxKeyCount := 2
|
||||
ret := make([]*fernet.Key, maxKeyCount)
|
||||
for i := 0; i < maxKeyCount; i += 1 {
|
||||
var fkey *fernet.Key
|
||||
if len(repoDir) > 0 {
|
||||
keyPath := filepath.Join(repoDir, fmt.Sprintf("%d", i))
|
||||
if fileutils2.Exists(keyPath) {
|
||||
keyCrypt, err := fileutils2.FileGetContents(keyPath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fileutils.FileGetContent")
|
||||
}
|
||||
fkey, err = fernet.DecodeKey(keyCrypt)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fernet.DecodeKey")
|
||||
}
|
||||
}
|
||||
}
|
||||
if fkey == nil {
|
||||
fkey = &fernet.Key{}
|
||||
err := fkey.Generate()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fkey.Generate")
|
||||
}
|
||||
}
|
||||
key := SFernetKey{
|
||||
Type: keyType,
|
||||
Index: i,
|
||||
Key: fkey.Encode(),
|
||||
}
|
||||
err := manager.TableSpec().Insert(&key)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "insertFernetKeys")
|
||||
}
|
||||
ret[i] = fkey
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
@@ -35,8 +35,6 @@ type IIdentityModelManager interface {
|
||||
db.IStandaloneModelManager
|
||||
|
||||
GetIIdentityModelManager() IIdentityModelManager
|
||||
|
||||
IsDomainReadonly(domain *SDomain) bool
|
||||
}
|
||||
|
||||
type IIdentityModel interface {
|
||||
@@ -109,10 +107,6 @@ func (manager *SIdentityBaseResourceManager) GetIIdentityModelManager() IIdentit
|
||||
return manager.GetVirtualObject().(IIdentityModelManager)
|
||||
}
|
||||
|
||||
func (manager *SIdentityBaseResourceManager) IsDomainReadonly(domain *SDomain) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (manager *SIdentityBaseResourceManager) FetchByName(userCred mcclient.IIdentityProvider, idStr string) (db.IModel, error) {
|
||||
return db.FetchByName(manager, userCred, idStr)
|
||||
}
|
||||
@@ -150,9 +144,6 @@ func (manager *SIdentityBaseResourceManager) ValidateCreateData(ctx context.Cont
|
||||
if domain.Enabled.IsFalse() {
|
||||
return nil, httperrors.NewInvalidStatusError("domain is disabled")
|
||||
}
|
||||
// if manager.GetIIdentityModelManager().IsDomainReadonly(domain) {
|
||||
// return nil, httperrors.NewForbiddenError("domain is readonly")
|
||||
// }
|
||||
return manager.SStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, data)
|
||||
}
|
||||
|
||||
@@ -162,14 +153,15 @@ func (manager *SIdentityBaseResourceManager) NamespaceScope() rbacutils.TRbacSco
|
||||
|
||||
func (manager *SIdentityBaseResourceManager) FetchCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, objs []db.IModel, fields stringutils2.SSortedStrings) []*jsonutils.JSONDict {
|
||||
rows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields)
|
||||
domainIds := stringutils2.SSortedStrings{}
|
||||
for i := range objs {
|
||||
idStr := objs[i].GetOwnerId().GetProjectDomainId()
|
||||
if idStr != api.KeystoneDomainRoot {
|
||||
domainIds = stringutils2.Append(domainIds, idStr)
|
||||
}
|
||||
}
|
||||
if len(fields) == 0 || fields.Contains("domain") {
|
||||
domainIds := stringutils2.SSortedStrings{}
|
||||
for i := range objs {
|
||||
idStr := objs[i].GetOwnerId().GetProjectDomainId()
|
||||
if idStr != api.KeystoneDomainRoot {
|
||||
domainIds = stringutils2.Append(domainIds, idStr)
|
||||
}
|
||||
}
|
||||
log.Debugf("expand domain ... %s", domainIds)
|
||||
domains := fetchDomain(domainIds)
|
||||
if domains != nil {
|
||||
for i := range rows {
|
||||
@@ -207,20 +199,20 @@ func (model *SIdentityBaseResource) CustomizeCreate(ctx context.Context, userCre
|
||||
}
|
||||
|
||||
func (self *SIdentityBaseResource) ValidateDeleteCondition(ctx context.Context) error {
|
||||
domain := self.GetDomain()
|
||||
if self.GetIIdentityModelManager().IsDomainReadonly(domain) {
|
||||
return httperrors.NewForbiddenError("readonly domain")
|
||||
}
|
||||
// domain := self.GetDomain()
|
||||
// if self.GetIIdentityModelManager().IsDomainReadonly(domain) {
|
||||
// return httperrors.NewForbiddenError("readonly domain")
|
||||
// }
|
||||
return self.SStandaloneResourceBase.ValidateDeleteCondition(ctx)
|
||||
}
|
||||
|
||||
func (self *SIdentityBaseResource) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
|
||||
if data.Contains("name") {
|
||||
domain := self.GetDomain()
|
||||
if self.GetIIdentityModelManager().IsDomainReadonly(domain) {
|
||||
return nil, httperrors.NewForbiddenError("cannot update name in readonly domain")
|
||||
}
|
||||
}
|
||||
// if data.Contains("name") {
|
||||
// domain := self.GetDomain()
|
||||
// if self.GetIIdentityModelManager().IsDomainReadonly(domain) {
|
||||
// return nil, httperrors.NewForbiddenError("cannot update name in readonly domain")
|
||||
// }
|
||||
// }
|
||||
return self.SStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, data)
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@ func InitDB() error {
|
||||
UserManager,
|
||||
AssignmentManager,
|
||||
CredentialManager,
|
||||
|
||||
FernetKeyManager,
|
||||
} {
|
||||
err := manager.InitializeData()
|
||||
if err != nil {
|
||||
|
||||
@@ -69,7 +69,8 @@ func init() {
|
||||
type SBaseProject struct {
|
||||
SEnabledIdentityBaseResource
|
||||
|
||||
ParentId string `width:"64" charset:"ascii" index:"true" list:"admin" create:"admin_optional"`
|
||||
ParentId string `width:"64" charset:"ascii" list:"admin" create:"admin_optional"`
|
||||
|
||||
IsDomain tristate.TriState `default:"false" nullable:"false" create:"admin_optional"`
|
||||
}
|
||||
|
||||
|
||||
@@ -25,9 +25,10 @@ type SKeystoneOptions struct {
|
||||
|
||||
AdminPort int `default:"35357" help:"listening port for admin API(deprecated)"`
|
||||
|
||||
TokenExpirationSeconds int `default:"86400" help:"token expiration seconds" token:"expiration"`
|
||||
TokenKeyRepository string `help:"fernet key repo directory" token:"key_repository" default:"/etc/yunion/keystone/fernet-keys"`
|
||||
CredentialKeyRepository string `help:"fernet key repo directory for credentials" token:"credential_key_repository"`
|
||||
TokenExpirationSeconds int `default:"86400" help:"token expiration seconds" token:"expiration"`
|
||||
FernetKeyRepository string `help:"fernet key repo directory" token:"key_repository" default:"/etc/yunion/keystone/fernet-keys"`
|
||||
SetupCredentialKeys bool `help:"setup standalone fernet keys for credentials" token:"setup_credential_key" default:"false"`
|
||||
// SetupStateKey bool `help:"setup standalone fernet keys for openid state" token:"setup_state_key"`
|
||||
|
||||
BootstrapAdminUserPassword string `help:"bootstreap sysadmin user password" default:"sysadmin"`
|
||||
|
||||
|
||||
@@ -52,10 +52,11 @@ func initHandlers(app *appsrv.Application) {
|
||||
|
||||
models.FederatedUserManager,
|
||||
models.FederationProtocolManager,
|
||||
models.IdentityProviderManager,
|
||||
models.ImpliedRoleManager,
|
||||
models.UserOptionManager,
|
||||
models.IdpRemoteIdsManager,
|
||||
|
||||
models.FernetKeyManager,
|
||||
} {
|
||||
db.RegisterModelManager(manager)
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ import (
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
common_options "yunion.io/x/onecloud/pkg/cloudcommon/options"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/policy"
|
||||
"yunion.io/x/onecloud/pkg/keystone/keys"
|
||||
// "yunion.io/x/onecloud/pkg/keystone/keys"
|
||||
"yunion.io/x/onecloud/pkg/keystone/models"
|
||||
"yunion.io/x/onecloud/pkg/keystone/options"
|
||||
"yunion.io/x/onecloud/pkg/keystone/tokens"
|
||||
@@ -63,10 +63,11 @@ func StartService() {
|
||||
opts.Port = 5000 // keystone well-known port
|
||||
}
|
||||
|
||||
err := keys.Init(opts.TokenKeyRepository, opts.CredentialKeyRepository)
|
||||
/* err := keys.Init(opts.FernetKeyRepository, opts.SetupCredentialKey)
|
||||
if err != nil {
|
||||
log.Fatalf("init fernet keys fail %s", err)
|
||||
}
|
||||
*/
|
||||
|
||||
app := app_common.InitApp(&opts.BaseOptions, true)
|
||||
initHandlers(app)
|
||||
@@ -79,6 +80,11 @@ func StartService() {
|
||||
|
||||
models.InitDB()
|
||||
|
||||
if opts.ExitAfterDBInit {
|
||||
log.Infof("Exiting after db initialization ...")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
app_common.InitBaseAuth(&opts.BaseOptions)
|
||||
|
||||
if !opts.IsSlaveNode {
|
||||
|
||||
+14
@@ -1,3 +1,17 @@
|
||||
// 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 candidate
|
||||
|
||||
import (
|
||||
|
||||
@@ -53,6 +53,10 @@ func (m *SFernetKeyManager) PrimaryKeyHash() string {
|
||||
return hex.EncodeToString(sum[:])
|
||||
}
|
||||
|
||||
func (m *SFernetKeyManager) SetKeys(keys []*fernet.Key) {
|
||||
m.keys = keys
|
||||
}
|
||||
|
||||
func (m *SFernetKeyManager) LoadKeys(path string) error {
|
||||
filesInfos, err := ioutil.ReadDir(path)
|
||||
if err != nil {
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// 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 multipart // import "yunion.io/x/onecloud/pkg/util/multipart"
|
||||
@@ -1,3 +1,17 @@
|
||||
// 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 multipart
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
// 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 multipart
|
||||
|
||||
import (
|
||||
|
||||
Reference in New Issue
Block a user