Skip to content

Commit

Permalink
Merge pull request #751 from uc-cdis/feat/google-user-sa
Browse files Browse the repository at this point in the history
feat(userinfo): add google primary service account email to userinfo …
  • Loading branch information
Avantol13 committed Jan 15, 2020
2 parents 8fefae0 + c3c43b8 commit 81afd19
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 13 deletions.
13 changes: 10 additions & 3 deletions docs/google_architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ In order to fully understand the options for requester pays support, it's import
The easiest option for supporting requester pays is to simply bill a Google Project you already own for all access to the bucket instead of requiring end-users to supply a project to bill. This essentially makes the requester pays bucket a non-requester pays bucket, since you'll be paying for all the access. This may be a necessary solution in cases where:

1) you want to serve data from a bucket you don't fully control (in other words, can't just turn "requester pays" off)
2) you don't want end-users to have to do manual configuration in Google Cloud Platform to enable billing their project
2) you don't want end-users (or client applications) to have to do configuration in Google Cloud Platform to enable billing their own project
3) you/end-users don't want to have to give your application IAM permissions in a project the end-user owns to automatically enable billing

**NOTE:** If you do _not_ want to bill yourself for access, it is possible to require end-users to provide the project to bill OR configure a default billing project other than one you own. _However_, this will require more work for end-users that you need to consider.
Expand All @@ -110,18 +110,25 @@ Whether you bill your own project, or require end-users to specify a billing pro

> "All actions that include a billing project in the request require serviceusage.services.use permission for the project that's specified" [according to Google's docs](https://cloud.google.com/storage/docs/access-control/iam-console).
You have 2 options to achieve the above:
You have 3 options to achieve the above:

1) assume end-users will provide the necessary permission for billing
2) configure Fence to automatically attempt to provide the necessary permission for billing
3) create a client application that automatically provides the necessary permission for billing

If you want Fence to automatically attempt to provide the necessary permissions to the relevant service accounts for data access, the Fence admin service account needs a couple pre-defined Google roles (through their Cloud IAM) on whatever project is provided for billing (be that in a request to Fence or whatever is configured as the "default billing project"):
If you want Fence to automatically attempt to provide the necessary permissions to the relevant service accounts for data access (option 2 above), the Fence admin service account needs a couple pre-defined Google roles (through their Cloud IAM) on whatever project is provided for billing (be that in a request to Fence or whatever is configured as the "default billing project"):

* `Project IAM Admin`: to update the project's policy to give the necessary service account(s) billing permission
* `Role Administrator`: for creating a custom role that only provides billing permission to the project

> NOTE: The custom role that Fence creates contains the single permission in Google `serviceusage.services.use`.
If you want to create a client application that will be able to give the right service accounts
billing permission (option 3) then there is some additional information you should know about. The
userinfo endpoint supplies the user's `primary_google_service_account` which is the email address of the Google Service Account attached to that user for the creation of Signed URLs.

> NOTE: Users' Primary Google Service Accounts are created lazily, so it is possible that `primary_google_service_account` is `None`/`null` if the user has not previously requested data via a Google Data Access method. There must be an API call previous to reading userinfo to access data in Google that the user has access to.
#### Requester Pays Signed URLs and Temporary Service Account Credentials

1) For [Signed URLs](#signed-urls): a `userProject=<google-project-to-bill>` query parameter will be appended to the signed url
Expand Down
6 changes: 6 additions & 0 deletions fence/resources/user/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from fence.resources.google.utils import (
get_linked_google_account_email,
get_linked_google_account_exp,
get_service_account,
)
from fence.resources.userdatamodel import get_user_groups
import smtplib
Expand Down Expand Up @@ -90,6 +91,11 @@ def get_user_info(current_session, username):
"message": "",
}

# User SAs are stored in db with client_id = None
primary_service_account = get_service_account(client_id=None, user_id=user.id) or {}
primary_service_account_email = getattr(primary_service_account, "email", None)
info["primary_google_service_account"] = primary_service_account_email

if hasattr(flask.current_app, "arborist"):
try:
resources = flask.current_app.arborist.list_resources_for_user(
Expand Down
24 changes: 14 additions & 10 deletions openapis/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ paths:
- oauth2
summary: Perform OAuth2 authorization
description: |
**IMPORTANT NOTE**: These docs are provided as a courtesy but do _NOT_ include the entirety of the OIDC Standard
**IMPORTANT NOTE**: These docs are provided as a courtesy but do _NOT_ include the entirety of the OIDC Standard
simply because of its length and complexity.
Please [refer to the standard](https://openid.net/specs/openid-connect-core-1_0.html) for complete details.
Obtain an authorization grant through the OAuth2 protocol. To handle
this request, render a page for the user to confirm the OAuth2 grant
(through e.g. Google). Redirect user to `redirect_uri` with an added
Expand Down Expand Up @@ -114,11 +114,11 @@ paths:
- oauth2
summary: Perform OAuth2 authorization
description: |
**IMPORTANT NOTE**: These docs are provided as a courtesy but do _NOT_ include the entirety of the OIDC Standard
**IMPORTANT NOTE**: These docs are provided as a courtesy but do _NOT_ include the entirety of the OIDC Standard
simply because of its length and complexity.
Please [refer to the standard](https://openid.net/specs/openid-connect-core-1_0.html) for complete details.
Obtain an authorization grant through the OAuth2 protocol. To handle
this request, render a page for the user to confirm the OAuth2 grant
(through e.g. Google). Redirect user to `redirect_uri` with an added
Expand Down Expand Up @@ -166,11 +166,11 @@ paths:
- oauth2
summary: Exchange code for or refresh the access token.
description: |
**IMPORTANT NOTE**: These docs are provided as a courtesy but do _NOT_ include the entirety of the OIDC Standard
**IMPORTANT NOTE**: These docs are provided as a courtesy but do _NOT_ include the entirety of the OIDC Standard
simply because of its length and complexity.
Please [refer to the standard](https://openid.net/specs/openid-connect-core-1_0.html) for complete details.
Exchange the `code` obtained from OAuth2 for an access token, or refresh
the access token using a refresh token.
operationId: token
Expand Down Expand Up @@ -841,7 +841,7 @@ paths:
summary: Receive API key
description: >-
Get a new API key for the current user. API keys can be used to retrieve
access tokens which will allow for authed communication to our API. Can
access tokens which will allow for authed communication to our API. Can
pass a list of requested OIDC scopes in the body. Automatically gives "openid" scope.
Any additional scopes (like "user" for seeing user information or "data" for hitting
signed url endpoint) must be explicitly requested and user must already have access.
Expand Down Expand Up @@ -1980,6 +1980,7 @@ components:
- certificates_uploaded
- email
- message
- primary_google_service_account
properties:
pdc_id:
type: string
Expand All @@ -2003,6 +2004,9 @@ components:
description: ''
message:
type: string
primary_google_service_account:
type: string
description: 'email address of the users primary service account used for signing URLs'
SignedURL:
type: object
properties:
Expand Down

0 comments on commit 81afd19

Please sign in to comment.