feat: add multiple authentication methods, token and oidc.

token is the current token comparison, and oidc generates oidc token using client-credentials flow. in addition - add ping verification using the same method
This commit is contained in:
Guy Lewin
2020-02-29 21:57:01 -05:00
committed by GitHub
parent 83d80857fd
commit 6c6607ae68
190 changed files with 47571 additions and 62 deletions

View File

@@ -23,6 +23,7 @@ import (
"sync"
"time"
"github.com/fatedier/frp/models/auth"
"github.com/fatedier/frp/models/config"
"github.com/fatedier/frp/models/consts"
frpErr "github.com/fatedier/frp/models/errors"
@@ -94,6 +95,9 @@ type Control struct {
// stats collector to store stats info of clients and proxies
statsCollector stats.Collector
// verifies authentication based on selected method
authVerifier auth.Verifier
// login message
loginMsg *msg.Login
@@ -149,6 +153,7 @@ func NewControl(
pxyManager *proxy.ProxyManager,
pluginManager *plugin.Manager,
statsCollector stats.Collector,
authVerifier auth.Verifier,
ctlConn net.Conn,
loginMsg *msg.Login,
serverCfg config.ServerCommonConf,
@@ -163,6 +168,7 @@ func NewControl(
pxyManager: pxyManager,
pluginManager: pluginManager,
statsCollector: statsCollector,
authVerifier: authVerifier,
conn: ctlConn,
loginMsg: loginMsg,
sendCh: make(chan msg.Message, 10),
@@ -204,7 +210,7 @@ func (ctl *Control) Start() {
go ctl.stoper()
}
func (ctl *Control) RegisterWorkConn(conn net.Conn) {
func (ctl *Control) RegisterWorkConn(conn net.Conn) error {
xl := ctl.xl
defer func() {
if err := recover(); err != nil {
@@ -216,9 +222,10 @@ func (ctl *Control) RegisterWorkConn(conn net.Conn) {
select {
case ctl.workConnCh <- conn:
xl.Debug("new work connection registered")
return nil
default:
xl.Debug("work connection pool is full, discarding")
conn.Close()
return fmt.Errorf("work connection pool is full, discarding")
}
}
@@ -454,6 +461,13 @@ func (ctl *Control) manager() {
ctl.CloseProxy(m)
xl.Info("close proxy [%s] success", m.ProxyName)
case *msg.Ping:
if err := ctl.authVerifier.VerifyPing(m); err != nil {
xl.Warn("received invalid ping: %v", err)
ctl.sendCh <- &msg.Pong{
Error: "invalid authentication in ping",
}
return
}
ctl.lastPing = time.Now()
xl.Debug("receive heartbeat")
ctl.sendCh <- &msg.Pong{}

View File

@@ -116,6 +116,7 @@ func (pxy *BaseProxy) GetWorkConnFromPool(src, dst net.Addr) (workConn net.Conn,
SrcPort: uint16(srcPort),
DstAddr: dstAddr,
DstPort: uint16(dstPort),
Error: "",
})
if err != nil {
xl.Warn("failed to send message to work connection from pool: %v, times: %d", err, i)

View File

@@ -30,6 +30,7 @@ import (
"time"
"github.com/fatedier/frp/assets"
"github.com/fatedier/frp/models/auth"
"github.com/fatedier/frp/models/config"
"github.com/fatedier/frp/models/msg"
"github.com/fatedier/frp/models/nathole"
@@ -86,6 +87,9 @@ type Service struct {
// All resource managers and controllers
rc *controller.ResourceController
// Verifies authentication based on selected method
authVerifier auth.Verifier
// stats collector to store server and proxies stats info
statsCollector stats.Collector
@@ -105,6 +109,7 @@ func NewService(cfg config.ServerCommonConf) (svr *Service, err error) {
UdpPortManager: ports.NewPortManager("udp", cfg.ProxyBindAddr, cfg.AllowPorts),
},
httpVhostRouter: vhost.NewVhostRouters(),
authVerifier: auth.NewAuthVerifier(cfg.AuthServerConfig),
tlsConfig: generateTLSConfig(),
cfg: cfg,
}
@@ -327,7 +332,9 @@ func (svr *Service) HandleListener(l net.Listener) {
conn.Close()
}
case *msg.NewWorkConn:
svr.RegisterWorkConn(conn, m)
if err := svr.RegisterWorkConn(conn, m); err != nil {
conn.Close()
}
case *msg.NewVisitorConn:
if err = svr.RegisterVisitorConn(conn, m); err != nil {
xl.Warn("register visitor conn error: %v", err)
@@ -399,12 +406,11 @@ func (svr *Service) RegisterControl(ctlConn net.Conn, loginMsg *msg.Login) (err
}
// Check auth.
if util.GetAuthKey(svr.cfg.Token, loginMsg.Timestamp) != loginMsg.PrivilegeKey {
err = fmt.Errorf("authorization failed")
if err = svr.authVerifier.VerifyLogin(loginMsg); err != nil {
return
}
ctl := NewControl(ctx, svr.rc, svr.pxyManager, svr.pluginManager, svr.statsCollector, ctlConn, loginMsg, svr.cfg)
ctl := NewControl(ctx, svr.rc, svr.pxyManager, svr.pluginManager, svr.statsCollector, svr.authVerifier, ctlConn, loginMsg, svr.cfg)
if oldCtl := svr.ctlManager.Add(loginMsg.RunId, ctl); oldCtl != nil {
oldCtl.allShutdown.WaitDone()
@@ -424,15 +430,22 @@ func (svr *Service) RegisterControl(ctlConn net.Conn, loginMsg *msg.Login) (err
}
// RegisterWorkConn register a new work connection to control and proxies need it.
func (svr *Service) RegisterWorkConn(workConn net.Conn, newMsg *msg.NewWorkConn) {
func (svr *Service) RegisterWorkConn(workConn net.Conn, newMsg *msg.NewWorkConn) error {
xl := frpNet.NewLogFromConn(workConn)
ctl, exist := svr.ctlManager.GetById(newMsg.RunId)
if !exist {
xl.Warn("No client control found for run id [%s]", newMsg.RunId)
return
return fmt.Errorf("no client control found for run id [%s]", newMsg.RunId)
}
ctl.RegisterWorkConn(workConn)
return
// Check auth.
if err := svr.authVerifier.VerifyNewWorkConn(newMsg); err != nil {
xl.Warn("Invalid authentication in NewWorkConn message on run id [%s]", newMsg.RunId)
msg.WriteMsg(workConn, &msg.StartWorkConn{
Error: "invalid authentication in NewWorkConn",
})
return fmt.Errorf("invalid authentication in NewWorkConn message on run id [%s]", newMsg.RunId)
}
return ctl.RegisterWorkConn(workConn)
}
func (svr *Service) RegisterVisitorConn(visitorConn net.Conn, newMsg *msg.NewVisitorConn) error {