You've already forked oauth2-proxy
mirror of
https://github.com/oauth2-proxy/oauth2-proxy.git
synced 2025-08-06 22:42:56 +02:00
feat: allow use more possible google admin-sdk api scopes (#2743)
* feat: Allow use more possible google admin-sdk api scopes. * reduce cognitive complexity Signed-off-by: Bob Du <i@bobdu.cc> * remove unnecessary else block / indentation Signed-off-by: Jan Larwig <jan@larwig.com> * add changelog entry Signed-off-by: Jan Larwig <jan@larwig.com> * slight formatting and error message rephrasing Signed-off-by: Jan Larwig <jan@larwig.com> --------- Signed-off-by: Bob Du <i@bobdu.cc> Signed-off-by: Jan Larwig <jan@larwig.com> Co-authored-by: Jan Larwig <jan@larwig.com>
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -17,6 +17,7 @@ c.out
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
.DS_Store
|
||||
.idea/
|
||||
.vscode/*
|
||||
!/.vscode/tasks.json
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
- [#2615](https://github.com/oauth2-proxy/oauth2-proxy/pull/2615) feat(cookies): add option to set a limit on the number of per-request CSRF cookies oauth2-proxy sets (@bh-tt)
|
||||
- [#2605](https://github.com/oauth2-proxy/oauth2-proxy/pull/2605) fix: show login page on broken cookie (@Primexz)
|
||||
- [#2743](https://github.com/oauth2-proxy/oauth2-proxy/pull/2743) feat: allow use more possible google admin-sdk api scopes (@BobDu)
|
||||
|
||||
# V7.10.0
|
||||
|
||||
|
@ -37,18 +37,17 @@ account is still authorized.
|
||||
|
||||
#### Restrict auth to specific Google groups on your domain. (optional)
|
||||
|
||||
1. Create a [service account](https://developers.google.com/identity/protocols/OAuth2ServiceAccount) and configure it
|
||||
1. Create a [service account](https://developers.google.com/identity/protocols/oauth2/service-account) and configure it
|
||||
to use [Application Default Credentials / Workload Identity / Workload Identity Federation (recommended)](#using-application-default-credentials-adc--workload-identity--workload-identity-federation-recommended) or,
|
||||
alternatively download the JSON.
|
||||
2. Make note of the Client ID for a future step.
|
||||
3. Under "APIs & Auth", choose APIs.
|
||||
4. Click on Admin SDK and then Enable API.
|
||||
5. Follow the steps on https://developers.google.com/admin-sdk/directory/v1/guides/delegation#delegate_domain-wide_authority_to_your_service_account
|
||||
5. Follow the steps on [Set up domain-wide delegation for a service account](https://developers.google.com/workspace/guides/create-credentials#optional_set_up_domain-wide_delegation_for_a_service_account)
|
||||
and give the client id from step 2 the following oauth scopes:
|
||||
|
||||
```
|
||||
https://www.googleapis.com/auth/admin.directory.group.readonly
|
||||
https://www.googleapis.com/auth/admin.directory.user.readonly
|
||||
https://www.googleapis.com/auth/admin.directory.group.member.readonly
|
||||
```
|
||||
|
||||
6. Follow the steps on https://support.google.com/a/answer/60757 to enable Admin API access.
|
||||
|
@ -229,38 +229,79 @@ func (p *GoogleProvider) setGroupRestriction(opts options.GoogleOptions) {
|
||||
}
|
||||
}
|
||||
|
||||
func getAdminService(opts options.GoogleOptions) *admin.Service {
|
||||
ctx := context.Background()
|
||||
var client *http.Client
|
||||
// https://developers.google.com/admin-sdk/directory/reference/rest/v1/members/hasMember#authorization-scopes
|
||||
var possibleScopesList = [...]string{
|
||||
admin.AdminDirectoryGroupMemberReadonlyScope,
|
||||
admin.AdminDirectoryGroupReadonlyScope,
|
||||
admin.AdminDirectoryGroupMemberScope,
|
||||
admin.AdminDirectoryGroupScope,
|
||||
}
|
||||
|
||||
func getOauth2TokenSource(ctx context.Context, opts options.GoogleOptions, scope string) oauth2.TokenSource {
|
||||
if opts.UseApplicationDefaultCredentials {
|
||||
ts, err := impersonate.CredentialsTokenSource(ctx, impersonate.CredentialsConfig{
|
||||
TargetPrincipal: getTargetPrincipal(ctx, opts),
|
||||
Scopes: []string{admin.AdminDirectoryGroupReadonlyScope, admin.AdminDirectoryUserReadonlyScope},
|
||||
Scopes: []string{scope},
|
||||
Subject: opts.AdminEmail,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Fatal("failed to fetch application default credentials: ", err)
|
||||
}
|
||||
client = oauth2.NewClient(ctx, ts)
|
||||
} else {
|
||||
credentialsReader, err := os.Open(opts.ServiceAccountJSON)
|
||||
if err != nil {
|
||||
logger.Fatal("couldn't open Google credentials file: ", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
data, err := io.ReadAll(credentialsReader)
|
||||
if err != nil {
|
||||
logger.Fatal("can't read Google credentials file:", err)
|
||||
}
|
||||
|
||||
conf, err := google.JWTConfigFromJSON(data, admin.AdminDirectoryUserReadonlyScope, admin.AdminDirectoryGroupReadonlyScope)
|
||||
if err != nil {
|
||||
logger.Fatal("can't load Google credentials file:", err)
|
||||
}
|
||||
conf.Subject = opts.AdminEmail
|
||||
client = conf.Client(ctx)
|
||||
return ts
|
||||
}
|
||||
|
||||
credentialsReader, err := os.Open(opts.ServiceAccountJSON)
|
||||
if err != nil {
|
||||
logger.Fatal("couldn't open Google credentials file: ", err)
|
||||
}
|
||||
|
||||
data, err := io.ReadAll(credentialsReader)
|
||||
if err != nil {
|
||||
logger.Fatal("can't read Google credentials file:", err)
|
||||
}
|
||||
|
||||
conf, err := google.JWTConfigFromJSON(data, scope)
|
||||
if err != nil {
|
||||
logger.Fatal("can't load Google credentials file:", err)
|
||||
}
|
||||
|
||||
conf.Subject = opts.AdminEmail
|
||||
return conf.TokenSource(ctx)
|
||||
}
|
||||
|
||||
func getAdminService(opts options.GoogleOptions) *admin.Service {
|
||||
ctx := context.Background()
|
||||
var client *http.Client
|
||||
|
||||
for _, scope := range possibleScopesList {
|
||||
|
||||
ts := getOauth2TokenSource(ctx, opts, scope)
|
||||
_, err := ts.Token()
|
||||
|
||||
if err == nil {
|
||||
client = oauth2.NewClient(ctx, ts)
|
||||
break
|
||||
}
|
||||
|
||||
if retrieveErr, ok := err.(*oauth2.RetrieveError); ok {
|
||||
retrieveErrBody := map[string]interface{}{}
|
||||
|
||||
if err := json.Unmarshal(retrieveErr.Body, &retrieveErrBody); err != nil {
|
||||
logger.Fatal("error unmarshalling retrieveErr body:", err)
|
||||
}
|
||||
|
||||
if retrieveErrBody["error"] == "unauthorized_client" && retrieveErrBody["error_description"] == "Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested." {
|
||||
continue
|
||||
}
|
||||
|
||||
logger.Fatal("error retrieving token:", err)
|
||||
}
|
||||
}
|
||||
|
||||
if client == nil {
|
||||
logger.Fatal("error: google credentials do not have enough permissions to access admin API scope")
|
||||
}
|
||||
|
||||
adminService, err := admin.NewService(ctx, option.WithHTTPClient(client))
|
||||
if err != nil {
|
||||
logger.Fatal(err)
|
||||
|
Reference in New Issue
Block a user