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
|
# Folders
|
||||||
_obj
|
_obj
|
||||||
_test
|
_test
|
||||||
|
.DS_Store
|
||||||
.idea/
|
.idea/
|
||||||
.vscode/*
|
.vscode/*
|
||||||
!/.vscode/tasks.json
|
!/.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)
|
- [#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)
|
- [#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
|
# V7.10.0
|
||||||
|
|
||||||
|
@ -37,18 +37,17 @@ account is still authorized.
|
|||||||
|
|
||||||
#### Restrict auth to specific Google groups on your domain. (optional)
|
#### 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,
|
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.
|
alternatively download the JSON.
|
||||||
2. Make note of the Client ID for a future step.
|
2. Make note of the Client ID for a future step.
|
||||||
3. Under "APIs & Auth", choose APIs.
|
3. Under "APIs & Auth", choose APIs.
|
||||||
4. Click on Admin SDK and then Enable API.
|
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:
|
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.group.member.readonly
|
||||||
https://www.googleapis.com/auth/admin.directory.user.readonly
|
|
||||||
```
|
```
|
||||||
|
|
||||||
6. Follow the steps on https://support.google.com/a/answer/60757 to enable Admin API access.
|
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 {
|
// https://developers.google.com/admin-sdk/directory/reference/rest/v1/members/hasMember#authorization-scopes
|
||||||
ctx := context.Background()
|
var possibleScopesList = [...]string{
|
||||||
var client *http.Client
|
admin.AdminDirectoryGroupMemberReadonlyScope,
|
||||||
|
admin.AdminDirectoryGroupReadonlyScope,
|
||||||
|
admin.AdminDirectoryGroupMemberScope,
|
||||||
|
admin.AdminDirectoryGroupScope,
|
||||||
|
}
|
||||||
|
|
||||||
|
func getOauth2TokenSource(ctx context.Context, opts options.GoogleOptions, scope string) oauth2.TokenSource {
|
||||||
if opts.UseApplicationDefaultCredentials {
|
if opts.UseApplicationDefaultCredentials {
|
||||||
ts, err := impersonate.CredentialsTokenSource(ctx, impersonate.CredentialsConfig{
|
ts, err := impersonate.CredentialsTokenSource(ctx, impersonate.CredentialsConfig{
|
||||||
TargetPrincipal: getTargetPrincipal(ctx, opts),
|
TargetPrincipal: getTargetPrincipal(ctx, opts),
|
||||||
Scopes: []string{admin.AdminDirectoryGroupReadonlyScope, admin.AdminDirectoryUserReadonlyScope},
|
Scopes: []string{scope},
|
||||||
Subject: opts.AdminEmail,
|
Subject: opts.AdminEmail,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatal("failed to fetch application default credentials: ", err)
|
logger.Fatal("failed to fetch application default credentials: ", err)
|
||||||
}
|
}
|
||||||
client = oauth2.NewClient(ctx, ts)
|
return 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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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))
|
adminService, err := admin.NewService(ctx, option.WithHTTPClient(client))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatal(err)
|
logger.Fatal(err)
|
||||||
|
Reference in New Issue
Block a user