Skip to content

Commit c10f7aa

Browse files
authored
split headers.Authenticate and headers.Authorization (#523)
1 parent c93d5c5 commit c10f7aa

21 files changed

+367
-422
lines changed

client_play_test.go

+8-4
Original file line numberDiff line numberDiff line change
@@ -1691,12 +1691,13 @@ func TestClientPlayRedirect(t *testing.T) {
16911691
authOpaque := "exampleOpaque"
16921692
authStale := "FALSE"
16931693
authAlg := "MD5"
1694+
16941695
err = conn.WriteResponse(&base.Response{
16951696
Header: base.Header{
16961697
"WWW-Authenticate": headers.Authenticate{
16971698
Method: headers.AuthDigest,
1698-
Realm: &authRealm,
1699-
Nonce: &authNonce,
1699+
Realm: authRealm,
1700+
Nonce: authNonce,
17001701
Opaque: &authOpaque,
17011702
Stale: &authStale,
17021703
Algorithm: &authAlg,
@@ -1706,13 +1707,16 @@ func TestClientPlayRedirect(t *testing.T) {
17061707
})
17071708
require.NoError(t, err)
17081709
}
1710+
17091711
req, err = conn.ReadRequest()
17101712
require.NoError(t, err)
1713+
17111714
authHeaderVal, exists := req.Header["Authorization"]
17121715
require.True(t, exists)
1713-
var authHeader headers.Authenticate
1716+
1717+
var authHeader headers.Authorization
17141718
require.NoError(t, authHeader.Unmarshal(authHeaderVal))
1715-
require.Equal(t, *authHeader.Username, "testusr")
1719+
require.Equal(t, authHeader.Username, "testusr")
17161720
require.Equal(t, base.Describe, req.Method)
17171721
}
17181722

pkg/auth/sender.go

+18-42
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,9 @@ func findHeader(v base.HeaderValue, prefix string) string {
1919

2020
// Sender allows to send credentials.
2121
type Sender struct {
22-
user string
23-
pass string
24-
method headers.AuthMethod
25-
realm string
26-
nonce string
22+
user string
23+
pass string
24+
authenticateHeader *headers.Authenticate
2725
}
2826

2927
// NewSender allocates a Sender.
@@ -38,20 +36,10 @@ func NewSender(v base.HeaderValue, user string, pass string) (*Sender, error) {
3836
return nil, err
3937
}
4038

41-
if auth.Realm == nil {
42-
return nil, fmt.Errorf("realm is missing")
43-
}
44-
45-
if auth.Nonce == nil {
46-
return nil, fmt.Errorf("nonce is missing")
47-
}
48-
4939
return &Sender{
50-
user: user,
51-
pass: pass,
52-
method: headers.AuthDigest,
53-
realm: *auth.Realm,
54-
nonce: *auth.Nonce,
40+
user: user,
41+
pass: pass,
42+
authenticateHeader: &auth,
5543
}, nil
5644
}
5745

@@ -62,15 +50,10 @@ func NewSender(v base.HeaderValue, user string, pass string) (*Sender, error) {
6250
return nil, err
6351
}
6452

65-
if auth.Realm == nil {
66-
return nil, fmt.Errorf("realm is missing")
67-
}
68-
6953
return &Sender{
70-
user: user,
71-
pass: pass,
72-
method: headers.AuthBasic,
73-
realm: *auth.Realm,
54+
user: user,
55+
pass: pass,
56+
authenticateHeader: &auth,
7457
}, nil
7558
}
7659

@@ -82,26 +65,19 @@ func (se *Sender) AddAuthorization(req *base.Request) {
8265
urStr := req.URL.CloneWithoutCredentials().String()
8366

8467
h := headers.Authorization{
85-
Method: se.method,
68+
Method: se.authenticateHeader.Method,
8669
}
8770

88-
switch se.method {
89-
case headers.AuthBasic:
71+
if se.authenticateHeader.Method == headers.AuthBasic {
9072
h.BasicUser = se.user
9173
h.BasicPass = se.pass
92-
93-
default: // headers.AuthDigest
94-
response := md5Hex(md5Hex(se.user+":"+se.realm+":"+se.pass) + ":" +
95-
se.nonce + ":" + md5Hex(string(req.Method)+":"+urStr))
96-
97-
h.DigestValues = headers.Authenticate{
98-
Method: headers.AuthDigest,
99-
Username: &se.user,
100-
Realm: &se.realm,
101-
Nonce: &se.nonce,
102-
URI: &urStr,
103-
Response: &response,
104-
}
74+
} else { // digest
75+
h.Username = se.user
76+
h.Realm = se.authenticateHeader.Realm
77+
h.Nonce = se.authenticateHeader.Nonce
78+
h.URI = urStr
79+
h.Response = md5Hex(md5Hex(se.user+":"+se.authenticateHeader.Realm+":"+se.pass) + ":" +
80+
se.authenticateHeader.Nonce + ":" + md5Hex(string(req.Method)+":"+urStr))
10581
}
10682

10783
if req.Header == nil {

pkg/auth/sender_test.go

+11-44
Original file line numberDiff line numberDiff line change
@@ -3,51 +3,18 @@ package auth
33
import (
44
"testing"
55

6-
"github.com/stretchr/testify/require"
7-
86
"github.com/bluenviron/gortsplib/v4/pkg/base"
97
)
108

11-
func TestSenderErrors(t *testing.T) {
12-
for _, ca := range []struct {
13-
name string
14-
hv base.HeaderValue
15-
err string
16-
}{
17-
{
18-
"invalid method",
19-
base.HeaderValue{`Invalid`},
20-
"no authentication methods available",
21-
},
22-
{
23-
"digest invalid",
24-
base.HeaderValue{`Digest`},
25-
"unable to split between method and keys (Digest)",
26-
},
27-
{
28-
"digest, missing realm",
29-
base.HeaderValue{`Digest nonce=123`},
30-
"realm is missing",
31-
},
32-
{
33-
"digest, missing nonce",
34-
base.HeaderValue{`Digest realm=123`},
35-
"nonce is missing",
36-
},
37-
{
38-
"basic invalid",
39-
base.HeaderValue{`Basic`},
40-
"unable to split between method and keys (Basic)",
41-
},
42-
{
43-
"basic, missing realm",
44-
base.HeaderValue{`Basic nonce=123`},
45-
"realm is missing",
46-
},
47-
} {
48-
t.Run(ca.name, func(t *testing.T) {
49-
_, err := NewSender(ca.hv, "myuser", "mypass")
50-
require.EqualError(t, err, ca.err)
51-
})
52-
}
9+
func FuzzSender(f *testing.F) {
10+
f.Add(`Invalid`)
11+
f.Add(`Digest`)
12+
f.Add(`Digest nonce=123`)
13+
f.Add(`Digest realm=123`)
14+
f.Add(`Basic`)
15+
f.Add(`Basic nonce=123`)
16+
17+
f.Fuzz(func(t *testing.T, a string) {
18+
NewSender(base.HeaderValue{a}, "myuser", "mypass") //nolint:errcheck
19+
})
5320
}

pkg/auth/validate.go

+9-29
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,14 @@ func GenerateWWWAuthenticate(methods []headers.AuthMethod, realm string, nonce s
3939
case headers.AuthBasic:
4040
ret = append(ret, (&headers.Authenticate{
4141
Method: headers.AuthBasic,
42-
Realm: &realm,
42+
Realm: realm,
4343
}).Marshal()...)
4444

4545
case headers.AuthDigest:
4646
ret = append(ret, headers.Authenticate{
4747
Method: headers.AuthDigest,
48-
Realm: &realm,
49-
Nonce: &nonce,
48+
Realm: realm,
49+
Nonce: nonce,
5050
}.Marshal()...)
5151
}
5252
}
@@ -92,46 +92,26 @@ func Validate(
9292
return fmt.Errorf("authentication failed")
9393
}
9494
case auth.Method == headers.AuthDigest && contains(methods, headers.AuthDigest):
95-
if auth.DigestValues.Realm == nil {
96-
return fmt.Errorf("realm is missing")
97-
}
98-
99-
if auth.DigestValues.Nonce == nil {
100-
return fmt.Errorf("nonce is missing")
101-
}
102-
103-
if auth.DigestValues.Username == nil {
104-
return fmt.Errorf("username is missing")
105-
}
106-
107-
if auth.DigestValues.URI == nil {
108-
return fmt.Errorf("uri is missing")
109-
}
110-
111-
if auth.DigestValues.Response == nil {
112-
return fmt.Errorf("response is missing")
113-
}
114-
115-
if *auth.DigestValues.Nonce != nonce {
95+
if auth.Nonce != nonce {
11696
return fmt.Errorf("wrong nonce")
11797
}
11898

119-
if *auth.DigestValues.Realm != realm {
99+
if auth.Realm != realm {
120100
return fmt.Errorf("wrong realm")
121101
}
122102

123-
if *auth.DigestValues.Username != user {
103+
if auth.Username != user {
124104
return fmt.Errorf("authentication failed")
125105
}
126106

127107
ur := req.URL
128108

129-
if *auth.DigestValues.URI != ur.String() {
109+
if auth.URI != ur.String() {
130110
// in SETUP requests, VLC strips the control attribute.
131111
// try again with the base URL.
132112
if baseURL != nil {
133113
ur = baseURL
134-
if *auth.DigestValues.URI != ur.String() {
114+
if auth.URI != ur.String() {
135115
return fmt.Errorf("wrong URL")
136116
}
137117
} else {
@@ -142,7 +122,7 @@ func Validate(
142122
response := md5Hex(md5Hex(user+":"+realm+":"+pass) +
143123
":" + nonce + ":" + md5Hex(string(req.Method)+":"+ur.String()))
144124

145-
if *auth.DigestValues.Response != response {
125+
if auth.Response != response {
146126
return fmt.Errorf("authentication failed")
147127
}
148128
default:

pkg/auth/validate_test.go

+47-67
Original file line numberDiff line numberDiff line change
@@ -3,75 +3,55 @@ package auth
33
import (
44
"testing"
55

6-
"github.com/stretchr/testify/require"
7-
86
"github.com/bluenviron/gortsplib/v4/pkg/base"
7+
"github.com/bluenviron/gortsplib/v4/pkg/headers"
8+
"github.com/stretchr/testify/require"
99
)
1010

11-
func TestValidateErrors(t *testing.T) {
12-
for _, ca := range []struct {
13-
name string
14-
hv base.HeaderValue
15-
err string
16-
}{
17-
{
18-
"invalid auth",
19-
base.HeaderValue{`Invalid`},
20-
"invalid authorization header",
21-
},
22-
{
23-
"digest missing realm",
24-
base.HeaderValue{`Digest `},
25-
"realm is missing",
26-
},
27-
{
28-
"digest missing nonce",
29-
base.HeaderValue{`Digest realm=123`},
30-
"nonce is missing",
31-
},
32-
{
33-
"digest missing username",
34-
base.HeaderValue{`Digest realm=123,nonce=123`},
35-
"username is missing",
36-
},
37-
{
38-
"digest missing uri",
39-
base.HeaderValue{`Digest realm=123,nonce=123,username=123`},
40-
"uri is missing",
41-
},
42-
{
43-
"digest missing response",
44-
base.HeaderValue{`Digest realm=123,nonce=123,username=123,uri=123`},
45-
"response is missing",
46-
},
47-
{
48-
"digest wrong nonce",
49-
base.HeaderValue{`Digest realm=123,nonce=123,username=123,uri=123,response=123`},
50-
"wrong nonce",
51-
},
52-
{
53-
"digest wrong realm",
54-
base.HeaderValue{`Digest realm=123,nonce=abcde,username=123,uri=123,response=123`},
55-
"wrong realm",
56-
},
57-
} {
58-
t.Run(ca.name, func(t *testing.T) {
59-
err := Validate(
60-
&base.Request{
61-
Method: base.Describe,
62-
URL: nil,
63-
Header: base.Header{
64-
"Authorization": ca.hv,
65-
},
11+
func FuzzValidate(f *testing.F) {
12+
f.Add(`Invalid`)
13+
f.Add(`Digest `)
14+
f.Add(`Digest realm=123`)
15+
f.Add(`Digest realm=123,nonce=123`)
16+
f.Add(`Digest realm=123,nonce=123,username=123`)
17+
f.Add(`Digest realm=123,nonce=123,username=123,uri=123`)
18+
f.Add(`Digest realm=123,nonce=123,username=123,uri=123,response=123`)
19+
f.Add(`Digest realm=123,nonce=abcde,username=123,uri=123,response=123`)
20+
21+
f.Fuzz(func(t *testing.T, a string) {
22+
Validate( //nolint:errcheck
23+
&base.Request{
24+
Method: base.Describe,
25+
URL: nil,
26+
Header: base.Header{
27+
"Authorization": base.HeaderValue{a},
6628
},
67-
"myuser",
68-
"mypass",
69-
nil,
70-
nil,
71-
"IPCAM",
72-
"abcde",
73-
)
74-
require.EqualError(t, err, ca.err)
75-
})
76-
}
29+
},
30+
"myuser",
31+
"mypass",
32+
nil,
33+
nil,
34+
"IPCAM",
35+
"abcde",
36+
)
37+
})
38+
}
39+
40+
func TestValidateAdditionalErrors(t *testing.T) {
41+
err := Validate(
42+
&base.Request{
43+
Method: base.Describe,
44+
URL: nil,
45+
Header: base.Header{
46+
"Authorization": base.HeaderValue{"Basic bXl1c2VyOm15cGFzcw=="},
47+
},
48+
},
49+
"myuser",
50+
"mypass",
51+
nil,
52+
[]headers.AuthMethod{headers.AuthDigest},
53+
"IPCAM",
54+
"abcde",
55+
)
56+
require.Error(t, err)
7757
}

0 commit comments

Comments
 (0)