diff options
author | Kegsay <kegan@matrix.org> | 2020-07-10 00:39:44 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-10 00:39:44 +0100 |
commit | abf26c12f1a97fd2894a0509de9cf4a91c79d3ab (patch) | |
tree | 13b693141a36bfc4ae2ef2759e67dca92b2fc857 /clientapi/auth/user_interactive_test.go | |
parent | 9cc52f47f3ea2e8a009731cc46117cb996aed722 (diff) |
Add User-Interactive Authentication (#1193)
* Add User-Interactive Authentication
And use it when deleting a device. With tests.
* Make remaining sytest pass
* Linting
* 403 not 401 on wrong user/pass
Diffstat (limited to 'clientapi/auth/user_interactive_test.go')
-rw-r--r-- | clientapi/auth/user_interactive_test.go | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/clientapi/auth/user_interactive_test.go b/clientapi/auth/user_interactive_test.go new file mode 100644 index 00000000..d12652c0 --- /dev/null +++ b/clientapi/auth/user_interactive_test.go @@ -0,0 +1,174 @@ +package auth + +import ( + "context" + "encoding/json" + "fmt" + "testing" + + "github.com/matrix-org/dendrite/internal/config" + "github.com/matrix-org/dendrite/userapi/api" + "github.com/matrix-org/gomatrixserverlib" + "github.com/matrix-org/util" +) + +var ( + ctx = context.Background() + serverName = gomatrixserverlib.ServerName("example.com") + // space separated localpart+password -> account + lookup = make(map[string]*api.Account) + device = &api.Device{ + AccessToken: "flibble", + DisplayName: "My Device", + ID: "device_id_goes_here", + } +) + +func getAccountByPassword(ctx context.Context, localpart, plaintextPassword string) (*api.Account, error) { + acc, ok := lookup[localpart+" "+plaintextPassword] + if !ok { + return nil, fmt.Errorf("unknown user/password") + } + return acc, nil +} + +func setup() *UserInteractive { + cfg := &config.Dendrite{} + cfg.Matrix.ServerName = serverName + return NewUserInteractive(getAccountByPassword, cfg) +} + +func TestUserInteractiveChallenge(t *testing.T) { + uia := setup() + // no auth key results in a challenge + _, errRes := uia.Verify(ctx, []byte(`{}`), device) + if errRes == nil { + t.Fatalf("Verify succeeded with {} but expected failure") + } + if errRes.Code != 401 { + t.Errorf("Expected HTTP 401, got %d", errRes.Code) + } +} + +func TestUserInteractivePasswordLogin(t *testing.T) { + uia := setup() + // valid password login succeeds when an account exists + lookup["alice herpassword"] = &api.Account{ + Localpart: "alice", + ServerName: serverName, + UserID: fmt.Sprintf("@alice:%s", serverName), + } + // valid password requests + testCases := []json.RawMessage{ + // deprecated form + []byte(`{ + "auth": { + "type": "m.login.password", + "user": "alice", + "password": "herpassword" + } + }`), + // new form + []byte(`{ + "auth": { + "type": "m.login.password", + "identifier": { + "type": "m.id.user", + "user": "alice" + }, + "password": "herpassword" + } + }`), + } + for _, tc := range testCases { + _, errRes := uia.Verify(ctx, tc, device) + if errRes != nil { + t.Errorf("Verify failed but expected success for request: %s - got %+v", string(tc), errRes) + } + } +} + +func TestUserInteractivePasswordBadLogin(t *testing.T) { + uia := setup() + // password login fails when an account exists but is specced wrong + lookup["bob hispassword"] = &api.Account{ + Localpart: "bob", + ServerName: serverName, + UserID: fmt.Sprintf("@bob:%s", serverName), + } + // invalid password requests + testCases := []struct { + body json.RawMessage + wantRes util.JSONResponse + }{ + { + // fields not in an auth dict + body: []byte(`{ + "type": "m.login.password", + "user": "bob", + "password": "hispassword" + }`), + wantRes: util.JSONResponse{ + Code: 401, + }, + }, + { + // wrong type + body: []byte(`{ + "auth": { + "type": "m.login.not_password", + "identifier": { + "type": "m.id.user", + "user": "bob" + }, + "password": "hispassword" + } + }`), + wantRes: util.JSONResponse{ + Code: 400, + }, + }, + { + // identifier type is wrong + body: []byte(`{ + "auth": { + "type": "m.login.password", + "identifier": { + "type": "m.id.thirdparty", + "user": "bob" + }, + "password": "hispassword" + } + }`), + wantRes: util.JSONResponse{ + Code: 401, + }, + }, + { + // wrong password + body: []byte(`{ + "auth": { + "type": "m.login.password", + "identifier": { + "type": "m.id.user", + "user": "bob" + }, + "password": "not_his_password" + } + }`), + wantRes: util.JSONResponse{ + Code: 401, + }, + }, + } + for _, tc := range testCases { + _, errRes := uia.Verify(ctx, tc.body, device) + if errRes == nil { + t.Errorf("Verify succeeded but expected failure for request: %s", string(tc.body)) + continue + } + if errRes.Code != tc.wantRes.Code { + t.Errorf("got code %d want code %d for request: %s", errRes.Code, tc.wantRes.Code, string(tc.body)) + } + } +} |