Skip to content

Commit

Permalink
enhancement: objectnode gets sk from authnode; authclient get and upd…
Browse files Browse the repository at this point in the history
…ate ticket automatically

Signed-off-by: wenjia322 <[email protected]>
  • Loading branch information
wenjia322 committed Jan 4, 2020
1 parent 116c1fb commit 87284a2
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 56 deletions.
18 changes: 15 additions & 3 deletions authnode/api_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,11 @@ func (m *Server) raftNodeOp(w http.ResponseWriter, r *http.Request) {
}

if ticket, ts, err = proto.ExtractAPIAccessTicket(&apiReq, m.cluster.AuthSecretKey); err != nil {
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: "ExtractAPIAccessTicket failed: " + err.Error()})
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
}

Expand Down Expand Up @@ -245,7 +249,11 @@ func (m *Server) apiAccessEntry(w http.ResponseWriter, r *http.Request) {
}

if ticket, ts, err = proto.ExtractAPIAccessTicket(&apiReq, m.cluster.AuthSecretKey); err != nil {
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: "ExtractAPIAccessTicket failed: " + err.Error()})
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
}

Expand Down Expand Up @@ -395,7 +403,11 @@ func (m *Server) osCapsOp(w http.ResponseWriter, r *http.Request) {
}

if ticket, ts, err = proto.ExtractAPIAccessTicket(&apiReq, m.cluster.AuthSecretKey); err != nil {
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: "ExtractAPIAccessTicket failed: " + err.Error()})
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
}

Expand Down
5 changes: 5 additions & 0 deletions docker/authnode/data_objectnode.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"id": "ObjectService",
"role": "service",
"caps": "{\"API\":[\"*:*:*\"]}"
}
26 changes: 13 additions & 13 deletions objectnode/auth_signature_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ import (
"strings"
"time"

"github.com/chubaofs/chubaofs/proto"
"github.com/chubaofs/chubaofs/util"
"github.com/chubaofs/chubaofs/util/keystore"
"github.com/chubaofs/chubaofs/util/log"
"github.com/gorilla/mux"
)
Expand Down Expand Up @@ -173,20 +175,16 @@ func (o *ObjectNode) checkSignatureV2(r *http.Request) (bool, error) {
return false, err
}

v, err := o.vm.Volume(authInfo.bucket)
var akCaps *keystore.AccessKeyCaps
akCaps, err = o.authClient.API().OSSGetCaps(proto.ObjectServiceID, o.authKey, authInfo.accessKeyId)
if err != nil {
log.LogInfof("load Volume error: %v, %v", authInfo.r, err)
log.LogInfof("get secretKey from authnode error: accessKey(%v), err(%v)", authInfo.accessKeyId, err)
return false, err
}
volAccessKey, volSecret := v.OSSSecure()

if authInfo.accessKeyId != volAccessKey {
log.LogInfof("load Volume error: %v, %v", authInfo.accessKeyId, volAccessKey)
return false, errors.New("")
}
//volAccessKey, volSecret := v.OSSSecure()

