From 613f7233751ff5c50f35464dc739a7aac2bf6b13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20Deifu=C3=9F?= Date: Tue, 4 Jan 2022 03:36:13 +0100 Subject: [PATCH] fix tests & rebased on master MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Fabian Deifuß --- clientapi/auth/challenge_response.go | 1 + clientapi/auth/user_interactive.go | 2 +- clientapi/auth/user_interactive_test.go | 96 ++++++++++++++++++++++++- 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/clientapi/auth/challenge_response.go b/clientapi/auth/challenge_response.go index fde3f4dd7..e1fdbd253 100644 --- a/clientapi/auth/challenge_response.go +++ b/clientapi/auth/challenge_response.go @@ -16,6 +16,7 @@ type GetAccountByChallengeResponse func(ctx context.Context, localpart, b64encod type ChallengeResponseRequest struct { Login Signature string `json:"signature"` + Session string `json:"session"` } // LoginTypeChallengeResponse using public key encryption diff --git a/clientapi/auth/user_interactive.go b/clientapi/auth/user_interactive.go index 4597751cb..e6786e092 100644 --- a/clientapi/auth/user_interactive.go +++ b/clientapi/auth/user_interactive.go @@ -252,7 +252,7 @@ func (u *UserInteractive) Verify(ctx context.Context, bodyBytes []byte, device * } r := loginType.Request() - if err := json.Unmarshal(bodyBytes, r); err != nil { + if err := json.Unmarshal([]byte(gjson.GetBytes(bodyBytes, "auth").Raw), r); err != nil { return nil, &util.JSONResponse{ Code: http.StatusBadRequest, JSON: jsonerror.BadJSON("The request body could not be decoded into valid JSON. " + err.Error()), diff --git a/clientapi/auth/user_interactive_test.go b/clientapi/auth/user_interactive_test.go index 859560bc6..fc9ead9fc 100644 --- a/clientapi/auth/user_interactive_test.go +++ b/clientapi/auth/user_interactive_test.go @@ -2,8 +2,12 @@ package auth import ( "context" + "crypto/ed25519" + "crypto/rand" + "encoding/base64" "encoding/json" "fmt" + "github.com/tidwall/gjson" "testing" "github.com/matrix-org/dendrite/setup/config" @@ -22,6 +26,8 @@ var ( DisplayName: "My Device", ID: "device_id_goes_here", } + _, priv, _ = ed25519.GenerateKey(rand.Reader) + pub64 = base64.StdEncoding.EncodeToString(priv.Public().(ed25519.PublicKey)) ) func getAccountByPassword(ctx context.Context, localpart, plaintextPassword string) (*api.Account, error) { @@ -33,7 +39,7 @@ func getAccountByPassword(ctx context.Context, localpart, plaintextPassword stri } func getAccountByChallengeResponse(ctx context.Context, localpart, b64encodedSignature, challenge string) (*api.Account, error) { - acc, ok := lookup[localpart+" "+b64encodedSignature+" "+challenge] + acc, ok := lookup[localpart+" "+pub64] if !ok { return nil, fmt.Errorf("unknown user/pubkey") } @@ -183,3 +189,91 @@ func TestUserInteractivePasswordBadLogin(t *testing.T) { } } } + +func TestUserInteractiveDigitalSignatureLogin(t *testing.T) { + uia := setup() + // valid digital signature login succeeds when an account exists + lookup["alice "+pub64] = &api.Account{ + Localpart: "alice", + ServerName: serverName, + UserID: fmt.Sprintf("@alice:%s", serverName), + } + getSessionReq := `{ + "identifier": { + "type": "m.id.user", + "user": "alice" + }, + "type": "m.login.challenge_response" + }` + _, errSessionRes := uia.Verify(ctx, []byte(getSessionReq), device) + byteSessionRes, _ := json.Marshal(errSessionRes) + var sessionRes struct { + Session string `json:"session"` + Params map[string]string `json:"params"` + } + jsonRes := gjson.GetBytes(byteSessionRes, "JSON").Raw + _ = json.Unmarshal([]byte(jsonRes), &sessionRes) + + session := sessionRes.Session + sig := ed25519.Sign(priv, []byte(sessionRes.Params["challenge"])) + b64sig := base64.StdEncoding.EncodeToString(sig) + loginReq := fmt.Sprintf(`{ + "auth": { + "session": "%s", + "type": "m.login.challenge_response", + "signature": "%s", + "identifier": { + "type": "m.id.user", + "user": "alice"} + }, + "type": "m.login.challenge_response" + }`, session, b64sig) + + _, err := uia.Verify(ctx, []byte(loginReq), device) + if err != nil { + t.Errorf("Verify failed but expected success for request: %s - got %+v", loginReq, err) + } +} + +func TestUserInteractiveInvalidDigitalSignatureLogin(t *testing.T) { + uia := setup() + // login fails when no sig is provided + lookup["alice "+pub64] = &api.Account{ + Localpart: "alice", + ServerName: serverName, + UserID: fmt.Sprintf("@alice:%s", serverName), + } + getSessionReq := `{ + "identifier": { + "type": "m.id.user", + "user": "alice" + }, + "type": "m.login.challenge_response" + }` + _, errSessionRes := uia.Verify(ctx, []byte(getSessionReq), device) + byteSessionRes, _ := json.Marshal(errSessionRes) + var sessionRes struct { + Session string `json:"session"` + Params map[string]string `json:"params"` + } + jsonRes := gjson.GetBytes(byteSessionRes, "JSON").Raw + _ = json.Unmarshal([]byte(jsonRes), &sessionRes) + + session := sessionRes.Session + loginReq := fmt.Sprintf(`{ + "auth": { + "session": "%s", + "type": "m.login.challenge_response", + "signature": "", + "identifier": { + "type": "m.id.user", + "user": "alice"} + }, + "type": "m.login.challenge_response" + }`, session) + + resp, err := uia.Verify(ctx, []byte(loginReq), device) + if err == nil { + t.Errorf("Verify succeeded but expected failure for request: %s - got %+v", loginReq, resp) + } +}