Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial version of OAuth server to manage access to Gitpod workspaces #4222

Merged
merged 1 commit into from
May 21, 2021

Conversation

rl-gitpod
Copy link
Contributor

No description provided.

@rl-gitpod
Copy link
Contributor Author

rl-gitpod commented May 17, 2021

What does this PR do?

  • Adds an OAuth2 server endpoints (behind a feature flag) to enable standard OAuth2 clients to interact with Gitpod and be granted access to a users workspaces
  • Specifically, it utilises PKCE (Proof Key for Code Exchange) to reduce the potential for MITM attacks to gain access to tokens
  • Exposes /api/oauth/authorization and /api/oauth/token for the client flow to use along with /oauth-approval for the access approval form:
    • /api/oauth/authorization
      • will open a browser and redirect to the standard Gitpod provider login (Github, Gitlab, etc) if not logged in (opening a browser works in Linux (requires xdg-open)/OSX/Windows
      • will open a browser and ask user to grant permission for the OAuth2 client to access their workspaces if not already done so
      • opened tabs are automatically closed
    • /api/oauth/token if given correct authenticaion code and PKCE params will return a Gitpod token in standard OAuth2 format:
{
  "access_token": "eyJhb...",
  "expires_in": 86400,
  "refresh_token": "eyJhb...",
  "scope": "function:getWorkspace, etc",
  "token_type": "Bearer"
}
* /oauth-approval displays the request for client access approval or not (needs tidying up)
  • Extends the existing login code to add support for the required redirection - currently limited only to the new endpoints on the same server
  • Connects the OAuth2 server into the db, reusing the GitpodToken table as the token repository, adding a table for the temporary auth code (needs to be periodically emptied)
  • Adds a hacky way to test this to the existing client
  • Adds some initial documentation on how to add tables, etc to gitpod-db via TypeORM

What this PR does not do?

  • Add the new OAuth2 flow to the existing client (next up)

Testing

Installing local app

  • Login: https://rl-gplctl-oauth-server.staging.gitpod-dev.com/workspaces/
  • Open this branch in Gitpod: https://gitpod.io/#https://github.com/gitpod-io/gitpod/pull/4222
  • Run leeway build --serve=:8080 components/local-app:app-darwin in terminal to build local-app for Mac
    for linux or windows use another suffix
  • Open port 8080 in another tab and download local-app
  • Grant permissions to execute the app (e.g. Ctrl+Click - Open on OSX)
  • chmod +x to make it executable
  • Run GITPOD_HOST=https://rl-gplctl-oauth-server.staging.gitpod-dev.com ./local-app test
  • It will open the standard login screen if you are not already logged in:
    Screen Shot 2021-05-18 at 8 59 31 am
  • If you haven't granted access to your workspaces to the client it will ask:
    Screen Shot 2021-05-18 at 8 59 45 am
  • Clicking 'No' will close down the local-app immediately
  • Clicking 'Yes' will proceed with the retrieval of the OAuth2 token

@rl-gitpod
Copy link
Contributor Author

rl-gitpod commented May 17, 2021

/werft run

👍 started the job as gitpod-build-rl-gplctl-oauth-server.2

@rl-gitpod rl-gitpod marked this pull request as ready for review May 17, 2021 23:13
@rl-gitpod rl-gitpod self-assigned this May 17, 2021
@rl-gitpod rl-gitpod requested a review from akosyakov May 18, 2021 05:58
@rl-gitpod
Copy link
Contributor Author

rl-gitpod commented May 18, 2021

/werft run

👍 started the job as gitpod-build-rl-gplctl-oauth-server.3

@rl-gitpod rl-gitpod requested a review from csweichel May 18, 2021 05:58
@svenefftinge
Copy link
Member

@gtsiolis can you help with the design of this page?
Screenshot 2021-05-18 at 09 34 18

@gtsiolis
Copy link
Contributor

gtsiolis commented May 18, 2021

@gtsiolis can you help with the design of this page?

@svenefftinge Yes! Although not needed, how could I see this page in aciton? I'd like to also see the interaction for this (if the tab is closing, etc). I tried following the steps in #4222 (comment) but only see the following then opening port 8080. /cc @rl-gitpod

Screenshot 2021-05-18 at 12 32 29 PM

@rl-gitpod
Copy link
Contributor Author

@gtsiolis can you help with the design of this page?

@svenefftinge Yes! Although not needed, how could I see this page in aciton? I'd like to also see the interaction for this (if the tab is closing, etc). I tried following the steps in #4222 (comment) but only see the following then opening port 8080. /cc @rl-gitpod

You need to download the local-app in that screen and keep on with the directions.
I'll record a loom which should help.

@rl-gitpod
Copy link
Contributor Author

rl-gitpod commented May 18, 2021

@gtsiolis https://www.loom.com/share/9442ca1e2ab6408c93ce8c3390cf20e4

Note that the gitpod.io page is only there to keep chrome on the screen during the recording, it plays no part.

Copy link
Contributor

@csweichel csweichel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other than the generous display of logging statements the code LGTM. I've gone through the testing instructions and things work as advertised. Pending @gtsiolis's comments this could land in main I reckon :)