// 2. calculate new signature
newSignature, err1 := calculateSignatureV2(authInfo, volSecret, o.domains)
newSignature, err1 := calculateSignatureV2(authInfo, akCaps.SecretKey, o.domains)
if err1 != nil {
log.LogInfof("calculute SignatureV2 error: %v, %v", authInfo.r, err)
return false, err1
Expand Down Expand Up @@ -264,9 +262,11 @@ func (o *ObjectNode) checkPresignedSignatureV2(r *http.Request) (bool, error) {
RequestIDFromRequest(r), r.URL.String(), accessKey, signature, expires)

//check access key
vlKey, secretKey := vl.OSSSecure()
if vlKey == "" || accessKey != vlKey {
return false, nil
var akCaps *keystore.AccessKeyCaps
akCaps, err = o.authClient.API().OSSGetCaps(proto.ObjectServiceID, o.authKey, accessKey)
if err != nil {
log.LogInfof("get secretKey from authnode error: accessKey(%v), err(%v)", accessKey, err)
return false, err
}

// check expires
Expand All @@ -278,7 +278,7 @@ func (o *ObjectNode) checkPresignedSignatureV2(r *http.Request) (bool, error) {
//calculatePresignedSignature
uri := strings.Split(r.RequestURI, "?")[0]
canoncialResourceQuery := getCanonicalQueryV2(uri, r.URL.Query().Encode())
calSignature := calPresignedSignatureV2(r.Method, canoncialResourceQuery, expires, secretKey, r.Header)
calSignature := calPresignedSignatureV2(r.Method, canoncialResourceQuery, expires, akCaps.SecretKey, r.Header)
if calSignature != signature {
log.LogDebugf("checkPresignedSignatureV2: invalid signature: requestID(%v) client(%v) server(%v)",
RequestIDFromRequest(r), signature, calSignature)
Expand Down
29 changes: 14 additions & 15 deletions objectnode/auth_signature_v4.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ import (
"strings"
"time"

"github.com/chubaofs/chubaofs/proto"
"github.com/chubaofs/chubaofs/util"
"github.com/chubaofs/chubaofs/util/keystore"
"github.com/chubaofs/chubaofs/util/log"
"github.com/gorilla/mux"
)
Expand Down Expand Up @@ -103,12 +105,17 @@ func (o *ObjectNode) checkSignatureV4(r *http.Request) (bool, error) {
log.LogInfof("checkSignatureV4: no volume info: requestID(%v)", RequestIDFromRequest(r))
return false, nil
}
_, secretKey := vl.OSSSecure()
req, err := parseRequestV4(r)
if err != nil {
return false, err
}
newSignature := calculateSignatureV4(r, o.region, secretKey, req.SignedHeaders)
var akCaps *keystore.AccessKeyCaps
akCaps, err = o.authClient.API().OSSGetCaps(proto.ObjectServiceID, o.authKey, req.Credential.AccessKey)
if err != nil {
log.LogInfof("get secretKey from authnode error: accessKey(%v), err(%v)", req.Credential.AccessKey, err)
return false, err
}
newSignature := calculateSignatureV4(r, o.region, akCaps.SecretKey, req.SignedHeaders)
if req.Signature != newSignature {
log.LogDebugf("checkSignatureV4: invalid signature: requestID(%v) client(%v) server(%v)",
RequestIDFromRequest(r), req.Signature, newSignature)
Expand Down Expand Up @@ -143,19 +150,11 @@ func (o *ObjectNode) checkPresignedSignatureV4(r *http.Request) (pass bool, err
}

// check accessKey valid
var v Volume
v, err = o.vm.Volume(req.bucket)
var akCaps *keystore.AccessKeyCaps
akCaps, err = o.authClient.API().OSSGetCaps(proto.ObjectServiceID, o.authKey, req.Credential.AccessKey)
if err != nil {
log.LogErrorf("checkPresignedSignatureV4: get volume fail: requestID(%v) err(%v)", RequestIDFromRequest(r), err)
return
}
//check accesskey
vaKey, secretKey := v.OSSSecure()
if req.Credential.AccessKey != vaKey {
log.LogInfof("checkPresignedSignatureV4: credential accessKey invalid: requestID(%v) requestAK(%v) volAK(%v)",
RequestIDFromRequest(r), req.Credential.AccessKey, vaKey)
err = errors.New("accesskey invalid")
return
log.LogInfof("get secretKey from authnode error: accessKey(%v), err(%v)", req.Credential.AccessKey, err)
return false, err
}
// create canonicalRequest
var canonicalHeader http.Header
Expand All @@ -177,7 +176,7 @@ func (o *ObjectNode) checkPresignedSignatureV4(r *http.Request) (pass bool, err
canonicalRequestString)

// build signingKey
signingKey := buildSigningKey(SCHEME, secretKey, req.Credential.Date, req.Credential.Region, req.Credential.Service, req.Credential.Request)
signingKey := buildSigningKey(SCHEME, akCaps.SecretKey, req.Credential.Date, req.Credential.Region, req.Credential.Service, req.Credential.Request)

// build stringToSign
scope := buildScope(req.Credential.Date, req.Credential.Region, req.Credential.Service, req.Credential.Request)
Expand Down
24 changes: 19 additions & 5 deletions objectnode/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"sync"
"sync/atomic"

authSDK "github.com/chubaofs/chubaofs/sdk/auth"
"github.com/chubaofs/chubaofs/util/config"
"github.com/chubaofs/chubaofs/util/errors"
"github.com/chubaofs/chubaofs/util/log"
Expand All @@ -38,11 +39,14 @@ const (

// Configuration keys
const (
configListen = "listen"
configDomains = "domains"
configMasters = "masters"
configAuthnodes = "authNodes"
configRegion = "region"
configListen = "listen"
configDomains = "domains"
configMasters = "masters"
configRegion = "region"
configAuthnodes = "authNodes"
configAuthkey = "authKey"
configEnableHTTPS = "enableHTTPS"
configCertFile = "certFile"
)

// Default of configuration value
Expand All @@ -63,6 +67,8 @@ type ObjectNode struct {
vm VolumeManager
state uint32
wg sync.WaitGroup
authKey string
authClient *authSDK.AuthClient
}

func (o *ObjectNode) Start(cfg *config.Config) (err error) {
Expand Down Expand Up @@ -131,6 +137,13 @@ func (o *ObjectNode) parseConfig(cfg *config.Config) (err error) {
region = defaultRegion
}
o.region = region

//parse authnode info
authNodes := cfg.GetString(configAuthnodes)
enableHTTPS := cfg.GetBool(configEnableHTTPS)
certFile := cfg.GetString(configCertFile)
o.authKey = cfg.GetString(configAuthkey)
o.authClient = authSDK.NewAuthClient(authNodes, enableHTTPS, certFile)
return
}

Expand All @@ -139,6 +152,7 @@ func (o *ObjectNode) handleStart(cfg *config.Config) (err error) {
if err = o.parseConfig(cfg); err != nil {
return
}

// start rest api
if err = o.startMuxRestAPI(); err != nil {
log.LogInfof("handleStart: start mux rest api fail, err(%v)", err)
Expand Down
5 changes: 4 additions & 1 deletion proto/auth_proto.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ const (

// DataServiceID defines ticket for datanode access (not supported)
DataServiceID = "DatanodeService"

//ObjectServiceID defines ticket for objectnode access
ObjectServiceID = "ObjectService"
)

const (
Expand Down Expand Up @@ -510,7 +513,7 @@ func ExtractAPIAccessTicket(req *APIAccessReq, key []byte) (ticket cryptoutil.Ti
}

if time.Now().Unix() >= ticket.Exp {
err = fmt.Errorf("ticket expired")
err = ErrExpiredTicket
return
}

Expand Down
48 changes: 34 additions & 14 deletions sdk/auth/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type API struct {
ac *AuthClient
}

func (api *API) GetTicket(id string, userKey string, serviceID string) (ticket *auth.Ticket, err error) {
func (api *API) GetTicket(clientId string, clientKey string, serviceID string) (ticket *auth.Ticket, err error) {
var (
key []byte
ts int64
Expand All @@ -21,59 +21,79 @@ func (api *API) GetTicket(id string, userKey string, serviceID string) (ticket *
)
message := proto.AuthGetTicketReq{
Type: proto.MsgAuthTicketReq,
ClientID: id,
ClientID: clientId,
ServiceID: proto.MasterServiceID,
}
if key, err = cryptoutil.Base64Decode(userKey); err != nil {
if key, err = cryptoutil.Base64Decode(clientKey); err != nil {
return
}
if message.Verifier, ts, err = cryptoutil.GenVerifier(key); err != nil {
return
}
if respData, err = api.ac.request(key, message, proto.ClientGetTicket); err != nil {
if respData, err = api.ac.request(clientId, clientKey, key, message, proto.ClientGetTicket); err != nil {
return
}
if err = json.Unmarshal(respData, &msgResp); err != nil {
return
}
if err = proto.VerifyTicketRespComm(&msgResp, proto.MsgAuthTicketReq, id, serviceID, ts); err != nil {
if err = proto.VerifyTicketRespComm(&msgResp, proto.MsgAuthTicketReq, clientId, serviceID, ts); err != nil {
return
}
ticket = &auth.Ticket{
ID: id,
ID: clientId,
SessionKey: cryptoutil.Base64Encode(msgResp.SessionKey.Key),
ServiceID: cryptoutil.Base64Encode(msgResp.SessionKey.Key),
Ticket: msgResp.Ticket,
}
return
}

func (api *API) OSSAddCaps(ticket *auth.Ticket, accessKey string, caps []byte) (newAKCaps *keystore.AccessKeyCaps, err error) {
func (api *API) OSSAddCaps(clientID, clientKey, accessKey string, caps []byte) (newAKCaps *keystore.AccessKeyCaps, err error) {
if api.ac.ticket == nil {
if api.ac.ticket, err = api.GetTicket(clientID, clientKey, proto.AuthServiceID); err != nil {
return
}
}
akCaps := &keystore.AccessKeyCaps{
AccessKey: accessKey,
Caps: caps,
}
return api.ac.serveOSSRequest(ticket.ID, ticket, akCaps, proto.MsgAuthOSAddCapsReq, proto.OSAddCaps)
return api.ac.serveOSSRequest(clientID, clientKey, api.ac.ticket, akCaps, proto.MsgAuthOSAddCapsReq, proto.OSAddCaps)
}

func (api *API) OSSDeleteCaps(ticket *auth.Ticket, accessKey string, caps []byte) (newAKCaps *keystore.AccessKeyCaps, err error) {
func (api *API) OSSDeleteCaps(clientID, clientKey, accessKey string, caps []byte) (newAKCaps *keystore.AccessKeyCaps, err error) {
if api.ac.ticket == nil {
if api.ac.ticket, err = api.GetTicket(clientID, clientKey, proto.AuthServiceID); err != nil {
return
}
}
akCaps := &keystore.AccessKeyCaps{
AccessKey: accessKey,
Caps: caps,
}
return api.ac.serveOSSRequest(ticket.ID, ticket, akCaps, proto.MsgAuthOSDeleteCapsReq, proto.OSDeleteCaps)
return api.ac.serveOSSRequest(clientID, clientKey, api.ac.ticket, akCaps, proto.MsgAuthOSDeleteCapsReq, proto.OSDeleteCaps)
}

func (api *API) OSSGetCaps(ticket *auth.Ticket, accessKey string) (caps *keystore.AccessKeyCaps, err error) {
func (api *API) OSSGetCaps(clientID, clientKey, accessKey string) (caps *keystore.AccessKeyCaps, err error) {
if api.ac.ticket == nil {
if api.ac.ticket, err = api.GetTicket(clientID, clientKey, proto.AuthServiceID); err != nil {
return
}
}
akCaps := &keystore.AccessKeyCaps{
AccessKey: accessKey,
}
return api.ac.serveOSSRequest(ticket.ID, ticket, akCaps, proto.MsgAuthOSGetCapsReq, proto.OSGetCaps)
return api.ac.serveOSSRequest(clientID, clientKey, api.ac.ticket, akCaps, proto.MsgAuthOSGetCapsReq, proto.OSGetCaps)
}

func (api *API) AdminGetCaps(ticket *auth.Ticket, userID string) (res *keystore.KeyInfo, err error) {
func (api *API) AdminGetCaps(clientID, clientKey, userID string) (res *keystore.KeyInfo, err error) {
if api.ac.ticket == nil {
if api.ac.ticket, err = api.GetTicket(clientID, clientKey, proto.AuthServiceID); err != nil {
return
}
}
keyInfo := &keystore.KeyInfo{
ID: userID,
}
return api.ac.serveAdminRequest(ticket.ID, ticket, keyInfo, proto.MsgAuthGetCapsReq, proto.AdminGetCaps)
return api.ac.serveAdminRequest(clientID, clientKey, api.ac.ticket, keyInfo, proto.MsgAuthGetCapsReq, proto.AdminGetCaps)
}
Loading

0 comments on commit 87284a2

Please sign in to comment.