Files
gortsplib/authclient.go
2020-09-20 10:18:11 +02:00

110 lines
2.3 KiB
Go

package gortsplib
import (
"encoding/base64"
"fmt"
"net/url"
"strings"
)
// authClient is an object that helps a client to send its credentials to a
// server.
type authClient struct {
user string
pass string
method AuthMethod
realm string
nonce string
}
// newAuthClient allocates an authClient.
// header is the WWW-Authenticate header provided by the server.
func newAuthClient(v HeaderValue, user string, pass string) (*authClient, error) {
// prefer digest
if headerAuthDigest := func() string {
for _, vi := range v {
if strings.HasPrefix(vi, "Digest ") {
return vi
}
}
return ""
}(); headerAuthDigest != "" {
auth, err := ReadHeaderAuth(HeaderValue{headerAuthDigest})
if err != nil {
return nil, err
}
if auth.Realm == nil {
return nil, fmt.Errorf("realm not provided")
}
if auth.Nonce == nil {
return nil, fmt.Errorf("nonce not provided")
}
return &authClient{
user: user,
pass: pass,
method: Digest,
realm: *auth.Realm,
nonce: *auth.Nonce,
}, nil
}
if headerAuthBasic := func() string {
for _, vi := range v {
if strings.HasPrefix(vi, "Basic ") {
return vi
}
}
return ""
}(); headerAuthBasic != "" {
auth, err := ReadHeaderAuth(HeaderValue{headerAuthBasic})
if err != nil {
return nil, err
}
if auth.Realm == nil {
return nil, fmt.Errorf("realm not provided")
}
return &authClient{
user: user,
pass: pass,
method: Basic,
realm: *auth.Realm,
}, nil
}
return nil, fmt.Errorf("there are no authentication methods available")
}
// GenerateHeader generates an Authorization Header that allows to authenticate a request with
// the given method and url.
func (ac *authClient) GenerateHeader(method Method, ur *url.URL) HeaderValue {
switch ac.method {
case Basic:
response := base64.StdEncoding.EncodeToString([]byte(ac.user + ":" + ac.pass))
return HeaderValue{"Basic " + response}
case Digest:
response := md5Hex(md5Hex(ac.user+":"+ac.realm+":"+ac.pass) + ":" +
ac.nonce + ":" + md5Hex(string(method)+":"+ur.String()))
return (&HeaderAuth{
Method: Digest,
Username: &ac.user,
Realm: &ac.realm,
Nonce: &ac.nonce,
URI: func() *string {
v := ur.String()
return &v
}(),
Response: &response,
}).Write()
}
return nil
}