components/gitpod-db/src/typeorm/user-db-impl.ts Outdated Show resolved Hide resolved
components/gitpod-protocol/src/protocol.ts Show resolved Hide resolved
components/server/src/oauth-server/oauth-controller.ts Outdated Show resolved Hide resolved
@gtsiolis
Copy link
Contributor

gtsiolis commented May 18, 2021

Note that the gitpod.io page is only there to keep chrome on the screen during the recording ...

Thanks for clarifying @rl-gitpod!


Here're two variations we could use in case one of these two makes more sense, following two relevant existing designs in the product. Feel free to adjust text per need. A couple of notes or things to consider:

  1. Since this action is associated with an account, including the account avatar can help the user understand which kind of data will be exposed with this authorization.
  2. If possible, we could include the workspace name (friendly identifier) in the message body. We limit the scope of this authorization to a specific workspace, right?
  3. Title message could also read Authorize Gitpod App, Authorize Gitpod CLI, etc.
  4. The first design proposal follows the specs from the Install GitHub App flow, see Install in Implement /install-github-app flow #3702.
  5. The second design proposal follows the modal component as used in the workspace start page when reaching a limit, see Parallel Workspaces [Dashboard] Workspace Start Page #3301.
  6. If both seem appropriate, let's go with Proposal A. Otherwise, I'll defer this to @svenefftinge.
  7. If useful, we could provide useful a link to the dashboard instead of cancelling the action. Cancel action is probably more appropriate.
  8. If these style changes can land into the same milestone, it should be fine to leave these out of the scope of this PR and open a new PR instead. 🛹
Proposal A (Full Page) Proposal B (Modal)
image image

See also relevant specs and relevant existing implementations in #3704 and #3693.

components/server/tsconfig.json Outdated Show resolved Hide resolved
yarn.lock Outdated
version "5.0.1"
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-5.0.1.tgz#9bab9c330d89f43fc8c1e8702b5c36e058a01794"
integrity sha512-JvONPptw3GAQGXlVV2utDcHx0BiY34FupW/kI6mZ5x06ER5DdPG/tXWMVHjTNULF5uKPOUUD0SaXg5QaubJL0A==

vscode-languageserver-protocol@3.15.3:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

surprising!

components/server/src/oauth-server/oauth-controller.ts Outdated Show resolved Hide resolved
components/dashboard/src/OauthClientApproval.tsx Outdated Show resolved Hide resolved
public issueAuthCode(client: OAuthClient, user: OAuthUser | undefined, scopes: OAuthScope[]): OAuthAuthCode {
const code = crypto.randomBytes(30).toString('hex');
log.info(`issueAuthCode: ${JSON.stringify(client)}, ${JSON.stringify(user)}, ${JSON.stringify(scopes)}, ${code}`);
// NOTE: caller (@jmondi/oauth2-server) is responsible for adding the remaining items, PKCE params, redirect URL, etc
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on #4164 (comment)

given, that this is called by the oauth2 server framework, I'd suggest to extract and move it to the server component. it seems odd to implement the missing bits for the framework within gitpod-db.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That requires moving the entire AuthCodeRepositoryDB (OAuthAuthCodeRepository) implementation to server and since it requires storage, then adding a db service + implementation for it to use.

I agree it meets the current, very structured implementation approach for most parts of the system that interact with the db and will take a look at it tomorrow.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That requires moving the entire AuthCodeRepositoryDB (OAuthAuthCodeRepository) implementation to server

no it doesn't.

this pattern is used in may cases here. the DB implementation lives in gitpod-db and is injected into services from server.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

odd to implement the missing bits for the framework within gitpod-db.

Not so much a missing bit but the OAuthAuthCodeRepository interface needs to be implemented for the framework to use. Moving 1 requires moving the rest (yes - there are other, less readable ways to do so).

this pattern is used in may cases here. the DB implementation lives in gitpod-db and is injected into services from server.

Agreed. That's what I was referring to with "then adding a db service + implementation for it to use"

components/dashboard/src/OauthClientApproval.tsx Outdated Show resolved Hide resolved
@rl-gitpod
Copy link
Contributor Author

rl-gitpod commented May 19, 2021

Thanks @gtsiolis!

  1. Since this action is associated with an account, including the account avatar can help the user understand which kind of data will be exposed with this authorization.

What we are doing here is the same as the 'Consent form' for any/all OAuth implementations e.g. here or here
They tend to be more modal in nature, but not always.

Ultimately we will want to itemise the types of access (scopes) they are approving, but we don't have a good sense of what they should be at this point so we are asking for a general access approval.

  1. If possible, we could include the workspace name (friendly identifier) in the message body. We limit the scope of this authorization to a specific workspace, right?

It is for all workspaces atm. That will likely change in the future, but not for the first iteration and possibly more.

  1. If both seem appropriate, let's go with Proposal A. Otherwise, I'll defer this to @svenefftinge.

The 'Consent form' in other systems tends to be modal. It is also simpler to implement :-)

