mirror of
https://github.com/cubefs/cubefs.git
synced 2026-08-02 02:00:56 +00:00
1. sts federation token 2. signature auth code refactor Signed-off-by: yhjiango <jiangyunhua@oppo.com>
176 lines
4.5 KiB
Go
176 lines
4.5 KiB
Go
// Copyright 2023 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 objectnode
|
|
|
|
import (
|
|
"crypto/aes"
|
|
"crypto/cipher"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"encoding/xml"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/cubefs/cubefs/proto"
|
|
)
|
|
|
|
const (
|
|
stsAkPrefix = "STS"
|
|
stsSep = ";;sts;;"
|
|
|
|
stsActionKey = "Action"
|
|
stsActionValue = "GetFederationToken"
|
|
stsPolicyKey = "Policy"
|
|
stsNameKey = "Name"
|
|
stsDurationSecondsKey = "DurationSeconds"
|
|
)
|
|
|
|
type FederationTokenResponse struct {
|
|
XMLName *xml.Name `xml:"GetFederationTokenResponse"`
|
|
GetFederationTokenResult *FederationTokenResult `xml:"GetFederationTokenResult"`
|
|
ResponseMetadata struct {
|
|
RequestID string `xml:"RequestId,omitempty"`
|
|
} `xml:"ResponseMetadata,omitempty"`
|
|
}
|
|
|
|
type FederationTokenResult struct {
|
|
Credentials *FederatedCredentials `xml:"Credentials"`
|
|
FederatedUser *FederatedUser `xml:"FederatedUser"`
|
|
PackedPolicySize int `xml:",omitempty"`
|
|
}
|
|
|
|
type FederatedUser struct {
|
|
Arn string `xml:"Arn"`
|
|
FederatedUserId string `xml:"FederatedUserId"`
|
|
}
|
|
|
|
type FederatedCredentials struct {
|
|
AccessKeyId string `xml:"AccessKeyId"`
|
|
SecretAccessKey string `xml:"SecretAccessKey"`
|
|
SessionToken string `xml:"SessionToken"`
|
|
Expiration string `xml:"Expiration"`
|
|
}
|
|
|
|
func EncodeFedSessionToken(ownerAk, ownerSk, fedAk, fedSk, name, policy, expireUnix string) (token string, err error) {
|
|
encoding, err := NewStsEncoding(fedAk, ownerSk)
|
|
if err != nil {
|
|
return
|
|
}
|
|
toEncrypt := strings.Join([]string{
|
|
fedAk,
|
|
fedSk,
|
|
name,
|
|
policy,
|
|
expireUnix,
|
|
}, stsSep)
|
|
token = base64.URLEncoding.EncodeToString([]byte(ownerAk + stsSep + encoding.Encrypt([]byte(toEncrypt))))
|
|
return
|
|
}
|
|
|
|
type FedDecodeResult struct {
|
|
FedSK string
|
|
Policy *PolicyV2
|
|
UserInfo *proto.UserInfo
|
|
}
|
|
|
|
func DecodeFedSessionToken(fedAk, session string, getUserInfo func(ak string) (*proto.UserInfo, error)) (*FedDecodeResult, error) {
|
|
if !strings.HasPrefix(fedAk, stsAkPrefix) {
|
|
return nil, InvalidAccessKeyId
|
|
}
|
|
token, err := base64.URLEncoding.DecodeString(session)
|
|
if err != nil {
|
|
return nil, InvalidToken
|
|
}
|
|
|
|
tokens := strings.Split(string(token), stsSep)
|
|
if len(tokens) != 2 {
|
|
return nil, InvalidToken
|
|
}
|
|
ownerAk, encryption := tokens[0], tokens[1]
|
|
userInfo, err := getUserInfo(ownerAk)
|
|
if err != nil {
|
|
return nil, InvalidToken
|
|
}
|
|
encoding, err := NewStsEncoding(fedAk, userInfo.SecretKey)
|
|
if err != nil {
|
|
return nil, InvalidToken
|
|
}
|
|
decryptInfo, err := encoding.Decrypt(encryption)
|
|
if err != nil {
|
|
return nil, InvalidToken
|
|
}
|
|
|
|
parts := strings.Split(string(decryptInfo), stsSep)
|
|
if len(parts) != 5 {
|
|
return nil, InvalidToken
|
|
}
|
|
fedAk1, fedSk, policyStr, expireUnixStr := parts[0], parts[1], parts[3], parts[4]
|
|
if fedAk != fedAk1 {
|
|
return nil, InvalidToken
|
|
}
|
|
|
|
expireUnix, err := strconv.ParseInt(expireUnixStr, 10, 64)
|
|
if err != nil {
|
|
return nil, InvalidToken
|
|
}
|
|
if time.Now().UTC().Unix() > expireUnix {
|
|
return nil, ExpiredToken
|
|
}
|
|
|
|
var policy PolicyV2
|
|
if err = json.Unmarshal([]byte(policyStr), &policy); err != nil {
|
|
return nil, InvalidToken
|
|
}
|
|
|
|
return &FedDecodeResult{UserInfo: userInfo, FedSK: fedSk, Policy: &policy}, nil
|
|
}
|
|
|
|
func NewStsEncoding(block, key string) (*StsEncoding, error) {
|
|
bk, err := aes.NewCipher(MakeSha256([]byte(block)))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &StsEncoding{
|
|
encoding: base64.RawURLEncoding,
|
|
block: bk,
|
|
key: MakeMD5([]byte(key)),
|
|
}, nil
|
|
}
|
|
|
|
type StsEncoding struct {
|
|
encoding *base64.Encoding
|
|
block cipher.Block
|
|
key []byte
|
|
}
|
|
|
|
func (ec *StsEncoding) Encrypt(data []byte) string {
|
|
buf := make([]byte, len(data))
|
|
cfb := cipher.NewCFBEncrypter(ec.block, ec.key)
|
|
cfb.XORKeyStream(buf, data)
|
|
return ec.encoding.EncodeToString(buf)
|
|
}
|
|
|
|
func (ec *StsEncoding) Decrypt(s string) ([]byte, error) {
|
|
data, err := ec.encoding.DecodeString(s)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
buf := make([]byte, len(data))
|
|
cfb := cipher.NewCFBDecrypter(ec.block, ec.key)
|
|
cfb.XORKeyStream(buf, data)
|
|
return buf, nil
|
|
}
|