mirror of
https://github.com/hoernschen/dendrite.git
synced 2024-12-26 15:08:28 +00:00
Check for AS user before real user
This commit is contained in:
parent
2fb2f7ca7b
commit
1fd2686bac
1 changed files with 69 additions and 43 deletions
|
@ -65,14 +65,33 @@ type Data struct {
|
||||||
func VerifyUserFromRequest(
|
func VerifyUserFromRequest(
|
||||||
req *http.Request, data Data,
|
req *http.Request, data Data,
|
||||||
) (*authtypes.Device, *util.JSONResponse) {
|
) (*authtypes.Device, *util.JSONResponse) {
|
||||||
// Try to find local user from device database
|
// Check to see if this is an application service user
|
||||||
dev, devErr := verifyAccessToken(req, data.DeviceDB)
|
dev, err := verifyApplicationServiceUser(req, data)
|
||||||
if devErr == nil {
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if dev != nil {
|
||||||
return dev, nil
|
return dev, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try to find local user from device database
|
||||||
|
dev, err = verifyAccessToken(req, data.DeviceDB)
|
||||||
|
if err == nil {
|
||||||
|
return dev, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, &util.JSONResponse{
|
||||||
|
Code: http.StatusUnauthorized,
|
||||||
|
JSON: jsonerror.UnknownToken("Unrecognized access token"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// verifyApplicationServiceUser attempts to retrieve a userID given a request
|
||||||
|
// originating from an application service
|
||||||
|
func verifyApplicationServiceUser(
|
||||||
|
req *http.Request, data Data,
|
||||||
|
) (*authtypes.Device, *util.JSONResponse) {
|
||||||
// Try to find the Application Service user
|
// Try to find the Application Service user
|
||||||
token, err := extractAccessToken(req)
|
token, err := extractApplicationServiceAccessToken(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, &util.JSONResponse{
|
return nil, &util.JSONResponse{
|
||||||
Code: http.StatusUnauthorized,
|
Code: http.StatusUnauthorized,
|
||||||
|
@ -89,6 +108,7 @@ func VerifyUserFromRequest(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
userID := req.URL.Query().Get("user_id")
|
||||||
if appService != nil {
|
if appService != nil {
|
||||||
// Create a dummy device for AS user
|
// Create a dummy device for AS user
|
||||||
dev := authtypes.Device{
|
dev := authtypes.Device{
|
||||||
|
@ -98,47 +118,47 @@ func VerifyUserFromRequest(
|
||||||
AccessToken: token,
|
AccessToken: token,
|
||||||
}
|
}
|
||||||
|
|
||||||
userID := req.URL.Query().Get("user_id")
|
// Check for user masquerading
|
||||||
localpart, err := userutil.ParseUsernameParam(userID, nil)
|
if userID != "" {
|
||||||
if err != nil {
|
localpart, err := userutil.ParseUsernameParam(userID, nil)
|
||||||
return nil, &util.JSONResponse{
|
if err != nil {
|
||||||
Code: http.StatusBadRequest,
|
return nil, &util.JSONResponse{
|
||||||
JSON: jsonerror.InvalidUsername(err.Error()),
|
Code: http.StatusBadRequest,
|
||||||
|
JSON: jsonerror.InvalidUsername(err.Error()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if localpart != "" { // AS is masquerading as another user
|
||||||
|
// Verify that the user is registered
|
||||||
|
account, err := data.AccountDB.GetAccountByLocalpart(req.Context(), localpart)
|
||||||
|
// Verify that account exists & appServiceID matches
|
||||||
|
if err == nil && account.AppServiceID == appService.ID {
|
||||||
|
// Set the userID of dummy device
|
||||||
|
dev.UserID = userID
|
||||||
|
return &dev, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, &util.JSONResponse{
|
||||||
|
Code: http.StatusForbidden,
|
||||||
|
JSON: jsonerror.Forbidden("Application service has not registered this user"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// AS is not masquerading as any user, so use AS's sender_localpart
|
||||||
|
dev.UserID = appService.SenderLocalpart
|
||||||
}
|
}
|
||||||
|
|
||||||
if localpart != "" { // AS is masquerading as another user
|
|
||||||
// Verify that the user is registered
|
|
||||||
account, err := data.AccountDB.GetAccountByLocalpart(req.Context(), localpart)
|
|
||||||
// Verify that account exists & appServiceID matches
|
|
||||||
if err == nil && account.AppServiceID == appService.ID {
|
|
||||||
// Set the userID of dummy device
|
|
||||||
dev.UserID = userID
|
|
||||||
return &dev, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, &util.JSONResponse{
|
|
||||||
Code: http.StatusForbidden,
|
|
||||||
JSON: jsonerror.Forbidden("Application service has not registered this user"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AS is not masquerading as any user, so use AS's sender_localpart
|
|
||||||
dev.UserID = appService.SenderLocalpart
|
|
||||||
return &dev, nil
|
return &dev, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, &util.JSONResponse{
|
// Application service was not found with this token
|
||||||
Code: http.StatusUnauthorized,
|
return nil, nil
|
||||||
JSON: jsonerror.UnknownToken("Unrecognized access token"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// verifyAccessToken verifies that an access token was supplied in the given HTTP request
|
// verifyAccessToken verifies that an access token was supplied in the given HTTP request
|
||||||
// and returns the device it corresponds to. Returns resErr (an error response which can be
|
// and returns the device it corresponds to. Returns resErr (an error response which can be
|
||||||
// sent to the client) if the token is invalid or there was a problem querying the database.
|
// sent to the client) if the token is invalid or there was a problem querying the database.
|
||||||
func verifyAccessToken(req *http.Request, deviceDB DeviceDatabase) (device *authtypes.Device, resErr *util.JSONResponse) {
|
func verifyAccessToken(req *http.Request, deviceDB DeviceDatabase) (device *authtypes.Device, resErr *util.JSONResponse) {
|
||||||
token, err := extractAccessToken(req)
|
token, err := extractUserAccessToken(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resErr = &util.JSONResponse{
|
resErr = &util.JSONResponse{
|
||||||
Code: http.StatusUnauthorized,
|
Code: http.StatusUnauthorized,
|
||||||
|
@ -172,20 +192,26 @@ func GenerateAccessToken() (string, error) {
|
||||||
return base64.RawURLEncoding.EncodeToString(b), nil
|
return base64.RawURLEncoding.EncodeToString(b), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// extractAccessToken from a request, or return an error detailing what went wrong. The
|
// extractApplicationServiceAccessToken retreives an access token from a request
|
||||||
// error message MUST be human-readable and comprehensible to the client.
|
// originating from an application service
|
||||||
func extractAccessToken(req *http.Request) (string, error) {
|
func extractApplicationServiceAccessToken(req *http.Request) (string, error) {
|
||||||
// cf https://github.com/matrix-org/synapse/blob/v0.19.2/synapse/api/auth.py#L631
|
|
||||||
authBearer := req.Header.Get("Authorization")
|
authBearer := req.Header.Get("Authorization")
|
||||||
queryToken := req.URL.Query().Get("access_token")
|
token := req.URL.Query().Get("access_token")
|
||||||
if authBearer != "" && queryToken != "" {
|
if authBearer != "" && token != "" {
|
||||||
return "", fmt.Errorf("mixing Authorization headers and access_token query parameters")
|
return "", fmt.Errorf("mixing Authorization headers and access_token query parameters")
|
||||||
}
|
}
|
||||||
|
if token != "" {
|
||||||
if queryToken != "" {
|
return token, nil
|
||||||
return queryToken, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return "", fmt.Errorf("missing access token")
|
||||||
|
}
|
||||||
|
|
||||||
|
// extractUserAccessToken retreives an access token from a request originating
|
||||||
|
// from a non-application service
|
||||||
|
func extractUserAccessToken(req *http.Request) (string, error) {
|
||||||
|
authBearer := req.Header.Get("Authorization")
|
||||||
|
|
||||||
if authBearer != "" {
|
if authBearer != "" {
|
||||||
parts := strings.SplitN(authBearer, " ", 2)
|
parts := strings.SplitN(authBearer, " ", 2)
|
||||||
if len(parts) != 2 || parts[0] != "Bearer" {
|
if len(parts) != 2 || parts[0] != "Bearer" {
|
||||||
|
|
Loading…
Reference in a new issue