mirror of
https://github.com/cubefs/cubefs.git
synced 2026-08-02 02:00:56 +00:00
174 lines
5.1 KiB
Go
174 lines
5.1 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 (
|
|
"crypto/tls"
|
|
"net/http"
|
|
"net/http/httputil"
|
|
"time"
|
|
|
|
"github.com/cubefs/cubefs/proto"
|
|
"github.com/cubefs/cubefs/util/cryptoutil"
|
|
"github.com/cubefs/cubefs/util/log"
|
|
)
|
|
|
|
func (m *Server) startHTTPService() {
|
|
go func() {
|
|
m.handleFunctions()
|
|
if m.cluster.PKIKey.EnableHTTPS {
|
|
// not use PKI to verify client certificate
|
|
// Instead, we use client secret key for authentication
|
|
cfg := &tls.Config{
|
|
MinVersion: tls.VersionTLS12,
|
|
// ClientAuth: tls.RequireAndVerifyClientCert,
|
|
// ClientCAs: caCertPool,
|
|
}
|
|
srv := &http.Server{
|
|
Addr: colonSplit + m.port,
|
|
TLSConfig: cfg,
|
|
ReadTimeout: 5 * time.Minute,
|
|
WriteTimeout: 5 * time.Minute,
|
|
}
|
|
if err := srv.ListenAndServeTLS("/app/server.crt", "/app/server.key"); err != nil {
|
|
log.LogErrorf("action[startHTTPService] failed,err[%v]", err)
|
|
panic(err)
|
|
}
|
|
|
|
} else {
|
|
if err := http.ListenAndServe(colonSplit+m.port, nil); err != nil {
|
|
log.LogErrorf("action[startHTTPService] failed,err[%v]", err)
|
|
panic(err)
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
func (m *Server) newAuthProxy() *AuthProxy {
|
|
var (
|
|
authProxy AuthProxy
|
|
err error
|
|
)
|
|
if m.cluster.PKIKey.EnableHTTPS {
|
|
if authProxy.client, err = cryptoutil.CreateClientX(&m.cluster.PKIKey.AuthRootPublicKey); err != nil {
|
|
panic(err)
|
|
}
|
|
} else {
|
|
authProxy.reverseProxy = &httputil.ReverseProxy{
|
|
Director: func(request *http.Request) {
|
|
request.URL.Scheme = "http"
|
|
request.URL.Host = m.leaderInfo.addr
|
|
},
|
|
}
|
|
}
|
|
return &authProxy
|
|
}
|
|
|
|
func (m *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
log.LogInfof("URL[%v],remoteAddr[%v]", r.URL, r.RemoteAddr)
|
|
switch r.URL.Path {
|
|
case proto.ClientGetTicket:
|
|
m.getTicket(w, r)
|
|
case proto.AdminCreateKey:
|
|
fallthrough
|
|
case proto.AdminGetKey:
|
|
fallthrough
|
|
case proto.AdminDeleteKey:
|
|
fallthrough
|
|
case proto.AdminAddCaps:
|
|
fallthrough
|
|
case proto.AdminDeleteCaps:
|
|
fallthrough
|
|
case proto.AdminGetCaps:
|
|
m.apiAccessEntry(w, r)
|
|
case proto.AdminAddRaftNode:
|
|
fallthrough
|
|
case proto.AdminRemoveRaftNode:
|
|
m.raftNodeOp(w, r)
|
|
case proto.OSAddCaps:
|
|
fallthrough
|
|
case proto.OSDeleteCaps:
|
|
fallthrough
|
|
case proto.OSGetCaps:
|
|
m.osCapsOp(w, r)
|
|
default:
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: "Invalid requst URL"})
|
|
}
|
|
}
|
|
|
|
func (m *Server) handleFunctions() {
|
|
http.HandleFunc(proto.ClientGetTicket, m.getTicket)
|
|
http.Handle(proto.AdminCreateKey, m.handlerWithInterceptor())
|
|
http.Handle(proto.AdminGetKey, m.handlerWithInterceptor())
|
|
http.Handle(proto.AdminDeleteKey, m.handlerWithInterceptor())
|
|
http.Handle(proto.AdminAddCaps, m.handlerWithInterceptor())
|
|
http.Handle(proto.AdminDeleteCaps, m.handlerWithInterceptor())
|
|
http.Handle(proto.AdminGetCaps, m.handlerWithInterceptor())
|
|
http.Handle(proto.AdminAddRaftNode, m.handlerWithInterceptor())
|
|
http.Handle(proto.AdminRemoveRaftNode, m.handlerWithInterceptor())
|
|
http.Handle(proto.OSAddCaps, m.handlerWithInterceptor())
|
|
http.Handle(proto.OSDeleteCaps, m.handlerWithInterceptor())
|
|
http.Handle(proto.OSGetCaps, m.handlerWithInterceptor())
|
|
}
|
|
|
|
func (m *Server) handlerWithInterceptor() http.Handler {
|
|
return http.HandlerFunc(
|
|
func(w http.ResponseWriter, r *http.Request) {
|
|
if m.partition.IsRaftLeader() {
|
|
if m.metaReady {
|
|
m.ServeHTTP(w, r)
|
|
return
|
|
}
|
|
log.LogWarnf("action[handlerWithInterceptor] leader meta has not ready")
|
|
http.Error(w, m.leaderInfo.addr, http.StatusBadRequest)
|
|
return
|
|
}
|
|
if m.leaderInfo.addr == "" {
|
|
log.LogErrorf("action[handlerWithInterceptor] no leader,request[%v]", r.URL)
|
|
http.Error(w, "no leader", http.StatusBadRequest)
|
|
return
|
|
}
|
|
m.proxy(w, r)
|
|
})
|
|
}
|
|
|
|
func (m *Server) proxy(w http.ResponseWriter, r *http.Request) {
|
|
if m.cluster.PKIKey.EnableHTTPS {
|
|
var (
|
|
plaintext []byte
|
|
err error
|
|
res []byte
|
|
jobj proto.HTTPAuthReply
|
|
)
|
|
target := "https://" + m.leaderInfo.addr + r.URL.Path
|
|
if plaintext, err = m.extractClientReqInfo(r); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeParamError, Msg: err.Error()})
|
|
return
|
|
}
|
|
res, err = proto.SendBytes(m.authProxy.client, target, plaintext)
|
|
if err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeAuthReqRedirectError, Msg: "[proxy] failed: " + err.Error()})
|
|
return
|
|
}
|
|
if jobj, err = proto.ParseAuthReply(res); err != nil {
|
|
sendErrReply(w, r, &proto.HTTPAuthReply{Code: proto.ErrCodeAuthReqRedirectError, Msg: "Target Server failed: " + err.Error()})
|
|
return
|
|
}
|
|
sendOkReply(w, r, newSuccessHTTPAuthReply(jobj.Data))
|
|
} else {
|
|
m.authProxy.reverseProxy.ServeHTTP(w, r)
|
|
}
|
|
}
|