mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-06-02 05:52:00 +08:00
210 lines
6.4 KiB
Go
210 lines
6.4 KiB
Go
// 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 (
|
|
"context"
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
|
|
"yunion.io/x/log"
|
|
"yunion.io/x/pkg/errors"
|
|
"yunion.io/x/pkg/util/timeutils"
|
|
"yunion.io/x/sqlchemy"
|
|
|
|
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{
|
|
SStandaloneAnonResourceBaseManager: db.NewStandaloneAnonResourceBaseManager(
|
|
STokenCache{},
|
|
"token_cache_tbl",
|
|
"token_cache",
|
|
"token_caches",
|
|
),
|
|
}
|
|
TokenCacheManager.SetVirtualObject(TokenCacheManager)
|
|
TokenCacheManager.TableSpec().AddIndex(false, "deleted", "valid")
|
|
}
|
|
|
|
type STokenCache struct {
|
|
db.SStandaloneAnonResourceBase
|
|
|
|
// Token string `width:"700" charset:"ascii" nullable:"false" primary:"true"`
|
|
ExpiredAt time.Time `nullable:"false"`
|
|
Valid bool
|
|
|
|
Method string `width:"32" charset:"ascii"`
|
|
AuditIds string `width:"512" 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.SStandaloneAnonResourceBaseManager
|
|
}
|
|
|
|
func joinAuditIds(ids []string) string {
|
|
sort.Strings(ids)
|
|
return strings.Join(ids, ",")
|
|
}
|
|
|
|
func (manager *STokenCacheManager) Save(ctx context.Context, tokenStr string, expiredAt time.Time, method string, auditIds []string, userId, projId, domainId, source, ip string) error {
|
|
return manager.insert(ctx, tokenStr, expiredAt, true, method, auditIds, userId, projId, domainId, source, ip)
|
|
}
|
|
|
|
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) 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 errors.Wrap(err, "FetchModelObjects")
|
|
}
|
|
if len(tokens) == 0 {
|
|
return nil
|
|
}
|
|
errs := make([]error, 0)
|
|
for i := range tokens {
|
|
token := tokens[i]
|
|
err := token.invalidate(ctx, userCred)
|
|
if err != nil {
|
|
errs = append(errs, errors.Wrapf(err, "batchInvalidateInternal token %s", token.Id))
|
|
}
|
|
}
|
|
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, userId, projectId, domainId, source, ip string) error {
|
|
val := STokenCache{
|
|
SStandaloneAnonResourceBase: db.SStandaloneAnonResourceBase{
|
|
Id: token,
|
|
},
|
|
ExpiredAt: expiredAt,
|
|
Valid: valid,
|
|
Method: method,
|
|
AuditIds: joinAuditIds(auditIds),
|
|
UserId: userId,
|
|
ProjectId: projectId,
|
|
DomainId: domainId,
|
|
Source: source,
|
|
Ip: ip,
|
|
}
|
|
val.SetModelManager(manager, &val)
|
|
err := manager.TableSpec().InsertOrUpdate(ctx, &val)
|
|
return errors.Wrap(err, "InsertOrUpdate")
|
|
}
|
|
|
|
func (manager *STokenCacheManager) FetchToken(tokenStr string) (*STokenCache, error) {
|
|
obj, err := manager.FetchById(tokenStr)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "FetchById")
|
|
}
|
|
return obj.(*STokenCache), nil
|
|
}
|
|
|
|
func (manager *STokenCacheManager) removeObsolete() error {
|
|
sql := fmt.Sprintf("DELETE FROM %s WHERE expired_at < ?", manager.TableSpec().Name())
|
|
db := sqlchemy.GetDBWithName(manager.TableSpec().GetDBName())
|
|
now := timeutils.UtcNow()
|
|
_, err := db.Exec(sql, now.Add(-24*time.Hour))
|
|
return errors.Wrap(err, "Exec Delete")
|
|
}
|
|
|
|
func RemoveObsoleteInvalidTokens(ctx context.Context, userCred mcclient.TokenCredential, start bool) {
|
|
err := TokenCacheManager.removeObsolete()
|
|
if err != nil {
|
|
log.Errorf("RemoveObsoleteInvalidTokens fail %s", err)
|
|
}
|
|
}
|
|
|
|
func (manager *STokenCacheManager) FetchInvalidTokens() ([]string, error) {
|
|
q := manager.Query("id").IsFalse("valid")
|
|
tokens := make([]STokenCache, 0)
|
|
err := db.FetchModelObjects(manager, q, &tokens)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "FetchModelObjects")
|
|
}
|
|
ret := make([]string, len(tokens))
|
|
for i := range tokens {
|
|
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
|
|
}
|