mirror of
https://github.com/cubefs/cubefs.git
synced 2026-08-02 02:00:56 +00:00
247 lines
6.6 KiB
Go
247 lines
6.6 KiB
Go
// Copyright 2018 The CubeFS Authors.
|
|
//
|
|
// 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 authnode
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/cubefs/cubefs/proto"
|
|
"github.com/cubefs/cubefs/raftstore"
|
|
"github.com/cubefs/cubefs/util"
|
|
"github.com/cubefs/cubefs/util/caps"
|
|
"github.com/cubefs/cubefs/util/cryptoutil"
|
|
"github.com/cubefs/cubefs/util/errors"
|
|
"github.com/cubefs/cubefs/util/keystore"
|
|
"github.com/cubefs/cubefs/util/log"
|
|
)
|
|
|
|
// PKIKey defines the pki keys
|
|
type PKIKey struct {
|
|
EnableHTTPS bool
|
|
AuthRootPrivateKey []byte
|
|
AuthRootPublicKey []byte
|
|
}
|
|
|
|
// Cluster stores all the cluster-level information.
|
|
type Cluster struct {
|
|
Name string
|
|
leaderInfo *LeaderInfo
|
|
cfg *clusterConfig
|
|
retainLogs uint64
|
|
DisableAutoAllocate bool
|
|
fsm *KeystoreFsm
|
|
partition raftstore.Partition
|
|
AuthSecretKey []byte
|
|
AuthRootKey []byte
|
|
PKIKey PKIKey
|
|
}
|
|
|
|
func newCluster(name string, leaderInfo *LeaderInfo, fsm *KeystoreFsm, partition raftstore.Partition, cfg *clusterConfig) (c *Cluster) {
|
|
c = new(Cluster)
|
|
c.Name = name
|
|
c.leaderInfo = leaderInfo
|
|
c.cfg = cfg
|
|
c.fsm = fsm
|
|
c.partition = partition
|
|
c.fsm.keystore = make(map[string]*keystore.KeyInfo)
|
|
c.fsm.accessKeystore = make(map[string]*keystore.AccessKeyInfo)
|
|
return
|
|
}
|
|
|
|
func (c *Cluster) scheduleTask() {
|
|
c.scheduleToCheckHeartbeat()
|
|
}
|
|
|
|
func (c *Cluster) scheduleToCheckHeartbeat() {
|
|
go func() {
|
|
for {
|
|
if c.partition != nil && c.partition.IsRaftLeader() {
|
|
c.checkLeaderAddr()
|
|
}
|
|
time.Sleep(time.Second * defaultIntervalToCheckHeartbeat)
|
|
}
|
|
}()
|
|
}
|
|
|
|
func (c *Cluster) checkLeaderAddr() {
|
|
leaderID, _ := c.partition.LeaderTerm()
|
|
c.leaderInfo.addr = AddrDatabase[leaderID]
|
|
}
|
|
|
|
// CreateNewKey create a new key to the keystore
|
|
func (c *Cluster) CreateNewKey(id string, keyInfo *keystore.KeyInfo) (res *keystore.KeyInfo, err error) {
|
|
c.fsm.opKeyMutex.Lock()
|
|
defer c.fsm.opKeyMutex.Unlock()
|
|
accessKeyInfo := &keystore.AccessKeyInfo{
|
|
ID: keyInfo.ID,
|
|
}
|
|
if _, err = c.fsm.GetKey(id); err == nil {
|
|
err = proto.ErrDuplicateKey
|
|
goto errHandler
|
|
}
|
|
keyInfo.Ts = time.Now().Unix()
|
|
keyInfo.AuthKey = cryptoutil.GenSecretKey([]byte(c.AuthRootKey), keyInfo.Ts, id)
|
|
// TODO check duplicate
|
|
keyInfo.AccessKey = util.RandomString(16, util.Numeric|util.LowerLetter|util.UpperLetter)
|
|
keyInfo.SecretKey = util.RandomString(32, util.Numeric|util.LowerLetter|util.UpperLetter)
|
|
if err = c.syncAddKey(keyInfo); err != nil {
|
|
goto errHandler
|
|
}
|
|
accessKeyInfo.AccessKey = keyInfo.AccessKey
|
|
if err = c.syncAddAccessKey(accessKeyInfo); err != nil {
|
|
goto errHandler
|
|
}
|
|
res = keyInfo
|
|
c.fsm.PutKey(keyInfo)
|
|
c.fsm.PutAKInfo(accessKeyInfo)
|
|
return
|
|
errHandler:
|
|
err = fmt.Errorf("action[CreateNewKey], clusterID[%v] ID:%v, err:%v ", c.Name, keyInfo, err.Error())
|
|
log.LogError(errors.Stack(err))
|
|
return
|
|
}
|
|
|
|
// DeleteKey delete a key from the keystore
|
|
func (c *Cluster) DeleteKey(id string) (res *keystore.KeyInfo, err error) {
|
|
c.fsm.opKeyMutex.Lock()
|
|
defer c.fsm.opKeyMutex.Unlock()
|
|
akInfo := new(keystore.AccessKeyInfo)
|
|
if res, err = c.fsm.GetKey(id); err != nil {
|
|
err = proto.ErrKeyNotExists
|
|
goto errHandler
|
|
}
|
|
if err = c.syncDeleteKey(res); err != nil {
|
|
goto errHandler
|
|
}
|
|
akInfo.AccessKey = res.AccessKey
|
|
akInfo.ID = res.ID
|
|
if err = c.syncDeleteAccessKey(akInfo); err != nil {
|
|
goto errHandler
|
|
}
|
|
c.fsm.DeleteKey(id)
|
|
c.fsm.DeleteAKInfo(akInfo.AccessKey)
|
|
return
|
|
errHandler:
|
|
err = fmt.Errorf("action[DeleteKey], clusterID[%v] ID:%v, err:%v ", c.Name, id, err.Error())
|
|
log.LogError(errors.Stack(err))
|
|
return
|
|
}
|
|
|
|
// GetKey get a key from the keystore
|
|
func (c *Cluster) GetKey(id string) (res *keystore.KeyInfo, err error) {
|
|
if res, err = c.fsm.GetKey(id); err != nil {
|
|
err = proto.ErrKeyNotExists
|
|
goto errHandler
|
|
}
|
|
return
|
|
errHandler:
|
|
err = fmt.Errorf("action[GetKey], clusterID[%v] ID:%v, err:%v ", c.Name, id, err.Error())
|
|
log.LogError(errors.Stack(err))
|
|
return
|
|
}
|
|
|
|
// GetKey get a key from the AKstore
|
|
func (c *Cluster) GetAKInfo(accessKey string) (akInfo *keystore.AccessKeyInfo, err error) {
|
|
if akInfo, err = c.fsm.GetAKInfo(accessKey); err != nil {
|
|
err = proto.ErrAccessKeyNotExists
|
|
goto errHandler
|
|
}
|
|
return
|
|
errHandler:
|
|
err = fmt.Errorf("action[GetAKInfo], clusterID[%v] ID:%v, err:%v ", c.Name, accessKey, err.Error())
|
|
log.LogError(errors.Stack(err))
|
|
return
|
|
}
|
|
|
|
// AddCaps add caps to the key
|
|
func (c *Cluster) AddCaps(id string, keyInfo *keystore.KeyInfo) (res *keystore.KeyInfo, err error) {
|
|
var (
|
|
addCaps *caps.Caps
|
|
curCaps *caps.Caps
|
|
newCaps []byte
|
|
)
|
|
c.fsm.opKeyMutex.Lock()
|
|
defer c.fsm.opKeyMutex.Unlock()
|
|
if res, err = c.fsm.GetKey(id); err != nil {
|
|
err = proto.ErrKeyNotExists
|
|
goto errHandler
|
|
}
|
|
|
|
addCaps = &caps.Caps{}
|
|
if err = addCaps.Init(keyInfo.Caps); err != nil {
|
|
goto errHandler
|
|
}
|
|
curCaps = &caps.Caps{}
|
|
if err = curCaps.Init(res.Caps); err != nil {
|
|
goto errHandler
|
|
}
|
|
curCaps.Union(addCaps)
|
|
if newCaps, err = json.Marshal(curCaps); err != nil {
|
|
goto errHandler
|
|
}
|
|
res.Caps = newCaps
|
|
if err = c.syncAddCaps(res); err != nil {
|
|
goto errHandler
|
|
}
|
|
c.fsm.PutKey(res)
|
|
return
|
|
errHandler:
|
|
err = fmt.Errorf("action[AddCaps], clusterID[%v] ID:%v, err:%v ", c.Name, keyInfo, err.Error())
|
|
log.LogError(errors.Stack(err))
|
|
return
|
|
}
|
|
|
|
// DeleteCaps delete caps from the key
|
|
func (c *Cluster) DeleteCaps(id string, keyInfo *keystore.KeyInfo) (res *keystore.KeyInfo, err error) {
|
|
var (
|
|
delCaps *caps.Caps
|
|
curCaps *caps.Caps
|
|
newCaps []byte
|
|
)
|
|
c.fsm.opKeyMutex.Lock()
|
|
defer c.fsm.opKeyMutex.Unlock()
|
|
if res, err = c.fsm.GetKey(id); err != nil {
|
|
err = proto.ErrKeyNotExists
|
|
goto errHandler
|
|
}
|
|
|
|
delCaps = &caps.Caps{}
|
|
if err = delCaps.Init(keyInfo.Caps); err != nil {
|
|
return
|
|
}
|
|
curCaps = &caps.Caps{}
|
|
if err = curCaps.Init(res.Caps); err != nil {
|
|
return
|
|
}
|
|
|
|
curCaps.Delete(delCaps)
|
|
|
|
if newCaps, err = json.Marshal(curCaps); err != nil {
|
|
goto errHandler
|
|
}
|
|
res.Caps = newCaps
|
|
if err = c.syncDeleteCaps(res); err != nil {
|
|
goto errHandler
|
|
}
|
|
c.fsm.PutKey(res)
|
|
return
|
|
errHandler:
|
|
err = fmt.Errorf("action[DeleteCaps], clusterID[%v] ID:%v, err:%v ", c.Name, keyInfo, err.Error())
|
|
log.LogError(errors.Stack(err))
|
|
return
|
|
}
|