feat: added organizationId/employee id as preferred username
Signed-off-by: Drew Foehn <drew@pixelburn.net>
This commit is contained in:
		
							parent
							
								
									9168731c7a
								
							
						
					
					
						commit
						1a32885dcf
					
				| 
						 | 
					@ -8,6 +8,8 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Changes since v7.12.0
 | 
					## Changes since v7.12.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- [3237](https://github.com/oauth2-proxy/oauth2-proxy/pull/3237) - Option to use organization id for preferred username in Google Provider
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# V7.12.0
 | 
					# V7.12.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Release Highlights
 | 
					## Release Highlights
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,13 +5,15 @@ title: Google (default)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Config Options
 | 
					## Config Options
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| Flag                                           | Toml Field                                   | Type   | Description                                                                                      | Default                                            |
 | 
					| Flag                                            | Toml Field                                   | Type   | Description                                                                                                                                                                                 | Default                                             |
 | 
				
			||||||
| ---------------------------------------------- | -------------------------------------------- | ------ | ------------------------------------------------------------------------------------------------ | -------------------------------------------------- |
 | 
					|-------------------------------------------------|----------------------------------------------| ------ |---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------|
 | 
				
			||||||
| `--google-admin-email`                         | `google_admin_email`                         | string | the google admin to impersonate for api calls                                                    |                                                    |
 | 
					| `--google-admin-email`                          | `google_admin_email`                         | string | the google admin to impersonate for api calls                                                                                                                                               |                                                     |
 | 
				
			||||||
| `--google-group`                               | `google_groups`                              | string | restrict logins to members of this google group (may be given multiple times). If not specified and service account or default credentials are configured, all user groups will be allowed.                   |                                                    |
 | 
					| `--google-group`                                | `google_groups`                              | string | restrict logins to members of this google group (may be given multiple times). If not specified and service account or default credentials are configured, all user groups will be allowed. |                                                     |
 | 
				
			||||||
| `--google-service-account-json`                | `google_service_account_json`                | string | the path to the service account json credentials                                                 |                                                    |
 | 
					| `--google-service-account-json`                 | `google_service_account_json`                | string | the path to the service account json credentials                                                                                                                                            |                                                     |
 | 
				
			||||||
| `--google-use-application-default-credentials` | `google_use_application_default_credentials` | bool   | use application default credentials instead of service account json (i.e. GKE Workload Identity) |                                                    |
 | 
					| `--google-use-application-default-credentials`  | `google_use_application_default_credentials` | bool   | use application default credentials instead of service account json (i.e. GKE Workload Identity)                                                                                            |                                                     |
 | 
				
			||||||
| `--google-target-principal`                    | `google_target_principal`                    | bool   | the target principal to impersonate when using ADC                                               | defaults to the service account configured for ADC |
 | 
					| `--google-target-principal`                     | `google_target_principal`                    | bool   | the target principal to impersonate when using ADC                                                                                                                                          | defaults to the service account configured for ADC  |
 | 
				
			||||||
 | 
					| `--google-use-organization-id`                  | `google_use_organization_id`                 | bool   | use organization id as preferred username                                                                                                                                                   | false                                               |
 | 
				
			||||||
 | 
					| `--google-admin-api-user-scope`                 | `google_admin_api_user_scope`                | string | the OAuth scope to use when querying the Google Admin SDK for organization id, can be 'readonly', 'user' or 'cloud'<br/>                                                                    | `readonly`                                          |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Usage
 | 
					## Usage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -73,3 +75,10 @@ can be leveraged through a feature called Workload Identity. Follow Google's [gu
 | 
				
			||||||
to set up Workload Identity.
 | 
					to set up Workload Identity.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
