66 "encoding/hex"
77 "encoding/json"
88 "fmt"
9+ "io"
910 "io/ioutil"
11+ "maps"
1012 "net/http"
1113 "net/url"
1214 "testing"
@@ -63,14 +65,10 @@ func TestRegistration(t *testing.T) {
6365 // sytest: POST /register can create a user
6466 t .Run ("POST /register can create a user" , func (t * testing.T ) {
6567 t .Parallel ()
66- res := unauthedClient .Do (t , "POST" , []string {"_matrix" , "client" , "v3" , "register" }, client .WithRawBody (json .RawMessage (`{
67- "auth": {
68- "type": "m.login.dummy"
69- },
70- "username": "post-can-create-a-user",
71- "password": "sUp3rs3kr1t"
72- }` )))
68+ reqBody , _ := startUIASession (t , unauthedClient , "post-can-create-a-user" , "sUp3rs3kr1t" , nil )
69+ res := unauthedClient .Do (t , "POST" , []string {"_matrix" , "client" , "v3" , "register" }, client .WithJSONBody (t , reqBody ))
7370 must .MatchResponse (t , res , match.HTTPResponse {
71+ StatusCode : 200 ,
7472 JSON : []match.JSON {
7573 match .JSONKeyTypeEqual ("access_token" , gjson .String ),
7674 match .JSONKeyTypeEqual ("user_id" , gjson .String ),
@@ -80,14 +78,10 @@ func TestRegistration(t *testing.T) {
8078 // sytest: POST /register downcases capitals in usernames
8179 t .Run ("POST /register downcases capitals in usernames" , func (t * testing.T ) {
8280 t .Parallel ()
83- res := unauthedClient .Do (t , "POST" , []string {"_matrix" , "client" , "v3" , "register" }, client .WithRawBody (json .RawMessage (`{
84- "auth": {
85- "type": "m.login.dummy"
86- },
87- "username": "user-UPPER",
88- "password": "sUp3rs3kr1t"
89- }` )))
81+ reqBody , _ := startUIASession (t , unauthedClient , "user-UPPER" , "sUp3rs3kr1t" , nil )
82+ res := unauthedClient .Do (t , "POST" , []string {"_matrix" , "client" , "v3" , "register" }, client .WithJSONBody (t , reqBody ))
9083 must .MatchResponse (t , res , match.HTTPResponse {
84+ StatusCode : 200 ,
9185 JSON : []match.JSON {
9286 match .JSONKeyTypeEqual ("access_token" , gjson .String ),
9387 match .JSONKeyEqual ("user_id" , "@user-upper:hs1" ),
@@ -98,15 +92,10 @@ func TestRegistration(t *testing.T) {
9892 t .Run ("POST /register returns the same device_id as that in the request" , func (t * testing.T ) {
9993 t .Parallel ()
10094 deviceID := "my_device_id"
101- res := unauthedClient .Do (t , "POST" , []string {"_matrix" , "client" , "v3" , "register" }, client .WithRawBody (json .RawMessage (`{
102- "auth": {
103- "type": "m.login.dummy"
104- },
105- "username": "user-device",
106- "password": "sUp3rs3kr1t",
107- "device_id": "` + deviceID + `"
108- }` )))
95+ reqBody , _ := startUIASession (t , unauthedClient , "user-device" , deviceID , map [string ]any {"device_id" : deviceID })
96+ res := unauthedClient .Do (t , "POST" , []string {"_matrix" , "client" , "v3" , "register" }, client .WithJSONBody (t , reqBody ))
10997 must .MatchResponse (t , res , match.HTTPResponse {
98+ StatusCode : 200 ,
11099 JSON : []match.JSON {
111100 match .JSONKeyTypeEqual ("access_token" , gjson .String ),
112101 match .JSONKeyEqual ("device_id" , deviceID ),
@@ -134,14 +123,10 @@ func TestRegistration(t *testing.T) {
134123 `'` ,
135124 }
136125 for _ , ch := range specialChars {
137- res := unauthedClient .Do (t , "POST" , []string {"_matrix" , "client" , "v3" , "register" },
138- client .WithJSONBody (t , map [string ]interface {}{
139- "auth" : map [string ]string {
140- "type" : "m.login.dummy" ,
141- },
142- "username" : "user-" + ch + "-reject-please" ,
143- "password" : "sUp3rs3kr1t" ,
144- }))
126+ // CONCERN: Should servers be expected to validate parameters before starting a UIA session?
127+ // This test will flake if they do so, since 401 will be returned instead of 400.
128+ reqBody , _ := startUIASession (t , unauthedClient , "user-" + ch + "-reject-please" , "sUp3rs3kr1t" , nil )
129+ res := unauthedClient .Do (t , "POST" , []string {"_matrix" , "client" , "v3" , "register" }, client .WithJSONBody (t , reqBody ))
145130 must .MatchResponse (t , res , match.HTTPResponse {
146131 StatusCode : 400 ,
147132 JSON : []match.JSON {
@@ -152,28 +137,21 @@ func TestRegistration(t *testing.T) {
152137 })
153138 t .Run ("POST /register rejects if user already exists" , func (t * testing.T ) {
154139 t .Parallel ()
155- res := unauthedClient .Do (t , "POST" , []string {"_matrix" , "client" , "v3" , "register" }, client .WithRawBody (json .RawMessage (`{
156- "auth": {
157- "type": "m.login.dummy"
158- },
159- "username": "post-can-create-a-user-once",
160- "password": "sUp3rs3kr1t"
161- }` )))
140+ reqBody , _ := startUIASession (t , unauthedClient , "post-can-create-a-user-once" , "sUp3rs3kr1t" , nil )
141+ res := unauthedClient .Do (t , "POST" , []string {"_matrix" , "client" , "v3" , "register" }, client .WithJSONBody (t , reqBody ))
162142 must .MatchResponse (t , res , match.HTTPResponse {
163143 JSON : []match.JSON {
164144 match .JSONKeyTypeEqual ("access_token" , gjson .String ),
165145 match .JSONKeyTypeEqual ("user_id" , gjson .String ),
166146 },
167147 })
168- res = unauthedClient .Do (t , "POST" , []string {"_matrix" , "client" , "v3" , "register" }, client .WithRawBody (json .RawMessage (`{
169- "auth": {
170- "type": "m.login.dummy"
171- },
172- "username": "post-can-create-a-user-once",
173- "password": "anotherSuperSecret"
174- }` )))
148+ reqBody , _ = startUIASession (t , unauthedClient , "post-can-create-a-user-once" , "sUp3rs3kr1t" , nil )
149+ res = unauthedClient .Do (t , "POST" , []string {"_matrix" , "client" , "v3" , "register" }, client .WithJSONBody (t , reqBody ))
175150 must .MatchResponse (t , res , match.HTTPResponse {
176151 StatusCode : 400 ,
152+ JSON : []match.JSON {
153+ match .JSONKeyEqual ("errcode" , "M_USER_IN_USE" ),
154+ },
177155 })
178156 })
179157 // sytest: POST /register allows registration of usernames with '$chr'
@@ -346,3 +324,29 @@ func registerSharedSecret(t *testing.T, c *client.CSAPI, user, pass string, isAd
346324 resp = c .Do (t , "POST" , []string {"_synapse" , "admin" , "v1" , "register" }, client .WithJSONBody (t , reqBody ))
347325 return resp
348326}
327+
328+ // startUIASession starts a UIA session and returns the updated request body,
329+ // and associated session token, failing the test if the response is not a UIA challenge.
330+ func startUIASession (t * testing.T , c * client.CSAPI , user , pass string , extra map [string ]any ) (map [string ]any , string ) {
331+ reqBody := map [string ]any {
332+ "username" : user ,
333+ "password" : pass ,
334+ }
335+ if extra != nil {
336+ maps .Copy (extra , reqBody )
337+ }
338+ res := c .Do (t , "POST" , []string {"_matrix" , "client" , "v3" , "register" }, client .WithJSONBody (t , reqBody ))
339+ if res .StatusCode != 401 {
340+ t .Fatalf ("expected status code 401 (UIA challenge), got %d" , res .StatusCode )
341+ }
342+ body , err := io .ReadAll (res .Body )
343+ if err != nil {
344+ t .Fatal (err )
345+ }
346+ session := client .GetJSONFieldStr (t , body , "session" )
347+ if session == "" {
348+ t .Fatal ("expected non-empty `session` in uia challenge" )
349+ }
350+ reqBody ["auth" ] = map [string ]string {"session" : session , "type" : "m.login.dummy" }
351+ return reqBody , session
352+ }
0 commit comments