From 43b869a50d5d76089498e5dc82196edc6a8df456 Mon Sep 17 00:00:00 2001 From: softctrl Date: Thu, 18 Aug 2022 10:46:15 -0300 Subject: [PATCH] Add a new feature to handle authentication using query path. --- .gck.sh.swp | Bin 0 -> 12288 bytes auth/entity/client/client.go | 27 ++++++ auth/entity/session/session.go | 43 +++++++++ auth/security.go | 141 ++++++++++++++++++++++++++++++ auth/utils/utils.go | 22 +++++ configure/liveconfig.go | 8 ++ gck.sh | 12 +++ livego.yaml | 3 + protocol/rtmp/core/conn_server.go | 1 + protocol/rtmp/rtmp.go | 16 +++- 10 files changed, 270 insertions(+), 3 deletions(-) create mode 100644 .gck.sh.swp create mode 100644 auth/entity/client/client.go create mode 100644 auth/entity/session/session.go create mode 100644 auth/security.go create mode 100644 auth/utils/utils.go create mode 100755 gck.sh diff --git a/.gck.sh.swp b/.gck.sh.swp new file mode 100644 index 0000000000000000000000000000000000000000..a59be63bf9b8cad55d3b9aa2804e7c18bdefd56f GIT binary patch literal 12288 zcmeI&Jxjwt90u@zby5^XcRACp?X~J)1(DJU3bqB`7I8@8rAfW!N^*87)lcB&s^CX( z@$0zw5flU$FA@=3myU%e@Nn-(?gtq{;uKH!>#STTlDQU%I-ehom%pRg6(ZM;q>2kV z=&0Bi;iXFE{BwEYLPhpJ14CWcBOCIX=n1L19T94Nq&!{Kk>pOhy&(fn@K&I?40@ua zc+0&k#QxBRXhHx2V+hRC`daDxQO{bdYw0s;_#00bZa0SG_<0uX=z1Rwx`2^6p|h^7~ankLEj|DX5&chi0| zc{O=4c{X`6c{F)2xi`5rIW|ewHq!b865y60009U<00Izz00bZa0SG_<0%HmY;rfc) zt4K1-*SfpKxm2z#eHH7i&0@L8T@~s`N!}8ACsL}jo$FWkDvieO!N8(qHT&%#@&cMk zhqtX 0) + + if client, err := security.findClient(user); err == nil { + if client != nil && client.Active { + + lsk := client.LastSessionKey + + session, err := security.findSession(lsk) + if err == redis.Nil || session == nil { + session = sess.New(user, ipAddr) + if err = security.saveSession(session); err == nil { + client.LastSessionKey = session.Key() + if err = security.saveClient(client); err == nil { + log.Debugf("security.Allow(): %+v", session) + allowed = true + } + } + } else { + // Validate the IP Address from source to identify if it is another session to the same user: + allowed = (strings.Split(ipAddr, ":")[0] == strings.Split(session.IpAddress, ":")[0]) + } + } + } + } + if err != nil { + log.Errorf("security.Allow(): %s", err.Error()) + } + return + +} + +func (s *Security) findClient(code string) (*cli.Client, error) { + + if value, err := s.redisCli.Get(fmt.Sprintf("client-%s", code)).Result(); err == nil { + return cli.FromJson([]byte(value)) + } else { + return nil, err + } + +} + +func (s *Security) saveClient(client *cli.Client) (err error) { + + content, _ := client.ToJson() + cmd_val, err := s.redisCli.Set(fmt.Sprintf("client-%s", client.Code), string(content), 0).Result() + log.Debugf("security.saveClient(): %s", cmd_val) + return + +} + +func (s *Security) findSession(key string) (*sess.Session, error) { + + if value, err := s.redisCli.Get(key).Result(); err == nil { + return sess.FromJson([]byte(value)) + } else { + return nil, err + } + +} + +func (s *Security) saveSession(session *sess.Session) (err error) { + + content, _ := session.ToJson() + cmd_val, err := s.redisCli.Set(session.Key(), string(content), 0).Result() + log.Debugf("security.saveSession(): %s", cmd_val) + return + +} diff --git a/auth/utils/utils.go b/auth/utils/utils.go new file mode 100644 index 00000000..50c2d302 --- /dev/null +++ b/auth/utils/utils.go @@ -0,0 +1,22 @@ +package utils + +import ( + "math/rand" + "strconv" + "strings" + "time" +) + +func init() { + rand.Seed(time.Now().Unix()) +} + +func RandomNumberString(length int) string { + + var result strings.Builder + for n := 0; n < length; n++ { + result.WriteString(strconv.Itoa(rand.Intn(9))) + } + return result.String() + +} diff --git a/configure/liveconfig.go b/configure/liveconfig.go index bc2117e4..ab432f81 100644 --- a/configure/liveconfig.go +++ b/configure/liveconfig.go @@ -41,6 +41,7 @@ type JWT struct { } type ServerCfg struct { Level string `mapstructure:"level"` + IsProtected bool `mapstructure:"is_protected"` ConfigFile string `mapstructure:"config_file"` FLVArchive bool `mapstructure:"flv_archive"` FLVDir string `mapstructure:"flv_dir"` @@ -52,6 +53,7 @@ type ServerCfg struct { APIAddr string `mapstructure:"api_addr"` RedisAddr string `mapstructure:"redis_addr"` RedisPwd string `mapstructure:"redis_pwd"` + RedisDb int `mapstructure:"redis_db"` ReadTimeout int `mapstructure:"read_timeout"` WriteTimeout int `mapstructure:"write_timeout"` EnableTLSVerify bool `mapstructure:"enable_tls_verify"` @@ -184,3 +186,9 @@ func GetStaticPushUrlList(appname string) ([]string, bool) { } return nil, false } + +func IsProtected() bool { + c := ServerCfg{} + Config.Unmarshal(&c) + return c.IsProtected +} diff --git a/gck.sh b/gck.sh new file mode 100755 index 00000000..e74aac03 --- /dev/null +++ b/gck.sh @@ -0,0 +1,12 @@ +#/bin/bash + +if [ $# -ne 1 ] +then + CHANNEL="${RANDOM}-${RANDOM}-${RANDOM}" +else + CHANNEL="${1}" +fi + +echo ${CHANNEL} +curl "http://localhost:8090/control/get?room=${CHANNEL}" +echo diff --git a/livego.yaml b/livego.yaml index 6d199016..945b5c9c 100644 --- a/livego.yaml +++ b/livego.yaml @@ -18,6 +18,9 @@ # # API Options # api_addr: ":8090" +is_protected: true +redis_addr: "localhost:6379" +# redis_db: 10 server: - appname: live live: true diff --git a/protocol/rtmp/core/conn_server.go b/protocol/rtmp/core/conn_server.go index 99419498..4553c9c7 100755 --- a/protocol/rtmp/core/conn_server.go +++ b/protocol/rtmp/core/conn_server.go @@ -350,6 +350,7 @@ func (connServer *ConnServer) GetInfo() (app string, name string, url string) { app = connServer.ConnInfo.App name = connServer.PublishInfo.Name url = connServer.ConnInfo.TcUrl + "/" + connServer.PublishInfo.Name + log.Debugf("connServer.GetInfo: [%s]-[%s]-[%s]", app, name, url) return } diff --git a/protocol/rtmp/rtmp.go b/protocol/rtmp/rtmp.go index 6693f4cb..62239b65 100755 --- a/protocol/rtmp/rtmp.go +++ b/protocol/rtmp/rtmp.go @@ -10,6 +10,7 @@ import ( "github.com/gwuhaolin/livego/utils/uid" + "github.com/gwuhaolin/livego/auth" "github.com/gwuhaolin/livego/av" "github.com/gwuhaolin/livego/configure" "github.com/gwuhaolin/livego/container/flv" @@ -91,8 +92,8 @@ func (s *Server) Serve(listener net.Listener) (err error) { return } conn := core.NewConn(netconn, 4*1024) - log.Debug("new client, connect remote: ", conn.RemoteAddr().String(), - "local:", conn.LocalAddr().String()) + log.Debugf("new client, connect remote: %s local: %s", conn.RemoteAddr().String(), + conn.LocalAddr().String()) go s.handleConn(conn) } } @@ -111,7 +112,16 @@ func (s *Server) handleConn(conn *core.Conn) error { return err } - appname, name, _ := connServer.GetInfo() + appname, name, uri := connServer.GetInfo() + + // If is not a publisher we need to validate the credential here...... + if !connServer.IsPublisher() && configure.IsProtected() { + if allow, err := auth.Auth.Allow(conn.RemoteAddr().String(), uri); err != nil || !allow { + conn.Close() + log.Error("handleConn auth err: ", allow, err) + return err + } + } if ret := configure.CheckAppName(appname); !ret { err := fmt.Errorf("application name=%s is not configured", appname)