fix: shorten keystone token (#18222)

Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
This commit is contained in:
Jian Qiu
2023-10-08 11:20:28 +08:00
committed by GitHub
parent 93d801097d
commit 8530152079
12 changed files with 330 additions and 136 deletions
+41
View File
@@ -0,0 +1,41 @@
// 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 cache
import (
"time"
"yunion.io/x/onecloud/pkg/util/hashcache"
)
var (
tokenCache *hashcache.Cache
)
func Init(expire int) {
tokenCache = hashcache.NewCache(2048, time.Duration(expire/2)*time.Second)
}
func Save(tokenStr string, token interface{}) {
tokenCache.AtomicSet(tokenStr, token)
}
func Remove(tokenStr string) {
tokenCache.AtomicRemove(tokenStr)
}
func Get(tokenStr string) interface{} {
return tokenCache.AtomicGet(tokenStr)
}
+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 cache // import "yunion.io/x/onecloud/pkg/keystone/cache"
+1 -1
View File
@@ -373,7 +373,7 @@ func (cred *SCredential) Delete(ctx context.Context, userCred mcclient.TokenCred
if cred.Type == api.ACCESS_SECRET_TYPE {
// clean tokens auth by this AKSK
err := TokenCacheManager.BatchInvalidate(ctx, api.AUTH_METHOD_AKSK, []string{cred.Id})
err := TokenCacheManager.BatchInvalidate(ctx, userCred, api.AUTH_METHOD_AKSK, []string{cred.Id})
if err != nil {
log.Errorf("BatchInvalidate token failed %s", err)
}
+105 -60
View File
@@ -16,6 +16,7 @@ package models
import (
"context"
"database/sql"
"fmt"
"sort"
"strings"
@@ -28,14 +29,16 @@ import (
api "yunion.io/x/onecloud/pkg/apis/identity"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/keystone/cache"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/logclient"
)
var TokenCacheManager *STokenCacheManager
func init() {
TokenCacheManager = &STokenCacheManager{
SModelBaseManager: db.NewModelBaseManager(
SStandaloneAnonResourceBaseManager: db.NewStandaloneAnonResourceBaseManager(
STokenCache{},
"token_cache_tbl",
"token_cache",
@@ -46,17 +49,25 @@ func init() {
}
type STokenCache struct {
db.SModelBase
db.SStandaloneAnonResourceBase
Token string `width:"700" charset:"ascii" nullable:"false" primary:"true"`
// Token string `width:"64" charset:"ascii" nullable:"false" primary:"true"`
ExpiredAt time.Time `nullable:"false"`
Valid bool
Method string `width:"32" charset:"ascii"`
AuditIds string `width:"700" charset:"utf8" index:"true"`
Method string `width:"32" charset:"ascii"`
AuditIds string `width:"256" charset:"utf8" index:"true"`
UserId string `width:"128" charset:"ascii" nullable:"false"`
ProjectId string `width:"128" charset:"ascii" nullable:"true"`
DomainId string `width:"128" charset:"ascii" nullable:"true"`
Source string `width:"16" charset:"ascii"`
Ip string `width:"64" charset:"ascii"`
}
type STokenCacheManager struct {
db.SModelBaseManager
db.SStandaloneAnonResourceBaseManager
}
func joinAuditIds(ids []string) string {
@@ -64,88 +75,101 @@ func joinAuditIds(ids []string) string {
return strings.Join(ids, ",")
}
func (manager *STokenCacheManager) Save(ctx context.Context, token string, expiredAt time.Time, method string, auditIds []string) error {
return manager.insert(ctx, token, expiredAt, true, method, auditIds)
}
func (manager *STokenCacheManager) Invalidate(ctx context.Context, token string, expiredAt time.Time, method string, auditIds []string) error {
return manager.insert(ctx, token, expiredAt, false, method, auditIds)
}
func (manager *STokenCacheManager) BatchInvalidate(ctx context.Context, method string, auditIds []string) error {
invalidQueue := []sCacheCredential{
{
Method: method,
AuditIds: auditIds,
},
func (manager *STokenCacheManager) Save(ctx context.Context, tokenStr string, expiredAt time.Time, method string, auditIds []string, userId, projId, domainId, source, ip string) error {
token, err := manager.FetchToken(tokenStr)
if err != nil && errors.Cause(err) != sql.ErrNoRows {
return errors.Wrap(err, "FetchToken")
}
for i := 0; i < len(invalidQueue); i++ {
queues, err := manager.batchInvalidateInternal(ctx, invalidQueue[i])
if err != nil {
return errors.Wrap(err, "batchInvalidateInternal")
}
if len(queues) > 0 {
invalidQueue = append(invalidQueue, queues...)
}
if token == nil || !token.Valid {
return manager.insert(ctx, tokenStr, expiredAt, true, method, auditIds, userId, projId, domainId, source, ip)
}
return nil
}
type sCacheCredential struct {
Method string
AuditIds []string
func (manager *STokenCacheManager) Invalidate(ctx context.Context, userCred mcclient.TokenCredential, tokenStr string) error {
token, err := manager.FetchToken(tokenStr)
if err != nil {
return errors.Wrap(err, "FetchToken")
}
err = token.invalidate(ctx, userCred)
if err != nil {
return errors.Wrap(err, "token.invalidate")
}
return nil
}
func (manager *STokenCacheManager) batchInvalidateInternal(ctx context.Context, cred sCacheCredential) ([]sCacheCredential, error) {
q := manager.Query().Equals("method", cred.Method).Equals("audit_ids", joinAuditIds(cred.AuditIds))
func (manager *STokenCacheManager) BatchInvalidateByUserId(ctx context.Context, userCred mcclient.TokenCredential, uid string) error {
return manager.batchInvalidateInternal(ctx, userCred, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
q = q.Equals("user_id", uid)
return q
})
}
func (manager *STokenCacheManager) BatchInvalidate(ctx context.Context, userCred mcclient.TokenCredential, method string, auditIds []string) error {
return manager.batchInvalidateInternal(ctx, userCred, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
q = q.Equals("method", method).Equals("audit_ids", joinAuditIds(auditIds))
return q
})
}
func (manager *STokenCacheManager) batchInvalidateInternal(ctx context.Context, userCred mcclient.TokenCredential, filter func(q *sqlchemy.SQuery) *sqlchemy.SQuery) error {
q := manager.Query().IsTrue("valid")
q = filter(q)
tokens := make([]STokenCache, 0)
err := db.FetchModelObjects(manager, q, &tokens)
if err != nil {
return nil, errors.Wrap(err, "FetchModelObjects")
return errors.Wrap(err, "FetchModelObjects")
}
if len(tokens) == 0 {
return nil, nil
return nil
}
queues := make([]sCacheCredential, 0)
errs := make([]error, 0)
for i := range tokens {
token := tokens[i]
queues = append(queues, sCacheCredential{
Method: api.AUTH_METHOD_TOKEN,
AuditIds: []string{token.Token},
})
err := token.invalidate(ctx, userCred)
if err != nil {
errs = append(errs, errors.Wrapf(err, "batchInvalidateInternal token %s", token.Id))
}
}
err = manager.TableSpec().GetTableSpec().UpdateBatch(
map[string]interface{}{
"valid": false,
},
map[string]interface{}{
"method": cred.Method,
"audit_ids": joinAuditIds(cred.AuditIds),
},
)
return queues, errors.Wrap(err, "UpdateBatch")
if len(errs) > 0 {
return errors.NewAggregate(errs)
}
return nil
}
func (manager *STokenCacheManager) insert(ctx context.Context, token string, expiredAt time.Time, valid bool, method string, auditIds []string) error {
func (manager *STokenCacheManager) insert(ctx context.Context, token string, expiredAt time.Time, valid bool, method string, auditIds []string, userId, projectId, domainId, source, ip string) error {
val := STokenCache{
Token: token,
SStandaloneAnonResourceBase: db.SStandaloneAnonResourceBase{
Id: token,
},
ExpiredAt: expiredAt,
Valid: valid,
Method: method,
AuditIds: joinAuditIds(auditIds),
UserId: userId,
ProjectId: projectId,
DomainId: domainId,
Source: source,
Ip: ip,
}
err := manager.TableSpec().InsertOrUpdate(ctx, &val)
return errors.Wrap(err, "InsertOrUpdate")
}
func (manager *STokenCacheManager) IsValid(token string) (bool, error) {
q := manager.Query().Equals("token", token)
tokenCache := STokenCache{}
err := q.First(&tokenCache)
func (manager *STokenCacheManager) FetchToken(tokenStr string) (*STokenCache, error) {
obj, err := manager.FetchById(tokenStr)
if err != nil {
return false, errors.Wrap(err, "Query")
return nil, errors.Wrap(err, "FetchById")
}
return tokenCache.Valid, nil
return obj.(*STokenCache), nil
}
func (manager *STokenCacheManager) IsValid(tokenStr string) (bool, error) {
token, err := manager.FetchToken(tokenStr)
if err != nil {
return false, errors.Wrap(err, "FetchToken")
}
return token.Valid, nil
}
func (manager *STokenCacheManager) removeObsolete() error {
@@ -164,7 +188,7 @@ func RemoveObsoleteInvalidTokens(ctx context.Context, userCred mcclient.TokenCre
}
func (manager *STokenCacheManager) FetchInvalidTokens() ([]string, error) {
q := manager.Query("token").IsFalse("valid")
q := manager.Query("id").IsFalse("valid")
tokens := make([]STokenCache, 0)
err := db.FetchModelObjects(manager, q, &tokens)
if err != nil {
@@ -172,7 +196,28 @@ func (manager *STokenCacheManager) FetchInvalidTokens() ([]string, error) {
}
ret := make([]string, len(tokens))
for i := range tokens {
ret[i] = tokens[i].Token
ret[i] = tokens[i].Id
}
return ret, nil
}
func (token *STokenCache) invalidate(ctx context.Context, userCred mcclient.TokenCredential) error {
err := TokenCacheManager.BatchInvalidate(ctx, userCred, api.AUTH_METHOD_TOKEN, []string{token.Id})
if err != nil {
return errors.Wrapf(err, "BatchInvalidate subtoken %s", token.Id)
}
_, err = db.Update(token, func() error {
token.Valid = false
return nil
})
if err != nil {
return errors.Wrap(err, "update")
}
cache.Remove(token.Id)
logclient.AddActionLogWithContext(ctx, token, logclient.ACT_DELETE, token.GetShortDesc(ctx), userCred, true)
return nil
}
+35 -7
View File
@@ -17,7 +17,6 @@ package models
import (
"context"
"database/sql"
"fmt"
"time"
"yunion.io/x/jsonutils"
@@ -838,10 +837,17 @@ func (user *SUser) PostUpdate(ctx context.Context, userCred mcclient.TokenCreden
}
logclient.AddActionLogWithContext(ctx, user, logclient.ACT_UPDATE_PASSWORD, nil, userCred, true)
}
if enabled, _ := data.Bool("enabled"); enabled {
err := user.clearFailedAuth()
if err != nil {
log.Errorf("clearFailedAuth %s", err)
if enabled, err := data.Bool("enabled"); err == nil {
if enabled {
err := user.clearFailedAuth()
if err != nil {
log.Errorf("clearFailedAuth %s", err)
}
} else {
batchErr := TokenCacheManager.BatchInvalidateByUserId(ctx, userCred, user.Id)
if batchErr != nil {
log.Errorf("BatchInvalidateByUserId fail %s", batchErr)
}
}
}
}
@@ -930,9 +936,12 @@ func (user *SUser) Delete(ctx context.Context, userCred mcclient.TokenCredential
if err != nil {
return errors.Wrap(err, "PasswordManager.delete")
}
batchErr := TokenCacheManager.BatchInvalidate(ctx, api.AUTH_METHOD_PASSWORD, []string{fmt.Sprintf("%d", localUser.Id)})
}
{
batchErr := TokenCacheManager.BatchInvalidateByUserId(ctx, userCred, user.Id)
if batchErr != nil {
log.Errorf("BatchInvalidate fail %s", batchErr)
log.Errorf("BatchInvalidateByUserId fail %s", batchErr)
}
}
@@ -1336,3 +1345,22 @@ func (user *SUser) PerformEnable(
}
return user.SEnabledIdentityBaseResource.PerformEnable(ctx, userCred, query, input)
}
func (user *SUser) PerformDisable(
ctx context.Context,
userCred mcclient.TokenCredential,
query jsonutils.JSONObject,
input apis.PerformDisableInput,
) (jsonutils.JSONObject, error) {
_, err := user.SEnabledIdentityBaseResource.PerformDisable(ctx, userCred, query, input)
if err != nil {
return nil, errors.Wrap(err, "SEnabledIdentityBaseResource.PerformDisable")
}
{
batchErr := TokenCacheManager.BatchInvalidateByUserId(ctx, userCred, user.Id)
if batchErr != nil {
log.Errorf("BatchInvalidateByUserId fail %s", batchErr)
}
}
return nil, nil
}
+3
View File
@@ -31,6 +31,7 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
common_options "yunion.io/x/onecloud/pkg/cloudcommon/options"
"yunion.io/x/onecloud/pkg/cloudcommon/policy"
"yunion.io/x/onecloud/pkg/keystone/cache"
"yunion.io/x/onecloud/pkg/keystone/cronjobs"
"yunion.io/x/onecloud/pkg/keystone/models"
"yunion.io/x/onecloud/pkg/keystone/options"
@@ -90,6 +91,8 @@ func StartService() {
common_options.StartOptionManagerWithSessionDriver(opts, opts.ConfigSyncPeriodSeconds, api.SERVICE_TYPE, "", options.OnOptionsChange, models.NewServiceConfigSession())
cache.Init(opts.TokenExpirationSeconds)
if !opts.IsSlaveNode {
cron := cronman.InitCronJobManager(true, opts.CronJobWorkerCount)
+2 -22
View File
@@ -46,25 +46,9 @@ func authUserByTokenV3(ctx context.Context, input mcclient.SAuthenticationInputV
}
func authUserByToken(ctx context.Context, tokenStr string) (*api.SUserExtended, error) {
valid, err := models.TokenCacheManager.IsValid(tokenStr)
if err == nil {
if !valid {
return nil, errors.Wrap(httperrors.ErrInvalidCredential, "invalid token")
} else {
// passthrough
}
} else {
if errors.Cause(err) != sql.ErrNoRows {
return nil, errors.Wrap(err, "TokenCacheManager.IsValid")
} else {
// passthrough
}
}
token := SAuthToken{}
err = token.ParseFernetToken(tokenStr)
token, err := TokenStrDecode(tokenStr)
if err != nil {
return nil, errors.Wrap(err, "token.ParseFernetToken")
return nil, errors.Wrap(err, "token.TokenStrDecode")
}
extUser, err := models.UserManager.FetchUserExtended(token.UserId, "", "", "")
if err != nil {
@@ -566,8 +550,6 @@ func AuthenticateV3(ctx context.Context, input mcclient.SAuthenticationInputV3)
return nil, errors.Wrap(err, "getTokenV3")
}
models.TokenCacheManager.Save(ctx, tokenV3.Id, token.ExpiresAt, token.Method, token.AuditIds)
return tokenV3, nil
}
@@ -658,7 +640,5 @@ func _authenticateV2(ctx context.Context, input mcclient.SAuthenticationInputV2)
return nil, errors.Wrap(err, "getTokenV2")
}
models.TokenCacheManager.Save(ctx, tokenV2.Token.Id, token.ExpiresAt, token.Method, token.AuditIds)
return tokenV2, nil
}
+17 -28
View File
@@ -16,7 +16,6 @@ package tokens
import (
"context"
"database/sql"
"net/http"
"yunion.io/x/jsonutils"
@@ -28,6 +27,7 @@ import (
"yunion.io/x/onecloud/pkg/appsrv"
"yunion.io/x/onecloud/pkg/cloudcommon/policy"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/keystone/cache"
"yunion.io/x/onecloud/pkg/keystone/models"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/auth"
@@ -136,20 +136,15 @@ func verifyTokensV2(ctx context.Context, w http.ResponseWriter, r *http.Request)
params, _, _ := appsrv.FetchEnv(ctx, w, r)
tokenStr := params["<token>"]
valid, err := models.TokenCacheManager.IsValid(tokenStr)
if err == nil {
if !valid {
httperrors.InvalidCredentialError(ctx, w, "invalid token")
cachedToken := cache.Get(tokenStr)
if cachedToken != nil {
if v2token, ok := cachedToken.(*mcclient.TokenCredentialV2); ok && v2token.IsValid() {
ret := jsonutils.NewDict()
ret.Add(jsonutils.Marshal(v2token), "access")
appsrv.SendJSON(w, ret)
return
} else {
// passthrough
}
} else {
if errors.Cause(err) != sql.ErrNoRows {
httperrors.GeneralServerError(ctx, w, err)
return
} else {
// passthrough
cache.Remove(tokenStr)
}
}
@@ -202,20 +197,15 @@ type VerifyTokenV3Param struct {
func verifyTokensV3(ctx context.Context, w http.ResponseWriter, r *http.Request) {
tokenStr := r.Header.Get(api.AUTH_SUBJECT_TOKEN_HEADER)
valid, err := models.TokenCacheManager.IsValid(tokenStr)
if err == nil {
if !valid {
httperrors.InvalidCredentialError(ctx, w, "invalid token")
cachedToken := cache.Get(tokenStr)
if cachedToken != nil {
if v3token, ok := cachedToken.(*mcclient.TokenCredentialV3); ok && v3token.IsValid() {
w.Header().Set(api.AUTH_SUBJECT_TOKEN_HEADER, v3token.Id)
v3token.Id = ""
appsrv.SendJSON(w, jsonutils.Marshal(v3token))
return
} else {
// passthrough
}
} else {
if errors.Cause(err) != sql.ErrNoRows {
httperrors.GeneralServerError(ctx, w, err)
return
} else {
// passthrough
cache.Remove(tokenStr)
}
}
@@ -269,12 +259,11 @@ func verifyCommon(ctx context.Context, w http.ResponseWriter, tokenStr string) (
if adminToken.IsAllow(rbacscope.ScopeSystem, api.SERVICE_TYPE, "tokens", "perform", "auth").Result.IsDeny() {
return nil, httperrors.NewForbiddenError("%s not allow to auth", adminToken.GetUserName())
}
token := SAuthToken{}
err := token.ParseFernetToken(tokenStr)
token, err := TokenStrDecode(tokenStr)
if err != nil {
return nil, httperrors.NewInvalidCredentialError(errors.Wrapf(err, "invalid token").Error())
}
return &token, nil
return token, nil
}
func authenticateToken(f appsrv.FilterHandler) appsrv.FilterHandler {
+10 -8
View File
@@ -49,18 +49,20 @@ func invalidateToken(ctx context.Context, tokenStr string) error {
if adminToken == nil || len(tokenStr) == 0 {
return httperrors.NewForbiddenError("missing auth token")
}
if adminToken.IsAllow(rbacscope.ScopeSystem, api.SERVICE_TYPE, "tokens", "delete").Result.IsDeny() {
return httperrors.NewForbiddenError("%s not allow to auth", adminToken.GetUserName())
}
token := SAuthToken{}
err := token.ParseFernetToken(tokenStr)
token, err := TokenStrDecode(tokenStr)
if err != nil {
return httperrors.NewInvalidCredentialError(errors.Wrapf(err, "invalid token").Error())
}
err = models.TokenCacheManager.Invalidate(ctx, tokenStr, token.ExpiresAt, token.Method, token.AuditIds)
if err != nil {
return errors.Wrap(err, "Insert")
if adminToken.GetUserId() != token.UserId && adminToken.IsAllow(rbacscope.ScopeSystem, api.SERVICE_TYPE, "tokens", "delete").Result.IsDeny() {
return httperrors.NewForbiddenError("%s not allow to auth", adminToken.GetUserName())
}
err = models.TokenCacheManager.Invalidate(ctx, adminToken, tokenStr)
if err != nil {
return errors.Wrap(err, "Invalidate")
}
return nil
}
+72 -8
View File
@@ -16,6 +16,7 @@ package tokens
import (
"context"
"database/sql"
"strings"
"time"
@@ -25,10 +26,13 @@ import (
"yunion.io/x/pkg/utils"
api "yunion.io/x/onecloud/pkg/apis/identity"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/keystone/cache"
"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/mcclient"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
var (
@@ -48,7 +52,7 @@ func GetDefaultToken() string {
AuditIds: []string{utils.GenRequestId(16)},
}
var err error
defaultAuthTokenStr, err = defaultAuthToken.EncodeFernetToken()
defaultAuthTokenStr, err = defaultAuthToken.encodeFernetToken()
if err != nil {
log.Fatalf("defaultAuthToken.EncodeFernetToken fail: %s", err)
}
@@ -174,7 +178,42 @@ func (t *SAuthToken) Encode() ([]byte, error) {
return t.getPayload().Encode()
}
func (t *SAuthToken) ParseFernetToken(tokenStr string) error {
func TokenStrDecode(tokenStr string) (*SAuthToken, error) {
token, err := models.TokenCacheManager.FetchToken(tokenStr)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
// not found
token := &SAuthToken{}
err := token.parseFernetToken(tokenStr)
if err != nil {
return nil, errors.Wrap(err, "parseFernetToken")
}
return token, nil
} else {
return nil, errors.Wrap(err, "FetchToken")
}
} else {
if !token.Valid {
return nil, errors.Wrap(httperrors.ErrInvalidCredential, "invalid token")
}
return &SAuthToken{
UserId: token.UserId,
ProjectId: token.ProjectId,
DomainId: token.DomainId,
Method: token.Method,
ExpiresAt: token.ExpiredAt,
AuditIds: strings.Split(token.AuditIds, ","),
Context: mcclient.SAuthContext{
Source: token.Source,
Ip: token.Ip,
},
}, nil
}
}
func (t *SAuthToken) parseFernetToken(tokenStr string) error {
tk := keys.TokenKeysManager.Decrypt([]byte(tokenStr)) // , time.Duration(options.Options.TokenExpirationSeconds)*time.Second)
if tk == nil {
return errors.Wrapf(ErrInvalidToken, tokenStr)
@@ -189,7 +228,7 @@ func (t *SAuthToken) ParseFernetToken(tokenStr string) error {
return nil
}
func (t *SAuthToken) EncodeFernetToken() (string, error) {
func (t *SAuthToken) encodeFernetToken() (string, error) {
tk, err := t.Encode()
if err != nil {
return "", errors.Wrap(err, "encode error")
@@ -201,6 +240,14 @@ func (t *SAuthToken) EncodeFernetToken() (string, error) {
return string(ftk), nil
}
func (t *SAuthToken) encodeShortToken() (string, error) {
tk, err := t.encodeFernetToken()
if err != nil {
return "", errors.Wrap(err, "encodeFernetToken")
}
return stringutils2.GenId(tk), nil
}
func (t *SAuthToken) GetSimpleUserCred(token string) (mcclient.TokenCredential, error) {
userExt, err := models.UserManager.FetchUserExtended(t.UserId, "", "", "")
if err != nil {
@@ -286,7 +333,7 @@ func (t *SAuthToken) getTokenV3(
token.Token.User.IsSystemAccount = user.IsSystemAccount
token.Token.Context = t.Context
tk, err := t.EncodeFernetToken()
tk, err := t.encodeShortToken()
if err != nil {
return nil, errors.Wrap(err, "EncodeFernetToken")
}
@@ -356,9 +403,9 @@ func (t *SAuthToken) getTokenV3(
}
policyNames, _, _ := models.RolePolicyManager.GetMatchPolicyGroup(&token, time.Time{}, true)
token.Token.Policies.Project, _ = policyNames[rbacscope.ScopeProject]
token.Token.Policies.Domain, _ = policyNames[rbacscope.ScopeDomain]
token.Token.Policies.System, _ = policyNames[rbacscope.ScopeSystem]
token.Token.Policies.Project = policyNames[rbacscope.ScopeProject]
token.Token.Policies.Domain = policyNames[rbacscope.ScopeDomain]
token.Token.Policies.System = policyNames[rbacscope.ScopeSystem]
endpoints, err := models.EndpointManager.FetchAll()
if err != nil {
@@ -368,6 +415,15 @@ func (t *SAuthToken) getTokenV3(
token.Token.Catalog = endpoints.GetKeystoneCatalogV3()
}
}
{
err := models.TokenCacheManager.Save(ctx, token.Id, t.ExpiresAt, t.Method, t.AuditIds, t.UserId, t.ProjectId, t.DomainId, t.Context.Source, t.Context.Ip)
if err != nil {
return nil, errors.Wrap(err, "Save Token")
}
cache.Save(token.Id, &token)
}
return &token, nil
}
@@ -383,7 +439,7 @@ func (t *SAuthToken) getTokenV2(
token.User.IsSystemAccount = user.IsSystemAccount
token.Context = t.Context
tk, err := t.EncodeFernetToken()
tk, err := t.encodeShortToken()
if err != nil {
return nil, errors.Wrap(err, "EncodeFernetToken")
}
@@ -435,5 +491,13 @@ func (t *SAuthToken) getTokenV2(
}
}
{
err := models.TokenCacheManager.Save(ctx, token.Token.Id, t.ExpiresAt, t.Method, t.AuditIds, t.UserId, t.ProjectId, t.DomainId, t.Context.Source, t.Context.Ip)
if err != nil {
return nil, errors.Wrap(err, "Save Token")
}
cache.Save(token.Token.Id, &token)
}
return &token, nil
}
+1 -2
View File
@@ -24,8 +24,7 @@ import (
)
func FernetTokenVerifier(ctx context.Context, tokenStr string) (mcclient.TokenCredential, error) {
token := SAuthToken{}
err := token.ParseFernetToken(tokenStr)
token, err := TokenStrDecode(tokenStr)
if err != nil {
return nil, httperrors.NewInvalidCredentialError("invalid token %s", err)
}
+28
View File
@@ -0,0 +1,28 @@
// 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 (
"crypto/sha256"
"fmt"
)
func GenId(ids ...string) string {
h := sha256.New()
for _, id := range ids {
h.Write([]byte(id))
}
return fmt.Sprintf("%x", h.Sum(nil))
}