When deployed outside of GCP, [Workload Identity Federation](https://cloud.google.com/docs/authentication/provide-credentials-adc#wlif) might be an option.
 | 
					When deployed outside of GCP, [Workload Identity Federation](https://cloud.google.com/docs/authentication/provide-credentials-adc#wlif) might be an option.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##### Using Organization ID as Preferred Username (optional)
 | 
				
			||||||
 | 
					By default, the google provider uses the google id as username. If you would like to use an organization id instead, you can set the `google-use-organization-id` flag to true.
 | 
				
			||||||
 | 
					This requires that the service account used to query the Google Admin SDK has one of the following scopes granted in step 5 above: 
 | 
				
			||||||
 | 
					- `https://www.googleapis.com/auth/admin.directory.user.readonly`, 
 | 
				
			||||||
 | 
					- `https://www.googleapis.com/auth/admin.directory.user` 
 | 
				
			||||||
 | 
					- `https://www.googleapis.com/auth/cloud-platform` 
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -510,6 +510,8 @@ type LegacyProvider struct {
 | 
				
			||||||
	GoogleServiceAccountJSON               string   `flag:"google-service-account-json" cfg:"google_service_account_json"`
 | 
						GoogleServiceAccountJSON               string   `flag:"google-service-account-json" cfg:"google_service_account_json"`
 | 
				
			||||||
	GoogleUseApplicationDefaultCredentials bool     `flag:"google-use-application-default-credentials" cfg:"google_use_application_default_credentials"`
 | 
						GoogleUseApplicationDefaultCredentials bool     `flag:"google-use-application-default-credentials" cfg:"google_use_application_default_credentials"`
 | 
				
			||||||
	GoogleTargetPrincipal                  string   `flag:"google-target-principal" cfg:"google_target_principal"`
 | 
						GoogleTargetPrincipal                  string   `flag:"google-target-principal" cfg:"google_target_principal"`
 | 
				
			||||||
 | 
						GoogleUseOrganizationId                bool     `flag:"google-use-organization-id" cfg:"google_use_organization_id"`
 | 
				
			||||||
 | 
						GoogleAdminApiUserScope                string   `flag:"google-admin-api-user-scope" cfg:"google_admin_api_user_scope"`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// These options allow for other providers besides Google, with
 | 
						// These options allow for other providers besides Google, with
 | 
				
			||||||
	// potential overrides.
 | 
						// potential overrides.
 | 
				
			||||||
| 
						 | 
					@ -623,6 +625,8 @@ func legacyGoogleFlagSet() *pflag.FlagSet {
 | 
				
			||||||
	flagSet.String("google-service-account-json", "", "the path to the service account json credentials")
 | 
						flagSet.String("google-service-account-json", "", "the path to the service account json credentials")
 | 
				
			||||||
	flagSet.String("google-use-application-default-credentials", "", "use application default credentials instead of service account json (i.e. GKE Workload Identity)")
 | 
						flagSet.String("google-use-application-default-credentials", "", "use application default credentials instead of service account json (i.e. GKE Workload Identity)")
 | 
				
			||||||
	flagSet.String("google-target-principal", "", "the target principal to impersonate when using ADC")
 | 
						flagSet.String("google-target-principal", "", "the target principal to impersonate when using ADC")
 | 
				
			||||||
 | 
						flagSet.String("google-use-organization-id", "", "use organization id as preferred username")
 | 
				
			||||||
 | 
						flagSet.String("google-admin-api-user-scope", "", "authorization scope required to call users.get, can be one of ")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return flagSet
 | 
						return flagSet
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -770,6 +774,8 @@ func (l *LegacyProvider) convert() (Providers, error) {
 | 
				
			||||||
			ServiceAccountJSON:               l.GoogleServiceAccountJSON,
 | 
								ServiceAccountJSON:               l.GoogleServiceAccountJSON,
 | 
				
			||||||
			UseApplicationDefaultCredentials: l.GoogleUseApplicationDefaultCredentials,
 | 
								UseApplicationDefaultCredentials: l.GoogleUseApplicationDefaultCredentials,
 | 
				
			||||||
			TargetPrincipal:                  l.GoogleTargetPrincipal,
 | 
								TargetPrincipal:                  l.GoogleTargetPrincipal,
 | 
				
			||||||
 | 
								UseOrganizationId:                l.GoogleUseOrganizationId,
 | 
				
			||||||
 | 
								AdminApiUserScope:                l.GoogleAdminApiUserScope,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case "entra-id":
 | 
						case "entra-id":
 | 
				
			||||||
		provider.MicrosoftEntraIDConfig = MicrosoftEntraIDOptions{
 | 
							provider.MicrosoftEntraIDConfig = MicrosoftEntraIDOptions{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -230,6 +230,10 @@ type GoogleOptions struct {
 | 
				
			||||||
	UseApplicationDefaultCredentials bool `json:"useApplicationDefaultCredentials,omitempty"`
 | 
						UseApplicationDefaultCredentials bool `json:"useApplicationDefaultCredentials,omitempty"`
 | 
				
			||||||
	// TargetPrincipal is the Google Service Account used for Application Default Credentials
 | 
						// TargetPrincipal is the Google Service Account used for Application Default Credentials
 | 
				
			||||||
	TargetPrincipal string `json:"targetPrincipal,omitempty"`
 | 
						TargetPrincipal string `json:"targetPrincipal,omitempty"`
 | 
				
			||||||
 | 
						// UseOrganizationId indicates whether to use the organization ID as the UserName claim
 | 
				
			||||||
 | 
						UseOrganizationId bool `json:"useOrganizationId,omitempty"`
 | 
				
			||||||
 | 
						// user scope needed for fetching user organization information from admin api, can be one of cloud user or readonly
 | 
				
			||||||
 | 
						AdminApiUserScope string `json:"adminApiUserScope,omitempty"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type OIDCOptions struct {
 | 
					type OIDCOptions struct {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,6 +40,8 @@ type GoogleProvider struct {
 | 
				
			||||||
	// Refresh. `Authorize` uses the results of this saved in `session.Groups`
 | 
						// Refresh. `Authorize` uses the results of this saved in `session.Groups`
 | 
				
			||||||
	// Since it is called on every request.
 | 
						// Since it is called on every request.
 | 
				
			||||||
	groupValidator func(*sessions.SessionState) bool
 | 
						groupValidator func(*sessions.SessionState) bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						setPreferredUsername func(s *sessions.SessionState) error
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var _ Provider = (*GoogleProvider)(nil)
 | 
					var _ Provider = (*GoogleProvider)(nil)
 | 
				
			||||||
| 
						 | 
					@ -100,15 +102,46 @@ func NewGoogleProvider(p *ProviderData, opts options.GoogleOptions) (*GoogleProv
 | 
				
			||||||
		groupValidator: func(*sessions.SessionState) bool {
 | 
							groupValidator: func(*sessions.SessionState) bool {
 | 
				
			||||||
			return true
 | 
								return true
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							setPreferredUsername: func(state *sessions.SessionState) error {
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if opts.ServiceAccountJSON != "" || opts.UseApplicationDefaultCredentials {
 | 
						if opts.ServiceAccountJSON != "" || opts.UseApplicationDefaultCredentials {
 | 
				
			||||||
		provider.configureGroups(opts)
 | 
							provider.configureGroups(opts)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if opts.UseOrganizationId {
 | 
				
			||||||
 | 
							userScope := getAdminApiUserScope(opts.AdminApiUserScope)
 | 
				
			||||||
 | 
							for index, scope := range possibleScopesList {
 | 
				
			||||||
 | 
								possibleScopesList[index] = scope + " " + userScope
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							adminService := getAdminService(opts)
 | 
				
			||||||
 | 
							provider.setPreferredUsername = func(s *sessions.SessionState) error {
 | 
				
			||||||
 | 
								userName, err := getUserInfo(adminService, s.Email)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								s.PreferredUsername = userName
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return provider, nil
 | 
						return provider, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// by default can be readonly user scope
 | 
				
			||||||
 | 
					func getAdminApiUserScope(adminApiUserScope string) string {
 | 
				
			||||||
 | 
						switch adminApiUserScope {
 | 
				
			||||||
 | 
						case "cloud":
 | 
				
			||||||
 | 
							return admin.CloudPlatformScope
 | 
				
			||||||
 | 
						case "user":
 | 
				
			||||||
 | 
							return admin.AdminDirectoryUserScope
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return admin.AdminDirectoryUserReadonlyScope
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (p *GoogleProvider) configureGroups(opts options.GoogleOptions) {
 | 
					func (p *GoogleProvider) configureGroups(opts options.GoogleOptions) {
 | 
				
			||||||
	adminService := getAdminService(opts)
 | 
						adminService := getAdminService(opts)
 | 
				
			||||||
	// Backwards compatibility with `--google-group` option
 | 
						// Backwards compatibility with `--google-group` option
 | 
				
			||||||
| 
						 | 
					@ -204,6 +237,7 @@ func (p *GoogleProvider) Redeem(ctx context.Context, redirectURL, code, codeVeri
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// EnrichSession checks the listed Google Groups configured and adds any
 | 
					// EnrichSession checks the listed Google Groups configured and adds any
 | 
				
			||||||
// that the user is a member of to session.Groups.
 | 
					// that the user is a member of to session.Groups.
 | 
				
			||||||
 | 
					// if preferred username is configured to be organization ID, it sets that as well.
 | 
				
			||||||
func (p *GoogleProvider) EnrichSession(_ context.Context, s *sessions.SessionState) error {
 | 
					func (p *GoogleProvider) EnrichSession(_ context.Context, s *sessions.SessionState) error {
 | 
				
			||||||
	// TODO (@NickMeves) - Move to pure EnrichSession logic and stop
 | 
						// TODO (@NickMeves) - Move to pure EnrichSession logic and stop
 | 
				
			||||||
	// reusing legacy `groupValidator`.
 | 
						// reusing legacy `groupValidator`.
 | 
				
			||||||
| 
						 | 
					@ -212,7 +246,7 @@ func (p *GoogleProvider) EnrichSession(_ context.Context, s *sessions.SessionSta
 | 
				
			||||||
	// populating logic.
 | 
						// populating logic.
 | 
				
			||||||
	p.groupValidator(s)
 | 
						p.groupValidator(s)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return p.setPreferredUsername(s)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SetGroupRestriction configures the GoogleProvider to restrict access to the
 | 
					// SetGroupRestriction configures the GoogleProvider to restrict access to the
 | 
				
			||||||
| 
						 | 
					@ -251,7 +285,8 @@ func (p *GoogleProvider) populateAllGroups(adminService *admin.Service) func(s *
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// https://developers.google.com/admin-sdk/directory/reference/rest/v1/members/hasMember#authorization-scopes
 | 
					// https://developers.google.com/admin-sdk/directory/reference/rest/v1/members/hasMember#authorization-scopes
 | 
				
			||||||
var possibleScopesList = [...]string{
 | 
					var possibleScopesList = []string{
 | 
				
			||||||
 | 
						admin.AdminDirectoryGroupMemberReadonlyScope, // least permissive combination
 | 
				
			||||||
	admin.AdminDirectoryGroupMemberReadonlyScope,
 | 
						admin.AdminDirectoryGroupMemberReadonlyScope,
 | 
				
			||||||
	admin.AdminDirectoryGroupReadonlyScope,
 | 
						admin.AdminDirectoryGroupReadonlyScope,
 | 
				
			||||||
	admin.AdminDirectoryGroupMemberScope,
 | 
						admin.AdminDirectoryGroupMemberScope,
 | 
				
			||||||
| 
						 | 
					@ -262,7 +297,7 @@ func getOauth2TokenSource(ctx context.Context, opts options.GoogleOptions, scope
 | 
				
			||||||
	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{scope},
 | 
								Scopes:          strings.Split(scope, " "),
 | 
				
			||||||
			Subject:         opts.AdminEmail,
 | 
								Subject:         opts.AdminEmail,
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
| 
						 | 
					@ -364,6 +399,30 @@ func getTargetPrincipal(ctx context.Context, opts options.GoogleOptions) (target
 | 
				
			||||||
	return targetPrincipal
 | 
						return targetPrincipal
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getUserInfo(service *admin.Service, email string) (string, error) {
 | 
				
			||||||
 | 
						req := service.Users.Get(email)
 | 
				
			||||||
 | 
						user, err := req.Do()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return "", fmt.Errorf("failed to get user details for %s: %v", email, err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ext, _ := user.ExternalIds.([]interface{})
 | 
				
			||||||
 | 
						for _, v := range ext {
 | 
				
			||||||
 | 
							m, _ := v.(map[string]interface{})
 | 
				
			||||||
 | 
							if m == nil {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if t, _ := m["type"].(string); t != "organization" {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if val, _ := m["value"].(string); val != "" {
 | 
				
			||||||
 | 
								return val, nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return "", fmt.Errorf("failed to get organization id for %s", email)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// getUserGroups retrieves all groups that a user is a member of using the Google Admin Directory API
 | 
					// getUserGroups retrieves all groups that a user is a member of using the Google Admin Directory API
 | 
				
			||||||
func getUserGroups(service *admin.Service, email string) ([]string, error) {
 | 
					func getUserGroups(service *admin.Service, email string) ([]string, error) {
 | 
				
			||||||
	var allGroups []string
 | 
						var allGroups []string
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -325,3 +325,83 @@ func TestGoogleProvider_getUserGroups(t *testing.T) {
 | 
				
			||||||
	assert.NoError(t, err)
 | 
						assert.NoError(t, err)
 | 
				
			||||||
	assert.Equal(t, []string{"group1@example.com", "group2@example.com"}, groups)
 | 
						assert.Equal(t, []string{"group1@example.com", "group2@example.com"}, groups)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestGoogleProvider_getUserInfo(t *testing.T) {
 | 
				
			||||||
 | 
						ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
 | 
							if r.URL.Path == "/admin/directory/v1/users/test@example.com" {
 | 
				
			||||||
 | 
								response := `{
 | 
				
			||||||
 | 
								  "kind": "admin#directory#user",
 | 
				
			||||||
 | 
								  "id": "",
 | 
				
			||||||
 | 
								  "etag": "\"\"",
 | 
				
			||||||
 | 
								  "primaryEmail": "test@example.com",
 | 
				
			||||||
 | 
								  "name": {
 | 
				
			||||||
 | 
									"givenName": "Test",
 | 
				
			||||||
 | 
									"familyName": "User",
 | 
				
			||||||
 | 
									"fullName": "Test User"
 | 
				
			||||||
 | 
								  },
 | 
				
			||||||
 | 
								  "isAdmin": false,
 | 
				
			||||||
 | 
								  "isDelegatedAdmin": false,
 | 
				
			||||||
 | 
								  "lastLoginTime": "",
 | 
				
			||||||
 | 
								  "creationTime": "",
 | 
				
			||||||
 | 
								  "agreedToTerms": true,
 | 
				
			||||||
 | 
								  "suspended": false,
 | 
				
			||||||
 | 
								  "archived": false,
 | 
				
			||||||
 | 
								  "changePasswordAtNextLogin": false,
 | 
				
			||||||
 | 
								  "ipWhitelisted": false,
 | 
				
			||||||
 | 
								  "emails": [
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
									  "address": "test@example.com",
 | 
				
			||||||
 | 
									  "primary": true
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								  ],
 | 
				
			||||||
 | 
								  "externalIds": [
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
									  "value": "test.user",
 | 
				
			||||||
 | 
									  "type": "organization"
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								  ],
 | 
				
			||||||
 | 
								  "organizations": [
 | 
				
			||||||
 | 
								  ],
 | 
				
			||||||
 | 
								  "phones": [
 | 
				
			||||||
 | 
								  ],
 | 
				
			||||||
 | 
								  "languages": [
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
									  "languageCode": "en",
 | 
				
			||||||
 | 
									  "preference": "preferred"
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								  ],
 | 
				
			||||||
 | 
								  "aliases": [
 | 
				
			||||||
 | 
									"test.user@example.com"
 | 
				
			||||||
 | 
								  ],
 | 
				
			||||||
 | 
								  "nonEditableAliases": [
 | 
				
			||||||
 | 
									"test.user@example.com"
 | 
				
			||||||
 | 
								  ],
 | 
				
			||||||
 | 
								  "gender": {
 | 
				
			||||||
 | 
									"type": "male"
 | 
				
			||||||
 | 
								  },
 | 
				
			||||||
 | 
								  "customerId": "",
 | 
				
			||||||
 | 
								  "orgUnitPath": "/",
 | 
				
			||||||
 | 
								  "isMailboxSetup": true,
 | 
				
			||||||
 | 
								  "isEnrolledIn2Sv": true,
 | 
				
			||||||
 | 
								  "isEnforcedIn2Sv": false,
 | 
				
			||||||
 | 
								  "includeInGlobalAddressList": true,
 | 
				
			||||||
 | 
								  "thumbnailPhotoUrl": "",
 | 
				
			||||||
 | 
								  "thumbnailPhotoEtag": "\"\"",
 | 
				
			||||||
 | 
								  "recoveryEmail": "test.user@gmail.com",
 | 
				
			||||||
 | 
								  "recoveryPhone": "+55555555555"
 | 
				
			||||||
 | 
								}`
 | 
				
			||||||
 | 
								fmt.Fprintln(w, response)
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								http.NotFound(w, r)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}))
 | 
				
			||||||
 | 
						defer ts.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						client := &http.Client{}
 | 
				
			||||||
 | 
						adminService, err := admin.NewService(context.Background(), option.WithHTTPClient(client), option.WithEndpoint(ts.URL))
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						info, err := getUserInfo(adminService, "test@example.com")
 | 
				
			||||||
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
						assert.Equal(t, "test.user", info)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue