fix: keystone fernet setup bugs and other bugs (#1022)

This commit is contained in:
Jian Qiu
2019-06-01 17:31:20 +08:00
committed by GitHub
parent 01381356a0
commit bff3ba9b16
19 changed files with 279 additions and 53 deletions
+20
View File
@@ -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"
)
+1 -1
View File
@@ -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
}
+3 -1
View File
@@ -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"`
+1 -1
View File
@@ -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
+7
View File
@@ -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,
}
)
-17
View File
@@ -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
}
+1
View File
@@ -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 {
+149
View File
@@ -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
}
+18 -26
View File
@@ -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)
}
+2
View File
@@ -38,6 +38,8 @@ func InitDB() error {
UserManager,
AssignmentManager,
CredentialManager,
FernetKeyManager,
} {
err := manager.InitializeData()
if err != nil {
+2 -1
View File
@@ -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"`
}
+4 -3
View File
@@ -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"`
+2 -1
View File
@@ -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)
}
+8 -2
View File
@@ -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
View File
@@ -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 (
+4
View File
@@ -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 {
+15
View File
@@ -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"
+14
View File
@@ -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 (
+14
View File
@@ -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 (