diff options
author | Kegsay <kegan@matrix.org> | 2020-06-16 14:10:55 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-16 14:10:55 +0100 |
commit | 9c77022513f400db59409f5b55fc6223d38d6bb8 (patch) | |
tree | 52223755553ef4d7065747528e40c27a79a71dff /userapi/internal/api.go | |
parent | 57b7fa3db801c27190bfd143cfebe98e3d76a6ae (diff) |
Make userapi responsible for checking access tokens (#1133)
* Make userapi responsible for checking access tokens
There's still plenty of dependencies on account/device DBs, but this
is a start. This is a breaking change as it adds a required config
value `listen.user_api`.
* Cleanup
* Review comments and test fix
Diffstat (limited to 'userapi/internal/api.go')
-rw-r--r-- | userapi/internal/api.go | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/userapi/internal/api.go b/userapi/internal/api.go index 0144526c..1f0d5c94 100644 --- a/userapi/internal/api.go +++ b/userapi/internal/api.go @@ -19,8 +19,11 @@ import ( "database/sql" "fmt" + "github.com/matrix-org/dendrite/appservice/types" "github.com/matrix-org/dendrite/clientapi/auth/storage/accounts" "github.com/matrix-org/dendrite/clientapi/auth/storage/devices" + "github.com/matrix-org/dendrite/clientapi/userutil" + "github.com/matrix-org/dendrite/internal/config" "github.com/matrix-org/dendrite/userapi/api" "github.com/matrix-org/gomatrixserverlib" ) @@ -29,6 +32,8 @@ type UserInternalAPI struct { AccountDB accounts.Database DeviceDB devices.Database ServerName gomatrixserverlib.ServerName + // AppServices is the list of all registered AS + AppServices []config.ApplicationService } func (a *UserInternalAPI) QueryProfile(ctx context.Context, req *api.QueryProfileRequest, res *api.QueryProfileResponse) error { @@ -51,3 +56,66 @@ func (a *UserInternalAPI) QueryProfile(ctx context.Context, req *api.QueryProfil res.DisplayName = prof.DisplayName return nil } + +func (a *UserInternalAPI) QueryAccessToken(ctx context.Context, req *api.QueryAccessTokenRequest, res *api.QueryAccessTokenResponse) error { + if req.AppServiceUserID != "" { + appServiceDevice, err := a.queryAppServiceToken(ctx, req.AccessToken, req.AppServiceUserID) + res.Device = appServiceDevice + res.Err = err + return nil + } + device, err := a.DeviceDB.GetDeviceByAccessToken(ctx, req.AccessToken) + if err != nil { + if err == sql.ErrNoRows { + return nil + } + return err + } + res.Device = device + return nil +} + +// Return the appservice 'device' or nil if the token is not an appservice. Returns an error if there was a problem +// creating a 'device'. +func (a *UserInternalAPI) queryAppServiceToken(ctx context.Context, token, appServiceUserID string) (*api.Device, error) { + // Search for app service with given access_token + var appService *config.ApplicationService + for _, as := range a.AppServices { + if as.ASToken == token { + appService = &as + break + } + } + if appService == nil { + return nil, nil + } + + // Create a dummy device for AS user + dev := api.Device{ + // Use AS dummy device ID + ID: types.AppServiceDeviceID, + // AS dummy device has AS's token. + AccessToken: token, + } + + localpart, err := userutil.ParseUsernameParam(appServiceUserID, &a.ServerName) + if err != nil { + return nil, err + } + + if localpart != "" { // AS is masquerading as another user + // Verify that the user is registered + account, err := a.AccountDB.GetAccountByLocalpart(ctx, localpart) + // Verify that account exists & appServiceID matches + if err == nil && account.AppServiceID == appService.ID { + // Set the userID of dummy device + dev.UserID = appServiceUserID + return &dev, nil + } + return nil, &api.ErrorForbidden{Message: "appservice 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 +} |