mirror of
https://github.com/cubefs/cubefs.git
synced 2026-08-02 02:00:56 +00:00
799 lines
26 KiB
Go
799 lines
26 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 proto
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/binary"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"regexp"
|
|
"time"
|
|
|
|
"github.com/cubefs/cubefs/util/caps"
|
|
"github.com/cubefs/cubefs/util/cryptoutil"
|
|
"github.com/cubefs/cubefs/util/keystore"
|
|
)
|
|
|
|
// ServiceID defines the type of tickets
|
|
type ServiceID uint32
|
|
|
|
// MsgType defines the type of req/resp for message
|
|
type MsgType uint32
|
|
|
|
// Nonce defines the nonce to mitigate the replay attack
|
|
type Nonce uint64
|
|
|
|
const (
|
|
APIRsc = "API"
|
|
APIAccess = "access"
|
|
capSeparator = ":"
|
|
reqLiveLength = 10
|
|
ClientMessage = "Token"
|
|
OwnerVOLRsc = "OwnerVOL"
|
|
NoneOwnerVOLRsc = "NoneOwnerVOL"
|
|
VOLAccess = "*"
|
|
)
|
|
|
|
// api
|
|
const (
|
|
// Client APIs
|
|
ClientGetTicket = "/client/getticket"
|
|
|
|
// Admin APIs
|
|
AdminCreateKey = "/admin/createkey"
|
|
AdminDeleteKey = "/admin/deletekey"
|
|
AdminGetKey = "/admin/getkey"
|
|
AdminAddCaps = "/admin/addcaps"
|
|
AdminDeleteCaps = "/admin/deletecaps"
|
|
AdminGetCaps = "/admin/getcaps"
|
|
|
|
// raft node APIs
|
|
AdminAddRaftNode = "/admin/addraftnode"
|
|
AdminRemoveRaftNode = "/admin/removeraftnode"
|
|
|
|
// Object node APIs
|
|
OSAddCaps = "/os/addcaps"
|
|
OSDeleteCaps = "/os/deletecaps"
|
|
OSGetCaps = "/os/getcaps"
|
|
)
|
|
|
|
const (
|
|
// AuthServiceID defines ticket for authnode access (not supported)
|
|
AuthServiceID = "AuthService"
|
|
|
|
// MasterServiceID defines ticket for master access
|
|
MasterServiceID = "MasterService"
|
|
|
|
// MetaServiceID defines ticket for metanode access (not supported)
|
|
MetaServiceID = "MetanodeService"
|
|
|
|
// DataServiceID defines ticket for datanode access (not supported)
|
|
DataServiceID = "DatanodeService"
|
|
|
|
// ObjectServiceID defines ticket for objectnode access
|
|
ObjectServiceID = "ObjectService"
|
|
)
|
|
|
|
const (
|
|
MasterNode = "master"
|
|
MetaNode = "metanode"
|
|
DataNode = "datanode"
|
|
)
|
|
|
|
const (
|
|
// MsgAuthBase define the starting value for auth message
|
|
MsgAuthBase MsgType = 0x100000
|
|
|
|
// MsgAuthTicketReq request type for an auth ticket
|
|
MsgAuthTicketReq MsgType = MsgAuthBase + 0x10000
|
|
|
|
// MsgAuthTicketResp respose type for an auth ticket
|
|
MsgAuthTicketResp MsgType = MsgAuthBase + 0x10001
|
|
|
|
// MsgMasterTicketReq request type for a master ticket
|
|
MsgMasterTicketReq MsgType = MsgAuthBase + 0x20000
|
|
|
|
// MsgMasterTicketResp response type for a master ticket
|
|
MsgMasterTicketResp MsgType = MsgAuthBase + 0x20001
|
|
|
|
// MsgMetaTicketReq request type for a metanode ticket
|
|
MsgMetaTicketReq MsgType = MsgAuthBase + 0x30000
|
|
|
|
// MsgMetaTicketResp response type for a metanode ticket
|
|
MsgMetaTicketResp MsgType = MsgAuthBase + 0x30001
|
|
|
|
// MsgDataTicketReq request type for a datanode ticket
|
|
MsgDataTicketReq MsgType = MsgAuthBase + 0x40000
|
|
|
|
// MsgDataTicketResp response type for a datanode ticket
|
|
MsgDataTicketResp MsgType = MsgAuthBase + 0x40001
|
|
|
|
// MsgAuthCreateKeyReq request type for authnode add key
|
|
MsgAuthCreateKeyReq MsgType = MsgAuthBase + 0x51000
|
|
|
|
// MsgAuthCreateKeyResp response type for authnode add key
|
|
MsgAuthCreateKeyResp MsgType = MsgAuthBase + 0x51001
|
|
|
|
// MsgAuthDeleteKeyReq request type for authnode delete key
|
|
MsgAuthDeleteKeyReq MsgType = MsgAuthBase + 0x52000
|
|
|
|
// MsgAuthDeleteKeyResp response type for authnode delete key
|
|
MsgAuthDeleteKeyResp MsgType = MsgAuthBase + 0x52001
|
|
|
|
// MsgAuthGetKeyReq request type for authnode get key info
|
|
MsgAuthGetKeyReq MsgType = MsgAuthBase + 0x53000
|
|
|
|
// MsgAuthGetKeyResp response type for authnode get key info
|
|
MsgAuthGetKeyResp MsgType = MsgAuthBase + 0x53001
|
|
|
|
// MsgAuthAddCapsReq request type for authnode add caps
|
|
MsgAuthAddCapsReq MsgType = MsgAuthBase + 0x54000
|
|
|
|
// MsgAuthAddCapsResp response type for authnode add caps
|
|
MsgAuthAddCapsResp MsgType = MsgAuthBase + 0x54001
|
|
|
|
// MsgAuthDeleteCapsReq request type for authnode add caps
|
|
MsgAuthDeleteCapsReq MsgType = MsgAuthBase + 0x55000
|
|
|
|
// MsgAuthDeleteCapsResp response type for authnode add caps
|
|
MsgAuthDeleteCapsResp MsgType = MsgAuthBase + 0x55001
|
|
|
|
// MsgAuthGetCapsReq request type for authnode add caps
|
|
MsgAuthGetCapsReq MsgType = MsgAuthBase + 0x56000
|
|
|
|
// MsgAuthGetCapsResp response type for authnode add caps
|
|
MsgAuthGetCapsResp MsgType = MsgAuthBase + 0x56001
|
|
|
|
// MsgAuthAddRaftNodeReq request type for authnode add node
|
|
MsgAuthAddRaftNodeReq MsgType = MsgAuthBase + 0x57000
|
|
|
|
// MsgAuthAddRaftNodeResp response type for authnode remove node
|
|
MsgAuthAddRaftNodeResp MsgType = MsgAuthBase + 0x57001
|
|
|
|
// MsgAuthRemoveRaftNodeReq request type for authnode remove node
|
|
MsgAuthRemoveRaftNodeReq MsgType = MsgAuthBase + 0x58000
|
|
|
|
// MsgAuthRemoveRaftNodeResp response type for authnode remove node
|
|
MsgAuthRemoveRaftNodeResp MsgType = MsgAuthBase + 0x58001
|
|
|
|
// MsgAuthOSAddCapsReq request type from ObjectNode to add caps
|
|
MsgAuthOSAddCapsReq MsgType = MsgAuthBase + 0x61000
|
|
|
|
// MsgAuthOSAddCapsResp request type from ObjectNode to add caps
|
|
MsgAuthOSAddCapsResp MsgType = MsgAuthBase + 0x61001
|
|
|
|
// MsgAuthOSDeleteCapsReq request type from ObjectNode to delete caps
|
|
MsgAuthOSDeleteCapsReq MsgType = MsgAuthBase + 0x62000
|
|
|
|
// MsgAuthOSDeleteCapsResp request type from ObjectNode to delete caps
|
|
MsgAuthOSDeleteCapsResp MsgType = MsgAuthBase + 0x62001
|
|
|
|
// MsgAuthOSGetCapsReq request type from ObjectNode to get caps
|
|
MsgAuthOSGetCapsReq MsgType = MsgAuthBase + 0x63000
|
|
|
|
// MsgAuthOSGetCapsResp response type from ObjectNode to get caps
|
|
MsgAuthOSGetCapsResp MsgType = MsgAuthBase + 0x63001
|
|
|
|
// MsgMasterAPIAccessReq request type for master api access
|
|
MsgMasterAPIAccessReq MsgType = 0x60000
|
|
|
|
// MsgMasterAPIAccessResp response type for master api access
|
|
MsgMasterAPIAccessResp MsgType = 0x60001
|
|
|
|
// Master API ClientVol
|
|
MsgMasterFetchVolViewReq MsgType = MsgMasterAPIAccessReq + 0x10000
|
|
|
|
// Master API cluster management
|
|
MsgMasterClusterFreezeReq MsgType = MsgMasterAPIAccessReq + 0x20100
|
|
MsgMasterAddRaftNodeReq MsgType = MsgMasterAPIAccessReq + 0x20200
|
|
MsgMasterRemoveRaftNodeReq MsgType = MsgMasterAPIAccessReq + 0x20300
|
|
MsgMasterSetNodeInfoReq MsgType = MsgMasterAPIAccessReq + 0x20400
|
|
MsgMasterSetNodeRdOnlyReq MsgType = MsgMasterAPIAccessReq + 0x20500
|
|
MsgMasterAutoDecommissionReq MsgType = MsgMasterAPIAccessReq + 0x20600
|
|
|
|
// Master API volume management
|
|
MsgMasterCreateVolReq MsgType = MsgMasterAPIAccessReq + 0x30100
|
|
MsgMasterDeleteVolReq MsgType = MsgMasterAPIAccessReq + 0x30200
|
|
MsgMasterUpdateVolReq MsgType = MsgMasterAPIAccessReq + 0x30300
|
|
MsgMasterVolShrinkReq MsgType = MsgMasterAPIAccessReq + 0x30400
|
|
MsgMasterVolExpandReq MsgType = MsgMasterAPIAccessReq + 0x30500
|
|
MsgMasterVolAddAllowedStorageClass MsgType = MsgMasterAPIAccessReq + 0x30501
|
|
|
|
// Master API meta partition management
|
|
MsgMasterLoadMetaPartitionReq MsgType = MsgMasterAPIAccessReq + 0x40100
|
|
MsgMasterDecommissionMetaPartitionReq MsgType = MsgMasterAPIAccessReq + 0x40200
|
|
MsgMasterChangeMetaPartitionLeaderReq MsgType = MsgMasterAPIAccessReq + 0x40300
|
|
MsgMasterCreateMetaPartitionReq MsgType = MsgMasterAPIAccessReq + 0x40400
|
|
MsgMasterAddMetaReplicaReq MsgType = MsgMasterAPIAccessReq + 0x40500
|
|
MsgMasterDeleteMetaReplicaReq MsgType = MsgMasterAPIAccessReq + 0x40600
|
|
MsgMasterQosUpdateReq MsgType = MsgMasterAPIAccessReq + 0x40700
|
|
MsgMasterQosUpdateZoneLimitReq MsgType = MsgMasterAPIAccessReq + 0x40800
|
|
MsgMasterQosUpdateMasterLimitReq MsgType = MsgMasterAPIAccessReq + 0x40900
|
|
MsgMasterQosUpdateClientParamReq MsgType = MsgMasterAPIAccessReq + 0x40a00
|
|
|
|
// Master API data partition management
|
|
MsgMasterCreateDataPartitionReq MsgType = MsgMasterAPIAccessReq + 0x50100
|
|
MsgMasterDataPartitionChangeLeaderReq MsgType = MsgMasterAPIAccessReq + 0x50200
|
|
MsgMasterLoadDataPartitionReq MsgType = MsgMasterAPIAccessReq + 0x50300
|
|
MsgMasterDecommissionDataPartitionReq MsgType = MsgMasterAPIAccessReq + 0x50400
|
|
MsgMasterAddDataReplicaReq MsgType = MsgMasterAPIAccessReq + 0x50500
|
|
MsgMasterDeleteDataReplicaReq MsgType = MsgMasterAPIAccessReq + 0x50600
|
|
MsgMasterSetDpRdOnlyReq MsgType = MsgMasterAPIAccessReq + 0x50700
|
|
MsgMasterReportLackDataPartitions MsgType = MsgMasterAPIAccessReq + 0x50800
|
|
|
|
// Master API meta node management
|
|
MsgMasterAddMetaNodeReq MsgType = MsgMasterAPIAccessReq + 0x60100
|
|
MsgMasterDecommissionMetaNodeReq MsgType = MsgMasterAPIAccessReq + 0x60200
|
|
MsgMasterMigrateMetaNodeReq MsgType = MsgMasterAPIAccessReq + 0x60300
|
|
MsgMasterSetMetaNodeThresholdReq MsgType = MsgMasterAPIAccessReq + 0x60400
|
|
MsgMasterUpdateMetaNodeReq MsgType = MsgMasterAPIAccessReq + 0x60500
|
|
|
|
// Master API data node management
|
|
MsgMasterAddDataNodeReq MsgType = MsgMasterAPIAccessReq + 0x70100
|
|
MsgMasterDecommissionDataNodeReq MsgType = MsgMasterAPIAccessReq + 0x70200
|
|
MsgMasterMigrateDataNodeReq MsgType = MsgMasterAPIAccessReq + 0x70300
|
|
MsgMasterCancelDecommissionDataNodeReq MsgType = MsgMasterAPIAccessReq + 0x70400
|
|
MsgMasterDecommissionDiskReq MsgType = MsgMasterAPIAccessReq + 0x70500
|
|
MsgMasterUpdateNodeSetCapcityReq MsgType = MsgMasterAPIAccessReq + 0x70600
|
|
MsgMasterUpdateNodeSetIdReq MsgType = MsgMasterAPIAccessReq + 0x70700
|
|
MsgMasterUpdateDomainDataUseRatioReq MsgType = MsgMasterAPIAccessReq + 0x70800
|
|
MsgMasterUpdateZoneExcludeRatioReq MsgType = MsgMasterAPIAccessReq + 0x70900
|
|
MsgMasterRecommissionDiskReq MsgType = MsgMasterAPIAccessReq + 0x70a00
|
|
|
|
// Master API user management
|
|
MsgMasterUserCreateReq MsgType = MsgMasterAPIAccessReq + 0x80100
|
|
MsgMasterUserDeleteReq MsgType = MsgMasterAPIAccessReq + 0x80200
|
|
MsgMasterUserUpdateReq MsgType = MsgMasterAPIAccessReq + 0x80300
|
|
MsgMasterUserUpdatePolicyReq MsgType = MsgMasterAPIAccessReq + 0x80400
|
|
MsgMasterUserRemovePolicyReq MsgType = MsgMasterAPIAccessReq + 0x80500
|
|
MsgMasterUserDeleteVolPolicyReq MsgType = MsgMasterAPIAccessReq + 0x80600
|
|
MsgMasterUserTransferVolReq MsgType = MsgMasterAPIAccessReq + 0x80700
|
|
|
|
// Master API zone management
|
|
MsgMasterUpdateZoneReq MsgType = MsgMasterAPIAccessReq + 0x90100
|
|
)
|
|
|
|
// HTTPAuthReply uniform response structure
|
|
type HTTPAuthReply = HTTPReply
|
|
|
|
// MsgType2ResourceMap define the mapping from message type to resource
|
|
var MsgType2ResourceMap = map[MsgType]string{
|
|
MsgAuthCreateKeyReq: "auth:createkey",
|
|
MsgAuthDeleteKeyReq: "auth:deletekey",
|
|
MsgAuthGetKeyReq: "auth:getkey",
|
|
MsgAuthAddCapsReq: "auth:addcaps",
|
|
MsgAuthDeleteCapsReq: "auth:deletecaps",
|
|
MsgAuthGetCapsReq: "auth:getcaps",
|
|
MsgAuthAddRaftNodeReq: "auth:addnode",
|
|
MsgAuthRemoveRaftNodeReq: "auth:removenode",
|
|
MsgAuthOSAddCapsReq: "auth:osaddcaps",
|
|
MsgAuthOSDeleteCapsReq: "auth:osdeletecaps",
|
|
MsgAuthOSGetCapsReq: "auth:osgetcaps",
|
|
|
|
MsgMasterFetchVolViewReq: "master:getvol",
|
|
|
|
// Master API cluster management
|
|
MsgMasterClusterFreezeReq: "master:clusterfreeze",
|
|
MsgMasterAddRaftNodeReq: "master:addraftnode",
|
|
MsgMasterRemoveRaftNodeReq: "master:removeraftnode",
|
|
MsgMasterSetNodeInfoReq: "master:setnodeinfo",
|
|
MsgMasterSetNodeRdOnlyReq: "master:sernoderdonly",
|
|
MsgMasterAutoDecommissionReq: "master:autodecommission",
|
|
|
|
// Master API volume management
|
|
MsgMasterCreateVolReq: "master:createvol",
|
|
MsgMasterDeleteVolReq: "master:deletevol",
|
|
MsgMasterUpdateVolReq: "master:updatevol",
|
|
MsgMasterVolShrinkReq: "master:volshrink",
|
|
MsgMasterVolExpandReq: "master:volexpand",
|
|
MsgMasterVolAddAllowedStorageClass: "master:voladdallowedStorageClass",
|
|
|
|
// Master API meta partition management
|
|
MsgMasterLoadMetaPartitionReq: "master:loadmetapartition",
|
|
MsgMasterDecommissionMetaPartitionReq: "master:decommissionmetapartition",
|
|
MsgMasterChangeMetaPartitionLeaderReq: "master:changemetapartitionleader",
|
|
MsgMasterCreateMetaPartitionReq: "master:createmetapartition",
|
|
MsgMasterAddMetaReplicaReq: "master:addmetareplica",
|
|
MsgMasterDeleteMetaReplicaReq: "master:deletemetareplica",
|
|
MsgMasterQosUpdateReq: "master:qosupdate",
|
|
MsgMasterQosUpdateZoneLimitReq: "master:qosupdatezonelimit",
|
|
MsgMasterQosUpdateMasterLimitReq: "master:qosupdatemasterlimit",
|
|
MsgMasterQosUpdateClientParamReq: "master:qosupdateclientparam",
|
|
|
|
// Master API data partition management
|
|
MsgMasterCreateDataPartitionReq: "master:createdatapartition",
|
|
MsgMasterDataPartitionChangeLeaderReq: "master:changedatapartitionleader",
|
|
MsgMasterLoadDataPartitionReq: "master:loaddatapartition",
|
|
MsgMasterDecommissionDataPartitionReq: "master:decommissiondatapartition",
|
|
MsgMasterAddDataReplicaReq: "master:adddatareplica",
|
|
MsgMasterDeleteDataReplicaReq: "master:removedatareplica",
|
|
MsgMasterSetDpRdOnlyReq: "master:setdprdonly",
|
|
MsgMasterReportLackDataPartitions: "master:reportLackDataPartitions",
|
|
|
|
// Master API meta node management
|
|
MsgMasterAddMetaNodeReq: "master:addmetanode",
|
|
MsgMasterDecommissionMetaNodeReq: "master:decommissionmetanode",
|
|
MsgMasterMigrateMetaNodeReq: "master:migratemetanode",
|
|
MsgMasterSetMetaNodeThresholdReq: "master:setmetanodethreshold",
|
|
MsgMasterUpdateMetaNodeReq: "master:updatemetanode",
|
|
|
|
// Master API data node management
|
|
MsgMasterAddDataNodeReq: "master:adddatannode",
|
|
MsgMasterDecommissionDataNodeReq: "master:decommissiondatannode",
|
|
MsgMasterMigrateDataNodeReq: "master:migratedatannode",
|
|
MsgMasterCancelDecommissionDataNodeReq: "master:canceldecommissiondatannode",
|
|
MsgMasterDecommissionDiskReq: "master:decommissiondisk",
|
|
MsgMasterUpdateNodeSetCapcityReq: "master:updatenodesetcapcity",
|
|
MsgMasterUpdateNodeSetIdReq: "master:updatenodesetid",
|
|
MsgMasterUpdateDomainDataUseRatioReq: "master:updatedomaindatauseratio",
|
|
MsgMasterUpdateZoneExcludeRatioReq: "master:updatezoneexcluderatio",
|
|
MsgMasterRecommissionDiskReq: "master:recommissiondisk",
|
|
|
|
// Master API user management
|
|
MsgMasterUserCreateReq: "master:usercreate",
|
|
MsgMasterUserDeleteReq: "master:userdelete",
|
|
MsgMasterUserUpdateReq: "master:userupdate",
|
|
MsgMasterUserUpdatePolicyReq: "master:userupdatepolicy",
|
|
MsgMasterUserRemovePolicyReq: "master:userremotepolicy",
|
|
MsgMasterUserDeleteVolPolicyReq: "master:userdeletevolpolicy",
|
|
MsgMasterUserTransferVolReq: "master:usertransfervol",
|
|
|
|
// Master API zone management
|
|
MsgMasterUpdateZoneReq: "master:updatezone",
|
|
}
|
|
|
|
// AuthGetTicketReq defines the message from client to authnode
|
|
// use Timestamp as verifier for MITM mitigation
|
|
// verifier is also used to verify the server identity
|
|
type AuthGetTicketReq struct {
|
|
Type MsgType `json:"type"`
|
|
ClientID string `json:"client_id"`
|
|
ServiceID string `json:"service_id"`
|
|
Verifier string `json:"verifier"`
|
|
}
|
|
|
|
// AuthGetTicketResp defines the message from authnode to client
|
|
type AuthGetTicketResp struct {
|
|
Type MsgType `json:"type"`
|
|
ClientID string `json:"client_id"`
|
|
ServiceID string `json:"service_id"`
|
|
Verifier int64 `json:"verifier"`
|
|
Ticket string `json:"ticket"`
|
|
SessionKey cryptoutil.CryptoKey `json:"session_key"`
|
|
}
|
|
|
|
// APIAccessReq defines the request for access restful api
|
|
// use Timestamp as verifier for MITM mitigation
|
|
// verifier is also used to verify the server identity
|
|
type APIAccessReq struct {
|
|
Type MsgType `json:"type"`
|
|
ClientID string `json:"client_id"`
|
|
ServiceID string `json:"service_id"`
|
|
Verifier string `json:"verifier"`
|
|
Ticket string `json:"ticket"`
|
|
}
|
|
|
|
// APIAccessResp defines the response for access restful api
|
|
// use Timestamp as verifier for MITM mitigation
|
|
// verifier is also used to verify the server identity
|
|
type APIAccessResp struct {
|
|
Type MsgType `json:"type"`
|
|
ClientID string `json:"client_id"`
|
|
ServiceID string `json:"service_id"`
|
|
Verifier int64 `json:"verifier"`
|
|
}
|
|
|
|
// AuthAPIAccessReq defines Auth API request
|
|
type AuthAPIAccessReq struct {
|
|
APIReq APIAccessReq `json:"api_req"`
|
|
KeyInfo keystore.KeyInfo `json:"key_info"`
|
|
}
|
|
|
|
// AuthAPIAccessResp defines the response for creating an key in authnode
|
|
type AuthAPIAccessResp struct {
|
|
APIResp APIAccessResp `json:"api_resp"`
|
|
KeyInfo keystore.KeyInfo `json:"key_info"`
|
|
AuthIDKey string `json:"auth_id_key"`
|
|
}
|
|
|
|
// AuthRaftNodeInfo defines raft node information
|
|
type AuthRaftNodeInfo struct {
|
|
ID uint64 `json:"id"`
|
|
Addr string `json:"addr"`
|
|
}
|
|
|
|
// AuthRaftNodeReq defines Auth API request for add/remove a raft node
|
|
type AuthRaftNodeReq struct {
|
|
APIReq APIAccessReq `json:"api_req"`
|
|
RaftNodeInfo AuthRaftNodeInfo `json:"node_info"`
|
|
}
|
|
|
|
// AuthRaftNodeResp defines Auth API response for add/remove a raft node
|
|
type AuthRaftNodeResp struct {
|
|
APIResp APIAccessResp `json:"api_resp"`
|
|
Msg string `json:"msg"`
|
|
}
|
|
|
|
// AuthAPIAccessKeystoreReq defines Auth API for put/delete Access Keystore vols
|
|
type AuthOSAccessKeyReq struct {
|
|
APIReq APIAccessReq `json:"api_req"`
|
|
AKCaps keystore.AccessKeyCaps `json:"access_key_caps"`
|
|
}
|
|
|
|
// AuthAPIAccessKeystoreResp defines the response for put/delete Access Keystore vols
|
|
type AuthOSAccessKeyResp struct {
|
|
APIResp APIAccessResp `json:"api_resp"`
|
|
AKCaps keystore.AccessKeyCaps `json:"access_key_caps"`
|
|
}
|
|
|
|
// IsValidServiceID determine the validity of a serviceID
|
|
func IsValidServiceID(serviceID string) (err error) {
|
|
if serviceID != AuthServiceID && serviceID != MasterServiceID && serviceID != MetaServiceID && serviceID != DataServiceID {
|
|
err = fmt.Errorf("invalid service ID [%s]", serviceID)
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
// IsValidMsgReqType determine the validity of a message type
|
|
func IsValidMsgReqType(serviceID string, msgType MsgType) (err error) {
|
|
b := false
|
|
switch serviceID {
|
|
case "AuthService":
|
|
fallthrough
|
|
case "MasterService":
|
|
if msgType|MsgAuthBase != 0 {
|
|
b = true
|
|
}
|
|
default:
|
|
// do nothing
|
|
}
|
|
if !b {
|
|
err = fmt.Errorf("invalid request type [%x] and serviceID[%s]", msgType, serviceID)
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
// IsValidClientID determine the validity of a clientID
|
|
func IsValidClientID(id string) (err error) {
|
|
re := regexp.MustCompile("^[A-Za-z]{1,1}[A-Za-z0-9_]{0,20}$")
|
|
if !re.MatchString(id) {
|
|
err = fmt.Errorf("clientID invalid format [%s]", id)
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
// ParseAuthReply parse the response from auth
|
|
func ParseAuthReply(body []byte) (jobj HTTPAuthReply, err error) {
|
|
if err = json.Unmarshal(body, &jobj); err != nil {
|
|
return
|
|
}
|
|
if jobj.Code != 0 {
|
|
err = fmt.Errorf(jobj.Msg)
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
// GetDataFromResp extract data from response
|
|
func GetDataFromResp(body []byte, key []byte) (plaintext []byte, err error) {
|
|
jobj, err := ParseAuthReply(body)
|
|
if err != nil {
|
|
return
|
|
}
|
|
data := fmt.Sprint(jobj.Data)
|
|
|
|
if plaintext, err = cryptoutil.DecodeMessage(data, key); err != nil {
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// ParseAuthGetTicketResp parse and validate the auth get ticket resp
|
|
func ParseAuthGetTicketResp(body []byte, key []byte) (resp AuthGetTicketResp, err error) {
|
|
var plaintext []byte
|
|
|
|
if plaintext, err = GetDataFromResp(body, key); err != nil {
|
|
return
|
|
}
|
|
|
|
if err = json.Unmarshal(plaintext, &resp); err != nil {
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// ParseAuthAPIAccessResp parse and validate the auth api access resp
|
|
func ParseAuthAPIAccessResp(body []byte, key []byte) (resp AuthAPIAccessResp, err error) {
|
|
var plaintext []byte
|
|
|
|
if plaintext, err = GetDataFromResp(body, key); err != nil {
|
|
return
|
|
}
|
|
|
|
if err = json.Unmarshal(plaintext, &resp); err != nil {
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// ParseAuthRaftNodeResp parse and validate the auth raft node resp
|
|
func ParseAuthRaftNodeResp(body []byte, key []byte) (resp AuthRaftNodeResp, err error) {
|
|
var plaintext []byte
|
|
|
|
if plaintext, err = GetDataFromResp(body, key); err != nil {
|
|
return
|
|
}
|
|
|
|
if err = json.Unmarshal(plaintext, &resp); err != nil {
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func ParseAuthOSAKResp(body []byte, key []byte) (resp AuthOSAccessKeyResp, err error) {
|
|
var plaintext []byte
|
|
|
|
if plaintext, err = GetDataFromResp(body, key); err != nil {
|
|
return
|
|
}
|
|
|
|
if err = json.Unmarshal(plaintext, &resp); err != nil {
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func ExtractTicket(str string, key []byte) (ticket cryptoutil.Ticket, err error) {
|
|
var plaintext []byte
|
|
|
|
if plaintext, err = cryptoutil.DecodeMessage(str, key); err != nil {
|
|
return
|
|
}
|
|
|
|
if err = json.Unmarshal(plaintext, &ticket); err != nil {
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func checkTicketCaps(ticket *cryptoutil.Ticket, kind string, cap string) (err error) {
|
|
c := new(caps.Caps)
|
|
if err = c.Init(ticket.Caps); err != nil {
|
|
return
|
|
}
|
|
if b := c.ContainCaps(kind, cap); !b {
|
|
err = fmt.Errorf("no permission to access %v", kind)
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
// ParseVerifier checks the verifier structure for replay attack mitigation
|
|
func ParseVerifier(verifier string, key []byte) (ts int64, err error) {
|
|
var plainttext []byte
|
|
|
|
if plainttext, err = cryptoutil.DecodeMessage(verifier, key); err != nil {
|
|
return
|
|
}
|
|
|
|
ts = int64(binary.LittleEndian.Uint64(plainttext))
|
|
|
|
if time.Now().Unix()-ts >= reqLiveLength { // mitigate replay attack
|
|
err = fmt.Errorf("req verifier is timeout [%d] >= [%d]", time.Now().Unix()-ts, reqLiveLength)
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// VerifyAPIAccessReqIDs verify the req IDs
|
|
func VerifyAPIAccessReqIDs(req *APIAccessReq) (err error) {
|
|
if err = IsValidClientID(req.ClientID); err != nil {
|
|
err = fmt.Errorf("IsValidClientID failed: %s", err.Error())
|
|
return
|
|
}
|
|
|
|
if err = IsValidServiceID(req.ServiceID); err != nil {
|
|
err = fmt.Errorf("IsValidServiceID failed: %s", err.Error())
|
|
return
|
|
}
|
|
|
|
if err = IsValidMsgReqType(req.ServiceID, req.Type); err != nil {
|
|
err = fmt.Errorf("IsValidMsgReqType failed: %s", err.Error())
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
// ExtractAPIAccessTicket verify ticket validity
|
|
func ExtractAPIAccessTicket(req *APIAccessReq, key []byte) (ticket cryptoutil.Ticket, ts int64, err error) {
|
|
if ticket, err = ExtractTicket(req.Ticket, key); err != nil {
|
|
err = fmt.Errorf("extractTicket failed: %s", err.Error())
|
|
return
|
|
}
|
|
|
|
if time.Now().Unix() >= ticket.Exp {
|
|
err = ErrExpiredTicket
|
|
return
|
|
}
|
|
|
|
if ts, err = ParseVerifier(req.Verifier, ticket.SessionKey.Key); err != nil {
|
|
err = fmt.Errorf("parseVerifier failed: %s", err.Error())
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// CheckAPIAccessCaps checks capability
|
|
func CheckAPIAccessCaps(ticket *cryptoutil.Ticket, rscType string, mp MsgType, action string) (err error) {
|
|
if _, ok := MsgType2ResourceMap[mp]; !ok {
|
|
err = fmt.Errorf("MsgType2ResourceMap key not found [%d]", mp)
|
|
return
|
|
}
|
|
|
|
rule := MsgType2ResourceMap[mp] + capSeparator + action
|
|
|
|
if err = checkTicketCaps(ticket, rscType, rule); err != nil {
|
|
err = fmt.Errorf("checkTicketCaps failed: %s", err.Error())
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
func GenAuthIDKey(id string, authKey []byte) (authIDKey string, err error) {
|
|
type AuthIDKey struct {
|
|
ID string `json:"id"`
|
|
AuthKey []byte `json:"auth_key"`
|
|
}
|
|
tmpAuthIDKey := AuthIDKey{
|
|
ID: id,
|
|
AuthKey: authKey,
|
|
}
|
|
var jAuthIDKey []byte
|
|
if jAuthIDKey, err = json.Marshal(tmpAuthIDKey); err != nil {
|
|
err = fmt.Errorf("json marshal authIDKey failed %s", err.Error())
|
|
return
|
|
}
|
|
authIDKey = cryptoutil.Base64Encode(jAuthIDKey)
|
|
return
|
|
}
|
|
|
|
func ExtractIDAndAuthKey(authIDKey string) (id string, authKey []byte, err error) {
|
|
type AuthIDKey struct {
|
|
ID string `json:"id"`
|
|
AuthKey string `json:"auth_key"`
|
|
}
|
|
var jAuthIDKey []byte
|
|
jAuthIDKey, err = cryptoutil.Base64Decode(authIDKey)
|
|
if err != nil {
|
|
err = fmt.Errorf("decode authIDKey failed %s", err.Error())
|
|
return
|
|
}
|
|
tmpAuthIDKey := &AuthIDKey{}
|
|
if err = json.Unmarshal(jAuthIDKey, &tmpAuthIDKey); err != nil {
|
|
err = fmt.Errorf("json unmarshal authIDKey failed %s", err.Error())
|
|
return
|
|
}
|
|
id = tmpAuthIDKey.ID
|
|
authKey = []byte(tmpAuthIDKey.AuthKey)
|
|
return
|
|
}
|
|
|
|
func CheckVOLAccessCaps(ticket *cryptoutil.Ticket, volName string, action string, accessNode string) (err error) {
|
|
rule := accessNode + capSeparator + volName + capSeparator + action
|
|
|
|
if err = checkTicketCaps(ticket, OwnerVOLRsc, rule); err != nil {
|
|
if err = checkTicketCaps(ticket, NoneOwnerVOLRsc, rule); err != nil {
|
|
err = fmt.Errorf("checkTicketCaps failed: %s", err.Error())
|
|
return
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// VerifyAPIRespComm client verifies commond attributes returned from server
|
|
func VerifyAPIRespComm(apiResp *APIAccessResp, msg MsgType, clientID string, serviceID string, ts int64) (err error) {
|
|
if ts+1 != apiResp.Verifier {
|
|
err = fmt.Errorf("verifier verification failed")
|
|
return
|
|
}
|
|
|
|
if apiResp.Type != msg+1 {
|
|
err = fmt.Errorf("msg verification failed")
|
|
return
|
|
}
|
|
|
|
if apiResp.ClientID != clientID {
|
|
err = fmt.Errorf("id verification failed")
|
|
return
|
|
}
|
|
|
|
if apiResp.ServiceID != serviceID {
|
|
err = fmt.Errorf("service id verification failed")
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
// VerifyTicketRespComm verifies the ticket respose from server
|
|
func VerifyTicketRespComm(ticketResp *AuthGetTicketResp, msg MsgType, clientID string, serviceID string, ts int64) (err error) {
|
|
if ts+1 != ticketResp.Verifier {
|
|
err = fmt.Errorf("verifier verification failed")
|
|
return
|
|
}
|
|
|
|
if ticketResp.Type != msg+1 {
|
|
err = fmt.Errorf("msg verification failed")
|
|
return
|
|
}
|
|
|
|
if ticketResp.ClientID != clientID {
|
|
err = fmt.Errorf("id verification failed")
|
|
return
|
|
}
|
|
|
|
if ticketResp.ServiceID != serviceID {
|
|
err = fmt.Errorf("service id verification failed")
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
// SendBytes send raw bytes target in http/https protocol
|
|
func SendBytes(client *http.Client, target string, data []byte) (res []byte, err error) {
|
|
message := base64.StdEncoding.EncodeToString(data)
|
|
resp, err := client.PostForm(target, url.Values{ClientMessage: {message}})
|
|
if err != nil {
|
|
err = fmt.Errorf("action[SendData] failed:" + err.Error())
|
|
return
|
|
}
|
|
defer resp.Body.Close()
|
|
body, err := io.ReadAll(resp.Body)
|
|
if err != nil {
|
|
err = fmt.Errorf("action[doRealSend] failed:" + err.Error())
|
|
return
|
|
}
|
|
res = body
|
|
return
|
|
}
|
|
|
|
// SendData sends data to target
|
|
func SendData(client *http.Client, target string, data interface{}) (res []byte, err error) {
|
|
messageJSON, err := json.Marshal(data)
|
|
if err != nil {
|
|
err = fmt.Errorf("action[doRealSend] failed:" + err.Error())
|
|
return
|
|
}
|
|
if res, err = SendBytes(client, target, messageJSON); err != nil {
|
|
return
|
|
}
|
|
return
|
|
}
|