feat(entra): add Workload Identity support for Entra ID (#2902)
This commit is contained in:
		
							parent
							
								
									60570cc60e
								
							
						
					
					
						commit
						ae8fb08a89
					
				|  | @ -15,6 +15,7 @@ | ||||||
| - [#2821](https://github.com/oauth2-proxy/oauth2-proxy/pull/2821) feat: add CF-Connecting-IP as supported real ip header (@ondrejsika) | - [#2821](https://github.com/oauth2-proxy/oauth2-proxy/pull/2821) feat: add CF-Connecting-IP as supported real ip header (@ondrejsika) | ||||||
| - [#2620](https://github.com/oauth2-proxy/oauth2-proxy/pull/2620) fix: update code_verifier to use recommended method (@vishvananda) | - [#2620](https://github.com/oauth2-proxy/oauth2-proxy/pull/2620) fix: update code_verifier to use recommended method (@vishvananda) | ||||||
| - [#2392](https://github.com/oauth2-proxy/oauth2-proxy/pull/2392) chore: extend test cases for oidc provider and documentation regarding implicit setting of the groups scope when no scope was specified in the config (@jjlakis / @tuunit) | - [#2392](https://github.com/oauth2-proxy/oauth2-proxy/pull/2392) chore: extend test cases for oidc provider and documentation regarding implicit setting of the groups scope when no scope was specified in the config (@jjlakis / @tuunit) | ||||||
|  | - [#2902](https://github.com/oauth2-proxy/oauth2-proxy/pull/2902) feat(entra): add Workload Identity support for Entra ID (@jjlakis) | ||||||
| 
 | 
 | ||||||
| # V7.7.1 | # V7.7.1 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -394,6 +394,7 @@ character. | ||||||
| | Field | Type | Description | | | Field | Type | Description | | ||||||
| | ----- | ---- | ----------- | | | ----- | ---- | ----------- | | ||||||
| | `allowedTenants` | _[]string_ | AllowedTenants is a list of allowed tenants. In case of multi-tenant apps, incoming tokens are<br/>issued by different issuers and OIDC issuer verification needs to be disabled.<br/>When not specified, all tenants are allowed. Redundant for single-tenant apps<br/>(regular ID token validation matches the issuer). | | | `allowedTenants` | _[]string_ | AllowedTenants is a list of allowed tenants. In case of multi-tenant apps, incoming tokens are<br/>issued by different issuers and OIDC issuer verification needs to be disabled.<br/>When not specified, all tenants are allowed. Redundant for single-tenant apps<br/>(regular ID token validation matches the issuer). | | ||||||
|  | | `federatedTokenAuth` | _bool_ | FederatedTokenAuth enable oAuth2 client authentication with federated token projected<br/>by Entra Workload Identity plugin, instead of client secret. | | ||||||
| 
 | 
 | ||||||
| ### OIDCOptions | ### OIDCOptions | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -12,6 +12,7 @@ The provider is OIDC-compliant, so all the OIDC parameters are honored. Addition | ||||||
| | Flag                        | Toml Field                 | Type           | Description                                                                                                                                                                                                                                                                               | Default | | | Flag                        | Toml Field                 | Type           | Description                                                                                                                                                                                                                                                                               | Default | | ||||||
| | --------------------------- | -------------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | | | --------------------------- | -------------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | | ||||||
| | `--entra-id-allowed-tenant` | `entra_id_allowed_tenants` | string \| list | List of allowed tenants. In case of multi-tenant apps, incoming tokens are issued by different issuers and OIDC issuer verification needs to be disabled. When not specified, all tenants are allowed. Redundant for single-tenant apps (regular ID token validation matches the issuer). |         | | | `--entra-id-allowed-tenant` | `entra_id_allowed_tenants` | string \| list | List of allowed tenants. In case of multi-tenant apps, incoming tokens are issued by different issuers and OIDC issuer verification needs to be disabled. When not specified, all tenants are allowed. Redundant for single-tenant apps (regular ID token validation matches the issuer). |         | | ||||||
|  | | `--entra-id-federated-token-auth` | `entra_id_federated_token_auth` | boolean | Enable oAuth2 client authentication with federated token projected by Entra Workload Identity plugin, instead of client secret.   | false | | ||||||
| 
 | 
 | ||||||
| ## Configure App registration | ## Configure App registration | ||||||
| To begin, create an App registration, set a redirect URI, and generate a secret. All account types are supported, including single-tenant, multi-tenant, multi-tenant with Microsoft accounts, and Microsoft accounts only. | To begin, create an App registration, set a redirect URI, and generate a secret. All account types are supported, including single-tenant, multi-tenant, multi-tenant with Microsoft accounts, and Microsoft accounts only. | ||||||
|  | @ -115,6 +116,34 @@ insecure_oidc_skip_issuer_verification=true | ||||||
| 
 | 
 | ||||||
| To provide additional security, Entra ID provider performs check on the ID token's `issuer` claim to match the `https://login.microsoftonline.com/{tenant-id}/v2.0` template. | To provide additional security, Entra ID provider performs check on the ID token's `issuer` claim to match the `https://login.microsoftonline.com/{tenant-id}/v2.0` template. | ||||||
| 
 | 
 | ||||||
|  | ### Workload Identity | ||||||
|  | Provider supports authentication with federated token, without need of using client secret. Following conditions have to be met: | ||||||
|  | 
 | ||||||
|  | * Cluster has public OIDC provider URL. For major cloud providers, it can be enabled with a single flag, for example for [Azure Kubernetes Service deployed with Terraform](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/kubernetes_cluster), it's `oidc_issuer_enabled`. | ||||||
|  | * Workload Identity admission webhook is deployed on the cluster. For AKS, it can be enabled with a flag (`workload_identity_enabled` in Terraform resource), for clusters outside of Azure, it can be installed from [helm chart](https://github.com/Azure/azure-workload-identity). | ||||||
|  | * Appropriate federated credential is added to application registration. | ||||||
|  | <details> | ||||||
|  |     <summary>See federated credential terraform example</summary> | ||||||
|  | ``` | ||||||
|  |     resource "azuread_application_federated_identity_credential" "fedcred" { | ||||||
|  |         application_id = azuread_application.application.id # ID of your application | ||||||
|  |         display_name   = "federation-cred" | ||||||
|  |         description    = "Workload identity for oauth2-proxy" | ||||||
|  |         audiences      = ["api://AzureADTokenExchange"] # Fixed value | ||||||
|  |         issuer         = "https://cluster-oidc-issuer-url..." | ||||||
|  |         subject        = "system:serviceaccount:oauth2-proxy-namespace-name:oauth2-proxy-sa-name" # set proper NS and SA name | ||||||
|  |     } | ||||||
|  | ``` | ||||||
|  | </details> | ||||||
|  | 
 | ||||||
|  | * Kubernetes service account associated with oauth2-proxy deployment, is annotated with `azure.workload.identity/client-id: <app-registration-client-id>` | ||||||
|  | * oauth2-proxy pod is labeled with `azure.workload.identity/use: "true"` | ||||||
|  | * oauth2-proxy is configured with `entra_id_federated_token_auth` set to `true`. | ||||||
|  | 
 | ||||||
|  | `client_secret` setting can be omitted when using federated token authentication. | ||||||
|  | 
 | ||||||
|  | See: [Azure Workload Identity documentation](https://azure.github.io/azure-workload-identity/docs/). | ||||||
|  | 
 | ||||||
| ### Example configurations | ### Example configurations | ||||||
| Single-tenant app without groups (*groups claim* not enabled). Consider using generic OIDC provider: | Single-tenant app without groups (*groups claim* not enabled). Consider using generic OIDC provider: | ||||||
| ```toml | ```toml | ||||||
|  | @ -145,6 +174,16 @@ scope="openid User.Read" | ||||||
| allowed_groups=["968b4844-d5e7-4e18-a834-59927959369f"] | allowed_groups=["968b4844-d5e7-4e18-a834-59927959369f"] | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
|  | Single-tenant app with more than 200 groups and workload identity enabled: | ||||||
|  | ```toml | ||||||
|  | provider="entra-id" | ||||||
|  | oidc_issuer_url="https://login.microsoftonline.com/<tenant-id>/v2.0" | ||||||
|  | client_id="<client-id>" | ||||||
|  | scope="openid User.Read" | ||||||
|  | allowed_groups=["968b4844-d5e7-4e18-a834-59927959369f"] | ||||||
|  | entra_id_federated_token_auth=true | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
| Multi-tenant app with Microsoft personal accounts & one Entra tenant allowed, with group overage considered: | Multi-tenant app with Microsoft personal accounts & one Entra tenant allowed, with group overage considered: | ||||||
| ```toml | ```toml | ||||||
| provider="entra-id" | provider="entra-id" | ||||||
|  |  | ||||||
|  | @ -489,6 +489,7 @@ type LegacyProvider struct { | ||||||
| 	AzureTenant                            string   `flag:"azure-tenant" cfg:"azure_tenant"` | 	AzureTenant                            string   `flag:"azure-tenant" cfg:"azure_tenant"` | ||||||
| 	AzureGraphGroupField                   string   `flag:"azure-graph-group-field" cfg:"azure_graph_group_field"` | 	AzureGraphGroupField                   string   `flag:"azure-graph-group-field" cfg:"azure_graph_group_field"` | ||||||
| 	EntraIDAllowedTenants                  []string `flag:"entra-id-allowed-tenant" cfg:"entra_id_allowed_tenants"` | 	EntraIDAllowedTenants                  []string `flag:"entra-id-allowed-tenant" cfg:"entra_id_allowed_tenants"` | ||||||
|  | 	EntraIDFederatedTokenAuth              bool     `flag:"entra-id-federated-token-auth" cfg:"entra_id_federated_token_auth"` | ||||||
| 	BitbucketTeam                          string   `flag:"bitbucket-team" cfg:"bitbucket_team"` | 	BitbucketTeam                          string   `flag:"bitbucket-team" cfg:"bitbucket_team"` | ||||||
| 	BitbucketRepository                    string   `flag:"bitbucket-repository" cfg:"bitbucket_repository"` | 	BitbucketRepository                    string   `flag:"bitbucket-repository" cfg:"bitbucket_repository"` | ||||||
| 	GitHubOrg                              string   `flag:"github-org" cfg:"github_org"` | 	GitHubOrg                              string   `flag:"github-org" cfg:"github_org"` | ||||||
|  | @ -552,6 +553,7 @@ func legacyProviderFlagSet() *pflag.FlagSet { | ||||||
| 	flagSet.String("azure-tenant", "common", "go to a tenant-specific or common (tenant-independent) endpoint.") | 	flagSet.String("azure-tenant", "common", "go to a tenant-specific or common (tenant-independent) endpoint.") | ||||||
| 	flagSet.String("azure-graph-group-field", "", "configures the group field to be used when building the groups list(`id` or `displayName`. Default is `id`) from Microsoft Graph(available only for v2.0 oidc url). Based on this value, the `allowed-group` config values should be adjusted accordingly. If using `id` as group field, `allowed-group` should contains groups IDs, if using `displayName` as group field, `allowed-group` should contains groups name") | 	flagSet.String("azure-graph-group-field", "", "configures the group field to be used when building the groups list(`id` or `displayName`. Default is `id`) from Microsoft Graph(available only for v2.0 oidc url). Based on this value, the `allowed-group` config values should be adjusted accordingly. If using `id` as group field, `allowed-group` should contains groups IDs, if using `displayName` as group field, `allowed-group` should contains groups name") | ||||||
| 	flagSet.StringSlice("entra-id-allowed-tenant", []string{}, "list of tenants allowed for MS Entra ID multi-tenant application") | 	flagSet.StringSlice("entra-id-allowed-tenant", []string{}, "list of tenants allowed for MS Entra ID multi-tenant application") | ||||||
|  | 	flagSet.Bool("entra-id-federated-token-auth", false, "enable oAuth client authentication with federated token projected by Azure Workload Identity plugin, instead of client secret.") | ||||||
| 	flagSet.String("bitbucket-team", "", "restrict logins to members of this team") | 	flagSet.String("bitbucket-team", "", "restrict logins to members of this team") | ||||||
| 	flagSet.String("bitbucket-repository", "", "restrict logins to user with access to this repository") | 	flagSet.String("bitbucket-repository", "", "restrict logins to user with access to this repository") | ||||||
| 	flagSet.String("github-org", "", "restrict logins to members of this organisation") | 	flagSet.String("github-org", "", "restrict logins to members of this organisation") | ||||||
|  | @ -760,7 +762,8 @@ func (l *LegacyProvider) convert() (Providers, error) { | ||||||
| 		} | 		} | ||||||
| 	case "entra-id": | 	case "entra-id": | ||||||
| 		provider.MicrosoftEntraIDConfig = MicrosoftEntraIDOptions{ | 		provider.MicrosoftEntraIDConfig = MicrosoftEntraIDOptions{ | ||||||
| 			AllowedTenants: l.EntraIDAllowedTenants, | 			AllowedTenants:     l.EntraIDAllowedTenants, | ||||||
|  | 			FederatedTokenAuth: l.EntraIDFederatedTokenAuth, | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -166,6 +166,10 @@ type MicrosoftEntraIDOptions struct { | ||||||
| 	// When not specified, all tenants are allowed. Redundant for single-tenant apps
 | 	// When not specified, all tenants are allowed. Redundant for single-tenant apps
 | ||||||
| 	// (regular ID token validation matches the issuer).
 | 	// (regular ID token validation matches the issuer).
 | ||||||
| 	AllowedTenants []string `json:"allowedTenants,omitempty"` | 	AllowedTenants []string `json:"allowedTenants,omitempty"` | ||||||
|  | 
 | ||||||
|  | 	// FederatedTokenAuth enable oAuth2 client authentication with federated token projected
 | ||||||
|  | 	// by Entra Workload Identity plugin, instead of client secret.
 | ||||||
|  | 	FederatedTokenAuth bool `json:"federatedTokenAuth,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type ADFSOptions struct { | type ADFSOptions struct { | ||||||
|  |  | ||||||
|  | @ -46,20 +46,47 @@ func validateProvider(provider options.Provider, providerIDs map[string]struct{} | ||||||
| 		msgs = append(msgs, "provider missing setting: client-id") | 		msgs = append(msgs, "provider missing setting: client-id") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// login.gov uses a signed JWT to authenticate, not a client-secret
 | 	if providerRequiresClientSecret(provider) { | ||||||
| 	if provider.Type != "login.gov" { | 		msgs = append(msgs, validateClientSecret(provider)...) | ||||||
| 		if provider.ClientSecret == "" && provider.ClientSecretFile == "" { |  | ||||||
| 			msgs = append(msgs, "missing setting: client-secret or client-secret-file") |  | ||||||
| 		} |  | ||||||
| 		if provider.ClientSecret == "" && provider.ClientSecretFile != "" { |  | ||||||
| 			_, err := os.ReadFile(provider.ClientSecretFile) |  | ||||||
| 			if err != nil { |  | ||||||
| 				msgs = append(msgs, "could not read client secret file: "+provider.ClientSecretFile) |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	msgs = append(msgs, validateGoogleConfig(provider)...) | 	if provider.Type == "google" { | ||||||
|  | 		msgs = append(msgs, validateGoogleConfig(provider)...) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if provider.Type == "entra-id" { | ||||||
|  | 		msgs = append(msgs, validateEntraConfig(provider)...) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return msgs | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // providerRequiresClientSecret checks if provider requires client secret to be set
 | ||||||
|  | // or it can be omitted in favor of JWT token to authenticate oAuth client
 | ||||||
|  | func providerRequiresClientSecret(provider options.Provider) bool { | ||||||
|  | 	if provider.Type == "entra-id" && provider.MicrosoftEntraIDConfig.FederatedTokenAuth { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if provider.Type == "login.gov" { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func validateClientSecret(provider options.Provider) []string { | ||||||
|  | 	msgs := []string{} | ||||||
|  | 
 | ||||||
|  | 	if provider.ClientSecret == "" && provider.ClientSecretFile == "" { | ||||||
|  | 		msgs = append(msgs, "missing setting: client-secret or client-secret-file") | ||||||
|  | 	} | ||||||
|  | 	if provider.ClientSecret == "" && provider.ClientSecretFile != "" { | ||||||
|  | 		_, err := os.ReadFile(provider.ClientSecretFile) | ||||||
|  | 		if err != nil { | ||||||
|  | 			msgs = append(msgs, "could not read client secret file: "+provider.ClientSecretFile) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return msgs | 	return msgs | ||||||
| } | } | ||||||
|  | @ -96,3 +123,23 @@ func validateGoogleConfig(provider options.Provider) []string { | ||||||
| 
 | 
 | ||||||
| 	return msgs | 	return msgs | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func validateEntraConfig(provider options.Provider) []string { | ||||||
|  | 	msgs := []string{} | ||||||
|  | 
 | ||||||
|  | 	if provider.MicrosoftEntraIDConfig.FederatedTokenAuth { | ||||||
|  | 		federatedTokenPath := os.Getenv("AZURE_FEDERATED_TOKEN_FILE") | ||||||
|  | 
 | ||||||
|  | 		if federatedTokenPath == "" { | ||||||
|  | 			msgs = append(msgs, "entra federated token authentication is enabled, but AZURE_FEDERATED_TOKEN_FILE variable is not set, check your workload identity configuration.") | ||||||
|  | 			return msgs | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		_, err := os.ReadFile(federatedTokenPath) | ||||||
|  | 		if err != nil { | ||||||
|  | 			msgs = append(msgs, "could not read entra federated token file") | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return msgs | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -1,9 +1,12 @@ | ||||||
| package providers | package providers | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"bytes" | ||||||
| 	"context" | 	"context" | ||||||
|  | 	"encoding/json" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"net/url" | 	"net/url" | ||||||
|  | 	"os" | ||||||
| 	"regexp" | 	"regexp" | ||||||
| 
 | 
 | ||||||
| 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options" | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options" | ||||||
|  | @ -12,12 +15,14 @@ import ( | ||||||
| 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests" | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests" | ||||||
| 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util" | 	"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util" | ||||||
| 	"github.com/spf13/cast" | 	"github.com/spf13/cast" | ||||||
|  | 	"golang.org/x/oauth2" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // MicrosoftEntraIDProvider represents provider for Azure Entra Authentication V2 endpoint
 | // MicrosoftEntraIDProvider represents provider for Azure Entra Authentication V2 endpoint
 | ||||||
| type MicrosoftEntraIDProvider struct { | type MicrosoftEntraIDProvider struct { | ||||||
| 	*OIDCProvider | 	*OIDCProvider | ||||||
| 	multiTenantAllowedTenants []string | 	multiTenantAllowedTenants []string | ||||||
|  | 	federatedTokenAuth        bool | ||||||
| 
 | 
 | ||||||
| 	microsoftGraphURL *url.URL | 	microsoftGraphURL *url.URL | ||||||
| } | } | ||||||
|  | @ -44,6 +49,7 @@ func NewMicrosoftEntraIDProvider(p *ProviderData, opts options.Provider) *Micros | ||||||
| 		OIDCProvider: NewOIDCProvider(p, opts.OIDCConfig), | 		OIDCProvider: NewOIDCProvider(p, opts.OIDCConfig), | ||||||
| 
 | 
 | ||||||
| 		multiTenantAllowedTenants: opts.MicrosoftEntraIDConfig.AllowedTenants, | 		multiTenantAllowedTenants: opts.MicrosoftEntraIDConfig.AllowedTenants, | ||||||
|  | 		federatedTokenAuth:        opts.MicrosoftEntraIDConfig.FederatedTokenAuth, | ||||||
| 		microsoftGraphURL:         microsoftGraphURL, | 		microsoftGraphURL:         microsoftGraphURL, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -89,6 +95,61 @@ func (p *MicrosoftEntraIDProvider) ValidateSession(ctx context.Context, session | ||||||
| 	return p.OIDCProvider.ValidateSession(ctx, session) | 	return p.OIDCProvider.ValidateSession(ctx, session) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // Redeem exchanges the OAuth2 authentication token for an ID token, considering federated token authentication
 | ||||||
|  | func (p *MicrosoftEntraIDProvider) Redeem(ctx context.Context, redirectURL, code, codeVerifier string) (*sessions.SessionState, error) { | ||||||
|  | 	if p.federatedTokenAuth { | ||||||
|  | 		return p.redeemWithFederatedToken(ctx, redirectURL, code, codeVerifier) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return p.OIDCProvider.Redeem(ctx, redirectURL, code, codeVerifier) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // redeemWithFederatedToken performs custom token exchange with federated token instead of client secret
 | ||||||
|  | func (p *MicrosoftEntraIDProvider) redeemWithFederatedToken(ctx context.Context, redirectURL, code, codeVerifier string) (*sessions.SessionState, error) { | ||||||
|  | 	federatedTokenPath := os.Getenv("AZURE_FEDERATED_TOKEN_FILE") | ||||||
|  | 	federatedToken, err := os.ReadFile(federatedTokenPath) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, fmt.Errorf("error reading federated token file %s: %s", federatedTokenPath, err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	params := url.Values{} | ||||||
|  | 
 | ||||||
|  | 	// create custom exchange parameters
 | ||||||
|  | 	if codeVerifier != "" { | ||||||
|  | 		params.Add("code_verifier", codeVerifier) | ||||||
|  | 	} | ||||||
|  | 	params.Add("redirect_uri", redirectURL) | ||||||
|  | 	params.Add("client_id", p.ClientID) | ||||||
|  | 	params.Add("client_assertion", string(federatedToken)) | ||||||
|  | 	params.Add("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer") | ||||||
|  | 	params.Add("code", code) | ||||||
|  | 	params.Add("grant_type", "authorization_code") | ||||||
|  | 
 | ||||||
|  | 	// perform exchange
 | ||||||
|  | 	resp := requests.New(p.RedeemURL.String()). | ||||||
|  | 		WithContext(ctx). | ||||||
|  | 		WithMethod("POST"). | ||||||
|  | 		WithBody(bytes.NewBufferString(params.Encode())). | ||||||
|  | 		SetHeader("Content-Type", "application/x-www-form-urlencoded"). | ||||||
|  | 		Do() | ||||||
|  | 
 | ||||||
|  | 	// prepare token of type *oauth2.Token
 | ||||||
|  | 	var token *oauth2.Token | ||||||
|  | 	var rawResponse interface{} | ||||||
|  | 
 | ||||||
|  | 	body := resp.Body() | ||||||
|  | 	if err := json.Unmarshal(body, &rawResponse); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if err := json.Unmarshal(body, &token); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// create session using new token and generic OIDC provider
 | ||||||
|  | 	return p.OIDCProvider.createSession(ctx, token.WithExtra(rawResponse), false) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // checkGroupOverage checks ID token's group membership claims for the group overage
 | // checkGroupOverage checks ID token's group membership claims for the group overage
 | ||||||
| func (p *MicrosoftEntraIDProvider) checkGroupOverage(session *sessions.SessionState) (bool, error) { | func (p *MicrosoftEntraIDProvider) checkGroupOverage(session *sessions.SessionState) (bool, error) { | ||||||
| 	extractor, err := p.getClaimExtractor(session.IDToken, session.AccessToken) | 	extractor, err := p.getClaimExtractor(session.IDToken, session.AccessToken) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue