mirror of
https://github.com/cubefs/cubefs.git
synced 2026-08-02 10:06:14 +00:00
680 lines
20 KiB
Go
680 lines
20 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"
|
|
"net/http"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/cubefs/cubefs/proto"
|
|
"github.com/cubefs/cubefs/util/cryptoutil"
|
|
"github.com/cubefs/cubefs/util/errors"
|
|
"github.com/cubefs/cubefs/util/iputil"
|
|
"github.com/cubefs/cubefs/util/keystore"
|
|
"github.com/cubefs/cubefs/util/log"
|
|
)
|
|
|
|
func (m *Server) getTicket(w http.ResponseWriter, r *http.Request) {
|
|
var (
|
|
plaintext []byte
|
|
err error
|
|
jobj proto.AuthGetTicketReq
|
|
ts int64
|
|
key []byte
|
|
message string
|
|
)
|
|
|
|
if !m.metaReady {
|
|
log.LogWarnf("action[handlerWithInterceptor] leader meta has not ready")
|
|
http.Error(w, m.leaderInfo.addr, http.StatusBadRequest)
|
|
}
|
|
|
|
if plaintext, err = m.extractClientReqInfo(r); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
|
|
return
|
|
}
|
|
|
|
if err = json.Unmarshal([]byte(plaintext), &jobj); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
|
|
return
|
|
}
|
|
|
|
if key, err = m.getSecretKey(jobj.ClientID); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
|
|
return
|
|
}
|
|
|
|
if ts, err = proto.ParseVerifier(jobj.Verifier, key); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
|
|
return
|
|
}
|
|
|
|
if err = validateGetTicketReqFormat(&jobj); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
|
|
return
|
|
}
|
|
|
|
if message, err = m.genGetTicketAuthResp(&jobj, ts, r); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
|
|
return
|
|
}
|
|
|
|
sendOkReply(w, r, newSuccessHTTPAuthReply(message))
|
|
}
|
|
|
|
func (m *Server) raftNodeOp(w http.ResponseWriter, r *http.Request) {
|
|
var (
|
|
plaintext []byte
|
|
err error
|
|
jobj proto.AuthRaftNodeReq
|
|
ticket cryptoutil.Ticket
|
|
ts int64
|
|
message string
|
|
)
|
|
|
|
if plaintext, err = m.extractClientReqInfo(r); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
|
|
return
|
|
}
|
|
|
|
if err = json.Unmarshal([]byte(plaintext), &jobj); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: "Unmarshal AuthRaftNodeReq failed: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
apiReq := jobj.APIReq
|
|
raftNodeInfo := jobj.RaftNodeInfo
|
|
|
|
if err = proto.VerifyAPIAccessReqIDs(&apiReq); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: "VerifyAPIAccessReqIDs failed: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
if ticket, ts, err = proto.ExtractAPIAccessTicket(&apiReq, m.cluster.AuthSecretKey); err != nil {
|
|
if err == proto.ErrExpiredTicket {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeExpiredTicket, Msg: "ExtractAPIAccessTicket failed: " + err.Error()})
|
|
} else {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: "ExtractAPIAccessTicket failed: " + err.Error()})
|
|
}
|
|
return
|
|
}
|
|
|
|
if err = proto.CheckAPIAccessCaps(&ticket, proto.APIRsc, apiReq.Type, proto.APIAccess); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: "CheckAPIAccessCaps failed: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
switch apiReq.Type {
|
|
case proto.MsgAuthAddRaftNodeReq:
|
|
err = m.handleAddRaftNode(&raftNodeInfo)
|
|
case proto.MsgAuthRemoveRaftNodeReq:
|
|
err = m.handleRemoveRaftNode(&raftNodeInfo)
|
|
default:
|
|
}
|
|
|
|
if err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeAuthKeyStoreError, Msg: err.Error()})
|
|
return
|
|
}
|
|
|
|
msg := fmt.Sprintf("add raft node id :%v, addr:%v successfully \n", raftNodeInfo.ID, raftNodeInfo.Addr)
|
|
|
|
if message, err = genAuthRaftNodeOpResp(&apiReq, ts, ticket.SessionKey.Key, msg); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeAuthRaftNodeGenRespError, Msg: err.Error()})
|
|
return
|
|
}
|
|
|
|
sendOkReply(w, r, newSuccessHTTPAuthReply(message))
|
|
}
|
|
|
|
func (m *Server) handleAddRaftNode(raftNodeInfo *proto.AuthRaftNodeInfo) (err error) {
|
|
return m.cluster.addRaftNode(raftNodeInfo.ID, raftNodeInfo.Addr)
|
|
}
|
|
|
|
func (m *Server) handleRemoveRaftNode(raftNodeInfo *proto.AuthRaftNodeInfo) (err error) {
|
|
return m.cluster.removeRaftNode(raftNodeInfo.ID, raftNodeInfo.Addr)
|
|
}
|
|
|
|
func genAuthRaftNodeOpResp(req *proto.APIAccessReq, ts int64, key []byte, msg string) (message string, err error) {
|
|
var (
|
|
jresp []byte
|
|
resp proto.AuthRaftNodeResp
|
|
)
|
|
|
|
resp.APIResp.Type = req.Type + 1
|
|
resp.APIResp.ClientID = req.ClientID
|
|
resp.APIResp.ServiceID = req.ServiceID
|
|
resp.APIResp.Verifier = ts + 1 // increase ts by one for client verify server identity
|
|
|
|
resp.Msg = msg
|
|
|
|
if jresp, err = json.Marshal(resp); err != nil {
|
|
err = fmt.Errorf("json marshal for response failed %s", err.Error())
|
|
return
|
|
}
|
|
|
|
if message, err = cryptoutil.EncodeMessage(jresp, key); err != nil {
|
|
err = fmt.Errorf("encode message for response failed %s", err.Error())
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (m *Server) apiAccessEntry(w http.ResponseWriter, r *http.Request) {
|
|
var (
|
|
plaintext []byte
|
|
err error
|
|
jobj proto.AuthAPIAccessReq
|
|
ticket cryptoutil.Ticket
|
|
ts int64
|
|
newKeyInfo *keystore.KeyInfo
|
|
message string
|
|
)
|
|
|
|
if plaintext, err = m.extractClientReqInfo(r); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
|
|
return
|
|
}
|
|
|
|
if err = json.Unmarshal([]byte(plaintext), &jobj); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: "Unmarshal AuthAPIAccessReq failed: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
apiReq := jobj.APIReq
|
|
keyInfo := jobj.KeyInfo
|
|
|
|
if err = keyInfo.IsValidID(); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
|
|
return
|
|
}
|
|
|
|
switch apiReq.Type {
|
|
case proto.MsgAuthCreateKeyReq:
|
|
if keyInfo.ID == proto.AuthServiceID {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: "AuthServiceID is reserved"})
|
|
return
|
|
}
|
|
if err = keyInfo.IsValidKeyInfo(); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
|
|
return
|
|
}
|
|
case proto.MsgAuthDeleteKeyReq:
|
|
case proto.MsgAuthGetKeyReq:
|
|
case proto.MsgAuthAddCapsReq:
|
|
fallthrough
|
|
case proto.MsgAuthDeleteCapsReq:
|
|
if err = keyInfo.IsValidCaps(); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
|
|
return
|
|
}
|
|
case proto.MsgAuthGetCapsReq:
|
|
default:
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: fmt.Errorf("invalid request messge type %x", int32(apiReq.Type)).Error()})
|
|
return
|
|
}
|
|
|
|
if err = proto.VerifyAPIAccessReqIDs(&apiReq); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: "VerifyAPIAccessReqIDs failed: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
if ticket, ts, err = proto.ExtractAPIAccessTicket(&apiReq, m.cluster.AuthSecretKey); err != nil {
|
|
if err == proto.ErrExpiredTicket {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeExpiredTicket, Msg: "ExtractAPIAccessTicket failed: " + err.Error()})
|
|
} else {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: "ExtractAPIAccessTicket failed: " + err.Error()})
|
|
}
|
|
return
|
|
}
|
|
|
|
if err = proto.CheckAPIAccessCaps(&ticket, proto.APIRsc, apiReq.Type, proto.APIAccess); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: "CheckAPIAccessCaps failed: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
switch apiReq.Type {
|
|
case proto.MsgAuthCreateKeyReq:
|
|
newKeyInfo, err = m.handleCreateKey(&keyInfo)
|
|
case proto.MsgAuthDeleteKeyReq:
|
|
newKeyInfo, err = m.handleDeleteKey(&keyInfo)
|
|
case proto.MsgAuthGetKeyReq:
|
|
newKeyInfo, err = m.handleGetKey(&keyInfo)
|
|
case proto.MsgAuthAddCapsReq:
|
|
newKeyInfo, err = m.handleAddCaps(&keyInfo)
|
|
case proto.MsgAuthDeleteCapsReq:
|
|
newKeyInfo, err = m.handleDeleteCaps(&keyInfo)
|
|
case proto.MsgAuthGetCapsReq:
|
|
newKeyInfo, err = m.handleGetCaps(&keyInfo)
|
|
default:
|
|
// do nothing
|
|
}
|
|
|
|
if err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeAuthKeyStoreError, Msg: err.Error()})
|
|
return
|
|
}
|
|
|
|
if message, err = genAuthAPIAccessResp(&apiReq, newKeyInfo, ts, ticket.SessionKey.Key); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeAuthAPIAccessGenRespError, Msg: err.Error()})
|
|
return
|
|
}
|
|
|
|
sendOkReply(w, r, newSuccessHTTPAuthReply(message))
|
|
}
|
|
|
|
func (m *Server) handleCreateKey(keyInfo *keystore.KeyInfo) (res *keystore.KeyInfo, err error) {
|
|
return m.cluster.CreateNewKey(keyInfo.ID, keyInfo)
|
|
}
|
|
|
|
func (m *Server) handleDeleteKey(keyInfo *keystore.KeyInfo) (res *keystore.KeyInfo, err error) {
|
|
return m.cluster.DeleteKey(keyInfo.ID)
|
|
}
|
|
|
|
func (m *Server) handleGetKey(keyInfo *keystore.KeyInfo) (res *keystore.KeyInfo, err error) {
|
|
return m.getSecretKeyInfo(keyInfo.ID)
|
|
}
|
|
|
|
func (m *Server) handleAddCaps(keyInfo *keystore.KeyInfo) (res *keystore.KeyInfo, err error) {
|
|
return m.cluster.AddCaps(keyInfo.ID, keyInfo)
|
|
}
|
|
|
|
func (m *Server) handleDeleteCaps(keyInfo *keystore.KeyInfo) (res *keystore.KeyInfo, err error) {
|
|
return m.cluster.DeleteCaps(keyInfo.ID, keyInfo)
|
|
}
|
|
|
|
func (m *Server) handleGetCaps(keyInfo *keystore.KeyInfo) (res *keystore.KeyInfo, err error) {
|
|
var info *keystore.KeyInfo
|
|
if info, err = m.getSecretKeyInfo(keyInfo.ID); err != nil {
|
|
return
|
|
}
|
|
res = &keystore.KeyInfo{
|
|
ID: info.ID,
|
|
AccessKey: info.AccessKey,
|
|
SecretKey: info.SecretKey,
|
|
Caps: info.Caps,
|
|
}
|
|
return
|
|
}
|
|
|
|
func (m *Server) extractClientReqInfo(r *http.Request) (plaintext []byte, err error) {
|
|
var message string
|
|
if err = r.ParseForm(); err != nil {
|
|
return
|
|
}
|
|
|
|
if message = r.FormValue(proto.ClientMessage); message == "" {
|
|
err = keyNotFound(proto.ClientMessage)
|
|
return
|
|
}
|
|
|
|
if plaintext, err = cryptoutil.Base64Decode(message); err != nil {
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (m *Server) osCapsOp(w http.ResponseWriter, r *http.Request) {
|
|
var (
|
|
plaintext []byte
|
|
err error
|
|
jobj proto.AuthOSAccessKeyReq
|
|
ticket cryptoutil.Ticket
|
|
ts int64
|
|
newAkCaps *keystore.AccessKeyCaps
|
|
message string
|
|
)
|
|
|
|
if plaintext, err = m.extractClientReqInfo(r); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
|
|
return
|
|
}
|
|
|
|
if err = json.Unmarshal([]byte(plaintext), &jobj); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: "Unmarshal AuthOSAccessKeyReq failed: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
apiReq := jobj.APIReq
|
|
akCaps := jobj.AKCaps
|
|
|
|
if err = akCaps.IsValidAK(); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
|
|
return
|
|
}
|
|
|
|
switch apiReq.Type {
|
|
case proto.MsgAuthOSAddCapsReq:
|
|
fallthrough
|
|
case proto.MsgAuthOSDeleteCapsReq:
|
|
if err = akCaps.IsValidCaps(); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
|
|
return
|
|
}
|
|
case proto.MsgAuthOSGetCapsReq:
|
|
default:
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: fmt.Errorf("invalid request messge type %x", int32(apiReq.Type)).Error()})
|
|
return
|
|
}
|
|
|
|
if err = proto.VerifyAPIAccessReqIDs(&apiReq); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: "VerifyAPIAccessReqIDs failed: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
if ticket, ts, err = proto.ExtractAPIAccessTicket(&apiReq, m.cluster.AuthSecretKey); err != nil {
|
|
if err == proto.ErrExpiredTicket {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeExpiredTicket, Msg: "ExtractAPIAccessTicket failed: " + err.Error()})
|
|
} else {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: "ExtractAPIAccessTicket failed: " + err.Error()})
|
|
}
|
|
return
|
|
}
|
|
|
|
if err = proto.CheckAPIAccessCaps(&ticket, proto.APIRsc, apiReq.Type, proto.APIAccess); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: "CheckAPIAccessCaps failed: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
switch apiReq.Type {
|
|
case proto.MsgAuthOSAddCapsReq:
|
|
newAkCaps, err = m.handleOSAddCaps(&akCaps)
|
|
case proto.MsgAuthOSDeleteCapsReq:
|
|
newAkCaps, err = m.handleOSDeleteCaps(&akCaps)
|
|
case proto.MsgAuthOSGetCapsReq:
|
|
newAkCaps, err = m.handleOSGetCaps(&akCaps)
|
|
default:
|
|
// do nothing
|
|
}
|
|
|
|
if err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeAuthKeyStoreError, Msg: err.Error()})
|
|
return
|
|
}
|
|
|
|
if message, err = genAuthOSCapsOpResp(&apiReq, newAkCaps, ts, ticket.SessionKey.Key); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeAuthOSCapsOpGenRespError, Msg: err.Error()})
|
|
return
|
|
}
|
|
|
|
sendOkReply(w, r, newSuccessHTTPAuthReply(message))
|
|
}
|
|
|
|
func (m *Server) genTicket(key []byte, serviceID string, IP string, caps []byte) (ticket cryptoutil.Ticket) {
|
|
currentTime := time.Now().Unix()
|
|
ticket.Version = cryptoutil.TicketVersion
|
|
ticket.ServiceID = serviceID
|
|
ticket.SessionKey.Ctime = currentTime
|
|
ticket.SessionKey.Key = cryptoutil.AuthGenSessionKeyTS(key)
|
|
ticket.Exp = currentTime + cryptoutil.TicketAge
|
|
ticket.IP = IP
|
|
ticket.Caps = caps
|
|
return
|
|
}
|
|
|
|
func (m *Server) getSecretKey(id string) (key []byte, err error) {
|
|
var keyInfo *keystore.KeyInfo
|
|
if keyInfo, err = m.getSecretKeyInfo(id); err != nil {
|
|
return
|
|
}
|
|
return keyInfo.AuthKey, err
|
|
}
|
|
|
|
func (m *Server) getSecretKeyInfo(id string) (keyInfo *keystore.KeyInfo, err error) {
|
|
if id == proto.AuthServiceID {
|
|
keyInfo = &keystore.KeyInfo{
|
|
AuthKey: m.cluster.AuthSecretKey,
|
|
Caps: []byte(`{"API": ["*:*:*"]}`),
|
|
}
|
|
} else {
|
|
if keyInfo, err = m.cluster.GetKey(id); err != nil {
|
|
return
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func (m *Server) genGetTicketAuthResp(req *proto.AuthGetTicketReq, ts int64, r *http.Request) (message string, err error) {
|
|
var (
|
|
jticket []byte
|
|
jresp []byte
|
|
resp proto.AuthGetTicketResp
|
|
serviceKey []byte
|
|
clientKey []byte
|
|
caps []byte
|
|
keyInfo *keystore.KeyInfo
|
|
)
|
|
|
|
resp.Type = req.Type + 1
|
|
resp.ClientID = req.ClientID
|
|
resp.ServiceID = req.ServiceID
|
|
// increase ts by one for client verify server
|
|
resp.Verifier = ts + 1
|
|
|
|
if keyInfo, err = m.getSecretKeyInfo(resp.ClientID); err != nil {
|
|
return
|
|
}
|
|
caps = keyInfo.Caps
|
|
|
|
// Use service key to encrypt ticket
|
|
if serviceKey, err = m.getSecretKey(req.ServiceID); err != nil {
|
|
return
|
|
}
|
|
|
|
ticket := m.genTicket(serviceKey, resp.ServiceID, iputil.RealIP(r), caps)
|
|
resp.SessionKey = ticket.SessionKey
|
|
|
|
if jticket, err = json.Marshal(ticket); err != nil {
|
|
return
|
|
}
|
|
|
|
if resp.Ticket, err = cryptoutil.EncodeMessage(jticket, serviceKey); err != nil {
|
|
return
|
|
}
|
|
|
|
if jresp, err = json.Marshal(resp); err != nil {
|
|
return
|
|
}
|
|
|
|
// Use client secret key to encrypt response message
|
|
if keyInfo, err = m.getSecretKeyInfo(resp.ClientID); err != nil {
|
|
return
|
|
}
|
|
clientKey = keyInfo.AuthKey
|
|
if message, err = cryptoutil.EncodeMessage(jresp, clientKey); err != nil {
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func validateGetTicketReqFormat(req *proto.AuthGetTicketReq) (err error) {
|
|
if err = proto.IsValidClientID(req.ClientID); err != nil {
|
|
return
|
|
}
|
|
|
|
if err = proto.IsValidServiceID(req.ServiceID); err != nil {
|
|
return
|
|
}
|
|
|
|
if err = proto.IsValidMsgReqType(req.ServiceID, req.Type); err != nil {
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
func genAuthAPIAccessResp(req *proto.APIAccessReq, keyInfo *keystore.KeyInfo, ts int64, key []byte) (message string, err error) {
|
|
var (
|
|
jresp []byte
|
|
resp proto.AuthAPIAccessResp
|
|
)
|
|
|
|
resp.APIResp.Type = req.Type + 1
|
|
resp.APIResp.ClientID = req.ClientID
|
|
resp.APIResp.ServiceID = req.ServiceID
|
|
resp.APIResp.Verifier = ts + 1 // increase ts by one for client verify server
|
|
|
|
resp.KeyInfo = *keyInfo
|
|
|
|
resp.AuthIDKey, err = proto.GenAuthIDKey(keyInfo.ID, keyInfo.AuthKey)
|
|
if err != nil {
|
|
err = fmt.Errorf("gen authIDKey for response failed %s", err.Error())
|
|
return
|
|
}
|
|
|
|
if jresp, err = json.Marshal(resp); err != nil {
|
|
err = fmt.Errorf("json marshal for response failed %s", err.Error())
|
|
return
|
|
}
|
|
|
|
if message, err = cryptoutil.EncodeMessage(jresp, key); err != nil {
|
|
err = fmt.Errorf("encode message for response failed %s", err.Error())
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (m *Server) handleOSAddCaps(akCaps *keystore.AccessKeyCaps) (newAKCaps *keystore.AccessKeyCaps, err error) {
|
|
var akInfo *keystore.AccessKeyInfo
|
|
if akInfo, err = m.cluster.GetAKInfo(akCaps.AccessKey); err != nil {
|
|
return
|
|
}
|
|
keyInfo := &keystore.KeyInfo{
|
|
ID: akInfo.ID,
|
|
Caps: akCaps.Caps,
|
|
}
|
|
if keyInfo, err = m.cluster.AddCaps(akInfo.ID, keyInfo); err != nil {
|
|
return
|
|
}
|
|
newAKCaps = &keystore.AccessKeyCaps{
|
|
AccessKey: keyInfo.AccessKey,
|
|
Caps: keyInfo.Caps,
|
|
}
|
|
return newAKCaps, err
|
|
}
|
|
|
|
func (m *Server) handleOSDeleteCaps(akCaps *keystore.AccessKeyCaps) (newAKCaps *keystore.AccessKeyCaps, err error) {
|
|
var akInfo *keystore.AccessKeyInfo
|
|
if akInfo, err = m.cluster.GetAKInfo(akCaps.AccessKey); err != nil {
|
|
return
|
|
}
|
|
keyInfo := &keystore.KeyInfo{
|
|
ID: akInfo.ID,
|
|
Caps: akCaps.Caps,
|
|
}
|
|
if keyInfo, err = m.cluster.DeleteCaps(akInfo.ID, keyInfo); err != nil {
|
|
return
|
|
}
|
|
newAKCaps = &keystore.AccessKeyCaps{
|
|
AccessKey: keyInfo.AccessKey,
|
|
Caps: keyInfo.Caps,
|
|
}
|
|
return newAKCaps, err
|
|
}
|
|
|
|
func (m *Server) handleOSGetCaps(akCaps *keystore.AccessKeyCaps) (newAKCaps *keystore.AccessKeyCaps, err error) {
|
|
var akInfo *keystore.AccessKeyInfo
|
|
var keyInfo *keystore.KeyInfo
|
|
if akInfo, err = m.cluster.GetAKInfo(akCaps.AccessKey); err != nil {
|
|
return
|
|
}
|
|
if keyInfo, err = m.getSecretKeyInfo(akInfo.ID); err != nil {
|
|
return
|
|
}
|
|
newAKCaps = &keystore.AccessKeyCaps{
|
|
AccessKey: keyInfo.AccessKey,
|
|
SecretKey: keyInfo.SecretKey,
|
|
Caps: keyInfo.Caps,
|
|
ID: keyInfo.ID,
|
|
}
|
|
return newAKCaps, err
|
|
}
|
|
|
|
func genAuthOSCapsOpResp(req *proto.APIAccessReq, akCaps *keystore.AccessKeyCaps, ts int64, key []byte) (message string, err error) {
|
|
var (
|
|
jresp []byte
|
|
resp proto.AuthOSAccessKeyResp
|
|
)
|
|
|
|
resp.APIResp.Type = req.Type + 1
|
|
resp.APIResp.ClientID = req.ClientID
|
|
resp.APIResp.ServiceID = req.ServiceID
|
|
resp.APIResp.Verifier = ts + 1 // increase ts by one for client verify server
|
|
|
|
resp.AKCaps = *akCaps
|
|
|
|
if jresp, err = json.Marshal(resp); err != nil {
|
|
err = fmt.Errorf("json marshal for response failed %s", err.Error())
|
|
return
|
|
}
|
|
|
|
if message, err = cryptoutil.EncodeMessage(jresp, key); err != nil {
|
|
err = fmt.Errorf("encode message for response failed %s", err.Error())
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func newSuccessHTTPAuthReply(data interface{}) *proto.HTTPAuthReply {
|
|
return &proto.HTTPAuthReply{Code: proto.ErrCodeSuccess, Msg: proto.ErrSuc.Error(), Data: data}
|
|
}
|
|
|
|
func sendOkReply(w http.ResponseWriter, r *http.Request, HTTPAuthReply *proto.HTTPAuthReply) (err error) {
|
|
reply, err := json.Marshal(HTTPAuthReply)
|
|
if err != nil {
|
|
log.LogErrorf("fail to marshal http reply[%v]. URL[%v],remoteAddr[%v] err:[%v]", HTTPAuthReply, r.URL, r.RemoteAddr, err)
|
|
http.Error(w, "fail to marshal http reply", http.StatusBadRequest)
|
|
return
|
|
}
|
|
send(w, r, reply)
|
|
return
|
|
}
|
|
|
|
func send(w http.ResponseWriter, r *http.Request, reply []byte) {
|
|
w.Header().Set("content-type", "application/json")
|
|
w.Header().Set("Content-Length", strconv.Itoa(len(reply)))
|
|
if _, err := w.Write(reply); err != nil {
|
|
log.LogErrorf("fail to write http reply[%s] len[%d].URL[%v],remoteAddr[%v] err:[%v]", string(reply), len(reply), r.URL, r.RemoteAddr, err)
|
|
return
|
|
}
|
|
log.LogInfof("URL[%v],remoteAddr[%v],response ok", r.URL, r.RemoteAddr)
|
|
}
|
|
|
|
func keyNotFound(name string) (err error) {
|
|
return errors.NewErrorf("parameter %v not found", name)
|
|
}
|
|
|
|
func sendErrReply(w http.ResponseWriter, r *http.Request, HTTPAuthReply *proto.HTTPAuthReply) {
|
|
log.LogInfof("URL[%v],remoteAddr[%v],response err[%v]", r.URL, r.RemoteAddr, HTTPAuthReply)
|
|
reply, err := json.Marshal(HTTPAuthReply)
|
|
if err != nil {
|
|
log.LogErrorf("fail to marshal http reply[%v]. URL[%v],remoteAddr[%v] err:[%v]", HTTPAuthReply, r.URL, r.RemoteAddr, err)
|
|
http.Error(w, "fail to marshal http reply", http.StatusBadRequest)
|
|
return
|
|
}
|
|
w.Header().Set("content-type", "application/json")
|
|
w.Header().Set("Content-Length", strconv.Itoa(len(reply)))
|
|
if _, err = w.Write(reply); err != nil {
|
|
log.LogErrorf("fail to write http reply[%s] len[%d].URL[%v],remoteAddr[%v] err:[%v]", string(reply), len(reply), r.URL, r.RemoteAddr, err)
|
|
}
|
|
}
|