This repository was archived by the owner on Nov 25, 2024. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 665
This repository was archived by the owner on Nov 25, 2024. It is now read-only.
Login: Implement Token-based authentication #403
Copy link
Copy link
Closed
Labels
Milestone
Description
Spec URL: https://matrix.org/docs/spec/client_server/r0.3.0.html#post-matrix-client-r0-login https://matrix.org/docs/spec/client_server/r0.5.0#token-based
Difficulty: Medium
dendrite/src/github.com/matrix-org/dendrite/clientapi/routing/login.go
Lines 60 to 146 in dfcf31f
// Login implements GET and POST /login | |
func Login( | |
req *http.Request, accountDB *accounts.Database, deviceDB *devices.Database, | |
cfg config.Dendrite, | |
) util.JSONResponse { | |
if req.Method == "GET" { // TODO: support other forms of login other than password, depending on config options | |
return util.JSONResponse{ | |
Code: 200, | |
JSON: passwordLogin(), | |
} | |
} else if req.Method == "POST" { | |
var r passwordRequest | |
resErr := httputil.UnmarshalJSONRequest(req, &r) | |
if resErr != nil { | |
return *resErr | |
} | |
if r.User == "" { | |
return util.JSONResponse{ | |
Code: 400, | |
JSON: jsonerror.BadJSON("'user' must be supplied."), | |
} | |
} | |
util.GetLogger(req.Context()).WithField("user", r.User).Info("Processing login request") | |
// r.User can either be a user ID or just the localpart... or other things maybe. | |
localpart := r.User | |
if strings.HasPrefix(r.User, "@") { | |
var domain gomatrixserverlib.ServerName | |
var err error | |
localpart, domain, err = gomatrixserverlib.SplitID('@', r.User) | |
if err != nil { | |
return util.JSONResponse{ | |
Code: 400, | |
JSON: jsonerror.InvalidUsername("Invalid username"), | |
} | |
} | |
if domain != cfg.Matrix.ServerName { | |
return util.JSONResponse{ | |
Code: 400, | |
JSON: jsonerror.InvalidUsername("User ID not ours"), | |
} | |
} | |
} | |
acc, err := accountDB.GetAccountByPassword(req.Context(), localpart, r.Password) | |
if err != nil { | |
// Technically we could tell them if the user does not exist by checking if err == sql.ErrNoRows | |
// but that would leak the existence of the user. | |
return util.JSONResponse{ | |
Code: 403, | |
JSON: jsonerror.Forbidden("username or password was incorrect, or the accouqnt does not exist"), | |
} | |
} | |
token, err := auth.GenerateAccessToken() | |
if err != nil { | |
httputil.LogThenError(req, err) | |
} | |
// TODO: Use the device ID in the request | |
dev, err := deviceDB.CreateDevice( | |
req.Context(), acc.Localpart, nil, token, r.InitialDisplayName, | |
) | |
if err != nil { | |
return util.JSONResponse{ | |
Code: 500, | |
JSON: jsonerror.Unknown("failed to create device: " + err.Error()), | |
} | |
} | |
return util.JSONResponse{ | |
Code: 200, | |
JSON: loginResponse{ | |
UserID: dev.UserID, | |
AccessToken: dev.AccessToken, | |
HomeServer: cfg.Matrix.ServerName, | |
DeviceID: dev.ID, | |
}, | |
} | |
} | |
return util.JSONResponse{ | |
Code: 405, | |
JSON: jsonerror.NotFound("Bad method"), | |
} | |
} |
We currently only allow password-based authentication for login. Token-based authentication will be necessary for basic operation with clients. Currently users have tokens generated for them, we just need to check them on login.
Summary:
- Differentiate between
"type":
"m.login.token" and "m.login.password" in request body - Authenticate user based on token and device ID. Relationship between access tokens and devices
- Create test case(s) for logging in with access token