diff --git a/clientconn.go b/clientconn.go index f8a67add..c7c62dd0 100644 --- a/clientconn.go +++ b/clientconn.go @@ -70,7 +70,7 @@ type ClientConn struct { bw *bufio.Writer session string cseq int - auth *auth.Client + sender *auth.Sender state clientConnState streamURL *base.URL streamProtocol *StreamProtocol @@ -168,8 +168,8 @@ func (c *ClientConn) Do(req *base.Request) (*base.Response, error) { } // add auth - if c.auth != nil { - req.Header["Authorization"] = c.auth.GenerateHeader(req.Method, req.URL) + if c.sender != nil { + req.Header["Authorization"] = c.sender.GenerateHeader(req.Method, req.URL) } // add cseq @@ -227,12 +227,12 @@ func (c *ClientConn) Do(req *base.Request) (*base.Response, error) { } // setup authentication - if res.StatusCode == base.StatusUnauthorized && req.URL.User != nil && c.auth == nil { - auth, err := auth.NewClient(res.Header["WWW-Authenticate"], req.URL.User) + if res.StatusCode == base.StatusUnauthorized && req.URL.User != nil && c.sender == nil { + sender, err := auth.NewSender(res.Header["WWW-Authenticate"], req.URL.User) if err != nil { return nil, fmt.Errorf("unable to setup authentication: %s", err) } - c.auth = auth + c.sender = sender // send request again return c.Do(req) diff --git a/pkg/auth/package_test.go b/pkg/auth/package_test.go index 29144420..012af6d0 100644 --- a/pkg/auth/package_test.go +++ b/pkg/auth/package_test.go @@ -31,15 +31,15 @@ var casesAuth = []struct { func TestAuthMethods(t *testing.T) { for _, c := range casesAuth { t.Run(c.name, func(t *testing.T) { - authServer := NewServer("testuser", "testpass", c.methods) - wwwAuthenticate := authServer.GenerateHeader() + va := NewValidator("testuser", "testpass", c.methods) + wwwAuthenticate := va.GenerateHeader() - ac, err := NewClient(wwwAuthenticate, url.UserPassword("testuser", "testpass")) + se, err := NewSender(wwwAuthenticate, url.UserPassword("testuser", "testpass")) require.NoError(t, err) - authorization := ac.GenerateHeader(base.Announce, + authorization := se.GenerateHeader(base.Announce, base.MustParseURL("rtsp://myhost/mypath")) - err = authServer.ValidateHeader(authorization, base.Announce, + err = va.ValidateHeader(authorization, base.Announce, base.MustParseURL("rtsp://myhost/mypath")) require.NoError(t, err) }) @@ -60,16 +60,16 @@ func TestAuthVLC(t *testing.T) { "rtsp://myhost/mypath/test?testing/trackID=0", }, } { - authServer := NewServer("testuser", "testpass", + se := NewValidator("testuser", "testpass", []headers.AuthMethod{headers.AuthBasic, headers.AuthDigest}) - wwwAuthenticate := authServer.GenerateHeader() + wwwAuthenticate := se.GenerateHeader() - ac, err := NewClient(wwwAuthenticate, url.UserPassword("testuser", "testpass")) + va, err := NewSender(wwwAuthenticate, url.UserPassword("testuser", "testpass")) require.NoError(t, err) - authorization := ac.GenerateHeader(base.Announce, + authorization := va.GenerateHeader(base.Announce, base.MustParseURL(ca.clientURL)) - err = authServer.ValidateHeader(authorization, base.Announce, + err = se.ValidateHeader(authorization, base.Announce, base.MustParseURL(ca.serverURL)) require.NoError(t, err) } diff --git a/pkg/auth/client.go b/pkg/auth/sender.go similarity index 75% rename from pkg/auth/client.go rename to pkg/auth/sender.go index 885b07f6..cccc7a0f 100644 --- a/pkg/auth/client.go +++ b/pkg/auth/sender.go @@ -10,8 +10,8 @@ import ( "github.com/aler9/gortsplib/pkg/headers" ) -// Client is an object that allows a client to authenticate against a server. -type Client struct { +// Sender is an object that allows a client to send credentials to a server. +type Sender struct { user string pass string method headers.AuthMethod @@ -19,9 +19,9 @@ type Client struct { nonce string } -// NewClient allocates a Client with the WWW-Authenticate header provided by +// NewSender allocates a Sender with the WWW-Authenticate header provided by // the server and a set of credentials. -func NewClient(v base.HeaderValue, userinfo *url.Userinfo) (*Client, error) { +func NewSender(v base.HeaderValue, userinfo *url.Userinfo) (*Sender, error) { pass, _ := userinfo.Password() user := userinfo.Username() @@ -47,7 +47,7 @@ func NewClient(v base.HeaderValue, userinfo *url.Userinfo) (*Client, error) { return nil, fmt.Errorf("nonce not provided") } - return &Client{ + return &Sender{ user: user, pass: pass, method: headers.AuthDigest, @@ -73,7 +73,7 @@ func NewClient(v base.HeaderValue, userinfo *url.Userinfo) (*Client, error) { return nil, fmt.Errorf("realm not provided") } - return &Client{ + return &Sender{ user: user, pass: pass, method: headers.AuthBasic, @@ -86,24 +86,24 @@ func NewClient(v base.HeaderValue, userinfo *url.Userinfo) (*Client, error) { // GenerateHeader generates an Authorization Header that allows to authenticate a request with // the given method and url. -func (ac *Client) GenerateHeader(method base.Method, ur *base.URL) base.HeaderValue { +func (se *Sender) GenerateHeader(method base.Method, ur *base.URL) base.HeaderValue { urStr := ur.CloneWithoutCredentials().String() - switch ac.method { + switch se.method { case headers.AuthBasic: - response := base64.StdEncoding.EncodeToString([]byte(ac.user + ":" + ac.pass)) + response := base64.StdEncoding.EncodeToString([]byte(se.user + ":" + se.pass)) return base.HeaderValue{"Basic " + response} case headers.AuthDigest: - response := md5Hex(md5Hex(ac.user+":"+ac.realm+":"+ac.pass) + ":" + - ac.nonce + ":" + md5Hex(string(method)+":"+urStr)) + response := md5Hex(md5Hex(se.user+":"+se.realm+":"+se.pass) + ":" + + se.nonce + ":" + md5Hex(string(method)+":"+urStr)) return headers.Auth{ Method: headers.AuthDigest, - Username: &ac.user, - Realm: &ac.realm, - Nonce: &ac.nonce, + Username: &se.user, + Realm: &se.realm, + Nonce: &se.nonce, URI: &urStr, Response: &response, }.Write() diff --git a/pkg/auth/server.go b/pkg/auth/validator.go similarity index 75% rename from pkg/auth/server.go rename to pkg/auth/validator.go index 8ea9948a..c6a05502 100644 --- a/pkg/auth/server.go +++ b/pkg/auth/validator.go @@ -11,8 +11,8 @@ import ( "github.com/aler9/gortsplib/pkg/headers" ) -// Server allows a server to authenticate a client. -type Server struct { +// Validator allows a server to validate some credentials sent by a client. +type Validator struct { user string pass string methods []headers.AuthMethod @@ -20,9 +20,9 @@ type Server struct { nonce string } -// NewServer allocates a Server. +// NewValidator allocates a Validator. // If methods is nil, the Basic and Digest methods are used. -func NewServer(user string, pass string, methods []headers.AuthMethod) *Server { +func NewValidator(user string, pass string, methods []headers.AuthMethod) *Validator { if methods == nil { methods = []headers.AuthMethod{headers.AuthBasic, headers.AuthDigest} } @@ -31,7 +31,7 @@ func NewServer(user string, pass string, methods []headers.AuthMethod) *Server { rand.Read(nonceByts) nonce := hex.EncodeToString(nonceByts) - return &Server{ + return &Validator{ user: user, pass: pass, methods: methods, @@ -42,21 +42,21 @@ func NewServer(user string, pass string, methods []headers.AuthMethod) *Server { // GenerateHeader generates the WWW-Authenticate header needed by a client to // authenticate. -func (as *Server) GenerateHeader() base.HeaderValue { +func (va *Validator) GenerateHeader() base.HeaderValue { var ret base.HeaderValue - for _, m := range as.methods { + for _, m := range va.methods { switch m { case headers.AuthBasic: ret = append(ret, (&headers.Auth{ Method: headers.AuthBasic, - Realm: &as.realm, + Realm: &va.realm, }).Write()...) case headers.AuthDigest: ret = append(ret, headers.Auth{ Method: headers.AuthDigest, - Realm: &as.realm, - Nonce: &as.nonce, + Realm: &va.realm, + Nonce: &va.nonce, }.Write()...) } } @@ -65,7 +65,7 @@ func (as *Server) GenerateHeader() base.HeaderValue { // ValidateHeader validates the Authorization header sent by a client after receiving the // WWW-Authenticate header. -func (as *Server) ValidateHeader(v base.HeaderValue, method base.Method, ur *base.URL) error { +func (va *Validator) ValidateHeader(v base.HeaderValue, method base.Method, ur *base.URL) error { if len(v) == 0 { return fmt.Errorf("authorization header not provided") } @@ -78,7 +78,7 @@ func (as *Server) ValidateHeader(v base.HeaderValue, method base.Method, ur *bas if strings.HasPrefix(v0, "Basic ") { inResponse := v0[len("Basic "):] - response := base64.StdEncoding.EncodeToString([]byte(as.user + ":" + as.pass)) + response := base64.StdEncoding.EncodeToString([]byte(va.user + ":" + va.pass)) if inResponse != response { return fmt.Errorf("wrong response") @@ -110,15 +110,15 @@ func (as *Server) ValidateHeader(v base.HeaderValue, method base.Method, ur *bas return fmt.Errorf("response not provided") } - if *auth.Nonce != as.nonce { + if *auth.Nonce != va.nonce { return fmt.Errorf("wrong nonce") } - if *auth.Realm != as.realm { + if *auth.Realm != va.realm { return fmt.Errorf("wrong realm") } - if *auth.Username != as.user { + if *auth.Username != va.user { return fmt.Errorf("wrong username") } @@ -135,8 +135,8 @@ func (as *Server) ValidateHeader(v base.HeaderValue, method base.Method, ur *bas } } - response := md5Hex(md5Hex(as.user+":"+as.realm+":"+as.pass) + - ":" + as.nonce + ":" + md5Hex(string(method)+":"+uri)) + response := md5Hex(md5Hex(va.user+":"+va.realm+":"+va.pass) + + ":" + va.nonce + ":" + md5Hex(string(method)+":"+uri)) if *auth.Response != response { return fmt.Errorf("wrong response")