If it is not modal, having the ability to jump to the dashboard/account/etc without completing an action would need to be handled. If we assume that it doesn't mean either yes or no (and therefore we don't need to update the db to reflect that) it could just be a timeout i.e. easy.

  1. If these style changes can land into the same milestone, it should be fine to leave these out of the scope of this PR and open a new PR instead. 🛹

If we have a decision on A vs B, I'll take a look tomorrow.

@rl-gitpod
Copy link
Contributor Author

rl-gitpod commented May 20, 2021

/werft run

👍 started the job as gitpod-build-rl-gplctl-oauth-server.10

@rl-gitpod
Copy link
Contributor Author

rl-gitpod commented May 21, 2021

/werft run

👍 started the job as gitpod-build-rl-gplctl-oauth-server.16

@rl-gitpod
Copy link
Contributor Author

rl-gitpod commented May 21, 2021

/werft run

👍 started the job as gitpod-build-rl-gplctl-oauth-server.17

Copy link
Contributor

@csweichel csweichel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got this when trying to authenticate:
image

components/server/src/oauth-server/oauth-controller.ts Outdated Show resolved Hide resolved
@rl-gitpod
Copy link
Contributor Author

Got this when trying to authenticate:
image

Ah, a little chicken/egg :-(

That scope is valid but insufficient (only a single workspace) so it was changed to 'getWorkspaces' in the backend.

You need to build a local app using the commit I linked to in our discussion

Copy link
Contributor

@csweichel csweichel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's still a bunch of log statements which I'd fret would be too loud in production. Many (most?) of them should either be on debug level, or be removed.

Other than that, after some commit history authoring this change would be ready for main.

Thank you very much for adding this! OAuth in Gitpod enables a whole host of new use-cases.

components/server/src/user/user-controller.ts Outdated Show resolved Hide resolved
components/server/src/user/user-controller.ts Outdated Show resolved Hide resolved
components/gitpod-db/src/typeorm/user-db-impl.ts Outdated Show resolved Hide resolved
components/gitpod-db/src/typeorm/user-db-impl.ts Outdated Show resolved Hide resolved
components/gitpod-db/src/typeorm/user-db-impl.ts Outdated Show resolved Hide resolved
components/gitpod-db/src/typeorm/user-db-impl.ts Outdated Show resolved Hide resolved
components/gitpod-db/src/typeorm/user-db-impl.ts Outdated Show resolved Hide resolved
components/gitpod-db/src/typeorm/user-db-impl.ts Outdated Show resolved Hide resolved
components/gitpod-db/src/typeorm/user-db-impl.ts Outdated Show resolved Hide resolved
components/gitpod-db/src/typeorm/user-db-impl.ts Outdated Show resolved Hide resolved
to manage client application access to users Gitpod workspaces
Copy link
Contributor

@csweichel csweichel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@rl-gitpod rl-gitpod merged commit f96392a into main May 21, 2021
@rl-gitpod rl-gitpod deleted the rl/gplctl-oauth-server branch May 21, 2021 11:23
MatthewFagan pushed a commit to trilogy-group/gitpod that referenced this pull request Nov 17, 2021
…io#4222)

to manage client application access to users Gitpod workspaces
MatthewFagan pushed a commit to trilogy-group/gitpod that referenced this pull request Nov 18, 2021
…io#4222)

to manage client application access to users Gitpod workspaces
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants