mirror of
https://github.com/distribution/distribution.git
synced 2025-11-03 11:19:37 +00:00
bump azure sdk
v1.3.0 of azidentity introduces support to workload identity. Signed-off-by: Flavian Missi <fmissi@redhat.com>
This commit is contained in:
33
vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/cache/cache.go
generated
vendored
33
vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/cache/cache.go
generated
vendored
@@ -11,6 +11,8 @@ implementers on the format being passed.
|
||||
*/
|
||||
package cache
|
||||
|
||||
import "context"
|
||||
|
||||
// Marshaler marshals data from an internal cache to bytes that can be stored.
|
||||
type Marshaler interface {
|
||||
Marshal() ([]byte, error)
|
||||
@@ -27,13 +29,26 @@ type Serializer interface {
|
||||
Unmarshaler
|
||||
}
|
||||
|
||||
// ExportReplace is used export or replace what is in the cache.
|
||||
type ExportReplace interface {
|
||||
// Replace replaces the cache with what is in external storage.
|
||||
// key is the suggested key which can be used for partioning the cache
|
||||
Replace(cache Unmarshaler, key string)
|
||||
// Export writes the binary representation of the cache (cache.Marshal()) to
|
||||
// external storage. This is considered opaque.
|
||||
// key is the suggested key which can be used for partioning the cache
|
||||
Export(cache Marshaler, key string)
|
||||
// ExportHints are suggestions for storing data.
|
||||
type ExportHints struct {
|
||||
// PartitionKey is a suggested key for partitioning the cache
|
||||
PartitionKey string
|
||||
}
|
||||
|
||||
// ReplaceHints are suggestions for loading data.
|
||||
type ReplaceHints struct {
|
||||
// PartitionKey is a suggested key for partitioning the cache
|
||||
PartitionKey string
|
||||
}
|
||||
|
||||
// ExportReplace exports and replaces in-memory cache data. It doesn't support nil Context or
|
||||
// define the outcome of passing one. A Context without a timeout must receive a default timeout
|
||||
// specified by the implementor. Retries must be implemented inside the implementation.
|
||||
type ExportReplace interface {
|
||||
// Replace replaces the cache with what is in external storage. Implementors should honor
|
||||
// Context cancellations and return context.Canceled or context.DeadlineExceeded in those cases.
|
||||
Replace(ctx context.Context, cache Unmarshaler, hints ReplaceHints) error
|
||||
// Export writes the binary representation of the cache (cache.Marshal()) to external storage.
|
||||
// This is considered opaque. Context cancellations should be honored as in Replace.
|
||||
Export(ctx context.Context, cache Marshaler, hints ExportHints) error
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ import (
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/AzureAD/microsoft-authentication-library-for-go/apps/cache"
|
||||
"github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base"
|
||||
@@ -50,8 +49,7 @@ duplication.
|
||||
.Net People, Take note on X509:
|
||||
This uses x509.Certificates and private keys. x509 does not store private keys. .Net
|
||||
has some x509.Certificate2 thing that has private keys, but that is just some bullcrap that .Net
|
||||
added, it doesn't exist in real life. Seriously, "x509.Certificate2", bahahahaha. As such I've
|
||||
put a PEM decoder into here.
|
||||
added, it doesn't exist in real life. As such I've put a PEM decoder into here.
|
||||
*/
|
||||
|
||||
// TODO(msal): This should have example code for each method on client using Go's example doc framework.
|
||||
@@ -63,7 +61,7 @@ type AuthResult = base.AuthResult
|
||||
|
||||
type Account = shared.Account
|
||||
|
||||
// CertFromPEM converts a PEM file (.pem or .key) for use with NewCredFromCert(). The file
|
||||
// CertFromPEM converts a PEM file (.pem or .key) for use with [NewCredFromCert]. The file
|
||||
// must contain the public certificate and the private key. If a PEM block is encrypted and
|
||||
// password is not an empty string, it attempts to decrypt the PEM blocks using the password.
|
||||
// Multiple certs are due to certificate chaining for use cases like TLS that sign from root to leaf.
|
||||
@@ -179,33 +177,15 @@ func NewCredFromSecret(secret string) (Credential, error) {
|
||||
return Credential{secret: secret}, nil
|
||||
}
|
||||
|
||||
// NewCredFromAssertion creates a Credential from a signed assertion.
|
||||
//
|
||||
// Deprecated: a Credential created by this function can't refresh the
|
||||
// assertion when it expires. Use NewCredFromAssertionCallback instead.
|
||||
func NewCredFromAssertion(assertion string) (Credential, error) {
|
||||
if assertion == "" {
|
||||
return Credential{}, errors.New("assertion can't be empty string")
|
||||
}
|
||||
return NewCredFromAssertionCallback(func(context.Context, AssertionRequestOptions) (string, error) { return assertion, nil }), nil
|
||||
}
|
||||
|
||||
// NewCredFromAssertionCallback creates a Credential that invokes a callback to get assertions
|
||||
// authenticating the application. The callback must be thread safe.
|
||||
func NewCredFromAssertionCallback(callback func(context.Context, AssertionRequestOptions) (string, error)) Credential {
|
||||
return Credential{assertionCallback: callback}
|
||||
}
|
||||
|
||||
// NewCredFromCert creates a Credential from an x509.Certificate and an RSA private key.
|
||||
// CertFromPEM() can be used to get these values from a PEM file.
|
||||
func NewCredFromCert(cert *x509.Certificate, key crypto.PrivateKey) Credential {
|
||||
cred, _ := NewCredFromCertChain([]*x509.Certificate{cert}, key)
|
||||
return cred
|
||||
}
|
||||
|
||||
// NewCredFromCertChain creates a Credential from a chain of x509.Certificates and an RSA private key
|
||||
// as returned by CertFromPEM().
|
||||
func NewCredFromCertChain(certs []*x509.Certificate, key crypto.PrivateKey) (Credential, error) {
|
||||
// NewCredFromCert creates a Credential from a certificate or chain of certificates and an RSA private key
|
||||
// as returned by [CertFromPEM].
|
||||
func NewCredFromCert(certs []*x509.Certificate, key crypto.PrivateKey) (Credential, error) {
|
||||
cred := Credential{key: key}
|
||||
k, ok := key.(*rsa.PrivateKey)
|
||||
if !ok {
|
||||
@@ -255,73 +235,32 @@ func AutoDetectRegion() string {
|
||||
// For more information, visit https://docs.microsoft.com/azure/active-directory/develop/msal-client-applications
|
||||
type Client struct {
|
||||
base base.Client
|
||||
|
||||
cred *accesstokens.Credential
|
||||
|
||||
// userID is some unique identifier for a user. It actually isn't used by us at all, it
|
||||
// simply acts as another hint that a confidential.Client is for a single user.
|
||||
userID string
|
||||
}
|
||||
|
||||
// Options are optional settings for New(). These options are set using various functions
|
||||
// clientOptions are optional settings for New(). These options are set using various functions
|
||||
// returning Option calls.
|
||||
type Options struct {
|
||||
// Accessor controls cache persistence.
|
||||
// By default there is no cache persistence. This can be set using the WithAccessor() option.
|
||||
Accessor cache.ExportReplace
|
||||
|
||||
// The host of the Azure Active Directory authority.
|
||||
// The default is https://login.microsoftonline.com/common. This can be changed using the
|
||||
// WithAuthority() option.
|
||||
Authority string
|
||||
|
||||
// The HTTP client used for making requests.
|
||||
// It defaults to a shared http.Client.
|
||||
HTTPClient ops.HTTPClient
|
||||
|
||||
// SendX5C specifies if x5c claim(public key of the certificate) should be sent to STS.
|
||||
SendX5C bool
|
||||
|
||||
// Instructs MSAL Go to use an Azure regional token service with sepcified AzureRegion.
|
||||
AzureRegion string
|
||||
|
||||
capabilities []string
|
||||
|
||||
disableInstanceDiscovery bool
|
||||
}
|
||||
|
||||
func (o Options) validate() error {
|
||||
u, err := url.Parse(o.Authority)
|
||||
if err != nil {
|
||||
return fmt.Errorf("the Authority(%s) does not parse as a valid URL", o.Authority)
|
||||
}
|
||||
if u.Scheme != "https" {
|
||||
return fmt.Errorf("the Authority(%s) does not appear to use https", o.Authority)
|
||||
}
|
||||
return nil
|
||||
type clientOptions struct {
|
||||
accessor cache.ExportReplace
|
||||
authority, azureRegion string
|
||||
capabilities []string
|
||||
disableInstanceDiscovery, sendX5C bool
|
||||
httpClient ops.HTTPClient
|
||||
}
|
||||
|
||||
// Option is an optional argument to New().
|
||||
type Option func(o *Options)
|
||||
type Option func(o *clientOptions)
|
||||
|
||||
// WithAuthority allows you to provide a custom authority for use in the client.
|
||||
func WithAuthority(authority string) Option {
|
||||
return func(o *Options) {
|
||||
o.Authority = authority
|
||||
}
|
||||
}
|
||||
|
||||
// WithAccessor provides a cache accessor that will read and write to some externally managed cache
|
||||
// that may or may not be shared with other applications.
|
||||
func WithAccessor(accessor cache.ExportReplace) Option {
|
||||
return func(o *Options) {
|
||||
o.Accessor = accessor
|
||||
// WithCache provides an accessor that will read and write authentication data to an externally managed cache.
|
||||
func WithCache(accessor cache.ExportReplace) Option {
|
||||
return func(o *clientOptions) {
|
||||
o.accessor = accessor
|
||||
}
|
||||
}
|
||||
|
||||
// WithClientCapabilities allows configuring one or more client capabilities such as "CP1"
|
||||
func WithClientCapabilities(capabilities []string) Option {
|
||||
return func(o *Options) {
|
||||
return func(o *clientOptions) {
|
||||
// there's no danger of sharing the slice's underlying memory with the application because
|
||||
// this slice is simply passed to base.WithClientCapabilities, which copies its data
|
||||
o.capabilities = capabilities
|
||||
@@ -330,21 +269,21 @@ func WithClientCapabilities(capabilities []string) Option {
|
||||
|
||||
// WithHTTPClient allows for a custom HTTP client to be set.
|
||||
func WithHTTPClient(httpClient ops.HTTPClient) Option {
|
||||
return func(o *Options) {
|
||||
o.HTTPClient = httpClient
|
||||
return func(o *clientOptions) {
|
||||
o.httpClient = httpClient
|
||||
}
|
||||
}
|
||||
|
||||
// WithX5C specifies if x5c claim(public key of the certificate) should be sent to STS to enable Subject Name Issuer Authentication.
|
||||
func WithX5C() Option {
|
||||
return func(o *Options) {
|
||||
o.SendX5C = true
|
||||
return func(o *clientOptions) {
|
||||
o.sendX5C = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithInstanceDiscovery set to false to disable authority validation (to support private cloud scenarios)
|
||||
func WithInstanceDiscovery(enabled bool) Option {
|
||||
return func(o *Options) {
|
||||
return func(o *clientOptions) {
|
||||
o.disableInstanceDiscovery = !enabled
|
||||
}
|
||||
}
|
||||
@@ -361,44 +300,37 @@ func WithInstanceDiscovery(enabled bool) Option {
|
||||
// If auto-detection fails, the non-regional endpoint will be used.
|
||||
// If an invalid region name is provided, the non-regional endpoint MIGHT be used or the token request MIGHT fail.
|
||||
func WithAzureRegion(val string) Option {
|
||||
return func(o *Options) {
|
||||
o.AzureRegion = val
|
||||
return func(o *clientOptions) {
|
||||
o.azureRegion = val
|
||||
}
|
||||
}
|
||||
|
||||
// New is the constructor for Client. userID is the unique identifier of the user this client
|
||||
// will store credentials for (a Client is per user). clientID is the Azure clientID and cred is
|
||||
// the type of credential to use.
|
||||
func New(clientID string, cred Credential, options ...Option) (Client, error) {
|
||||
// New is the constructor for Client. authority is the URL of a token authority such as "https://login.microsoftonline.com/<your tenant>".
|
||||
// If the Client will connect directly to AD FS, use "adfs" for the tenant. clientID is the application's client ID (also called its
|
||||
// "application ID").
|
||||
func New(authority, clientID string, cred Credential, options ...Option) (Client, error) {
|
||||
internalCred, err := cred.toInternal()
|
||||
if err != nil {
|
||||
return Client{}, err
|
||||
}
|
||||
|
||||
opts := Options{
|
||||
Authority: base.AuthorityPublicCloud,
|
||||
HTTPClient: shared.DefaultClient,
|
||||
opts := clientOptions{
|
||||
authority: authority,
|
||||
// if the caller specified a token provider, it will handle all details of authentication, using Client only as a token cache
|
||||
disableInstanceDiscovery: cred.tokenProvider != nil,
|
||||
httpClient: shared.DefaultClient,
|
||||
}
|
||||
|
||||
for _, o := range options {
|
||||
o(&opts)
|
||||
}
|
||||
if err := opts.validate(); err != nil {
|
||||
return Client{}, err
|
||||
}
|
||||
|
||||
baseOpts := []base.Option{
|
||||
base.WithCacheAccessor(opts.Accessor),
|
||||
base.WithCacheAccessor(opts.accessor),
|
||||
base.WithClientCapabilities(opts.capabilities),
|
||||
base.WithRegionDetection(opts.AzureRegion),
|
||||
base.WithX5C(opts.SendX5C),
|
||||
base.WithInstanceDiscovery(!opts.disableInstanceDiscovery),
|
||||
base.WithRegionDetection(opts.azureRegion),
|
||||
base.WithX5C(opts.sendX5C),
|
||||
}
|
||||
if cred.tokenProvider != nil {
|
||||
// The caller will handle all details of authentication, using Client only as a token cache.
|
||||
baseOpts = append(baseOpts, base.WithInstanceDiscovery(false))
|
||||
}
|
||||
base, err := base.New(clientID, opts.Authority, oauth.New(opts.HTTPClient), baseOpts...)
|
||||
base, err := base.New(clientID, opts.authority, oauth.New(opts.httpClient), baseOpts...)
|
||||
if err != nil {
|
||||
return Client{}, err
|
||||
}
|
||||
@@ -407,11 +339,6 @@ func New(clientID string, cred Credential, options ...Option) (Client, error) {
|
||||
return Client{base: base, cred: internalCred}, nil
|
||||
}
|
||||
|
||||
// UserID is the unique user identifier this client if for.
|
||||
func (cca Client) UserID() string {
|
||||
return cca.userID
|
||||
}
|
||||
|
||||
// authCodeURLOptions contains options for AuthCodeURL
|
||||
type authCodeURLOptions struct {
|
||||
claims, loginHint, tenantID, domainHint string
|
||||
@@ -508,13 +435,13 @@ func WithClaims(claims string) interface {
|
||||
CallOption: options.NewCallOption(
|
||||
func(a any) error {
|
||||
switch t := a.(type) {
|
||||
case *AcquireTokenByAuthCodeOptions:
|
||||
case *acquireTokenByAuthCodeOptions:
|
||||
t.claims = claims
|
||||
case *acquireTokenByCredentialOptions:
|
||||
t.claims = claims
|
||||
case *acquireTokenOnBehalfOfOptions:
|
||||
t.claims = claims
|
||||
case *AcquireTokenSilentOptions:
|
||||
case *acquireTokenSilentOptions:
|
||||
t.claims = claims
|
||||
case *authCodeURLOptions:
|
||||
t.claims = claims
|
||||
@@ -527,7 +454,7 @@ func WithClaims(claims string) interface {
|
||||
}
|
||||
}
|
||||
|
||||
// WithTenantID specifies a tenant for a single authentication. It may be different than the tenant set in [New] by [WithAuthority].
|
||||
// WithTenantID specifies a tenant for a single authentication. It may be different than the tenant set in [New].
|
||||
// This option is valid for any token acquisition method.
|
||||
func WithTenantID(tenantID string) interface {
|
||||
AcquireByAuthCodeOption
|
||||
@@ -548,13 +475,13 @@ func WithTenantID(tenantID string) interface {
|
||||
CallOption: options.NewCallOption(
|
||||
func(a any) error {
|
||||
switch t := a.(type) {
|
||||
case *AcquireTokenByAuthCodeOptions:
|
||||
case *acquireTokenByAuthCodeOptions:
|
||||
t.tenantID = tenantID
|
||||
case *acquireTokenByCredentialOptions:
|
||||
t.tenantID = tenantID
|
||||
case *acquireTokenOnBehalfOfOptions:
|
||||
t.tenantID = tenantID
|
||||
case *AcquireTokenSilentOptions:
|
||||
case *acquireTokenSilentOptions:
|
||||
t.tenantID = tenantID
|
||||
case *authCodeURLOptions:
|
||||
t.tenantID = tenantID
|
||||
@@ -567,12 +494,10 @@ func WithTenantID(tenantID string) interface {
|
||||
}
|
||||
}
|
||||
|
||||
// AcquireTokenSilentOptions are all the optional settings to an AcquireTokenSilent() call.
|
||||
// acquireTokenSilentOptions are all the optional settings to an AcquireTokenSilent() call.
|
||||
// These are set by using various AcquireTokenSilentOption functions.
|
||||
type AcquireTokenSilentOptions struct {
|
||||
// Account represents the account to use. To set, use the WithSilentAccount() option.
|
||||
Account Account
|
||||
|
||||
type acquireTokenSilentOptions struct {
|
||||
account Account
|
||||
claims, tenantID string
|
||||
}
|
||||
|
||||
@@ -581,11 +506,6 @@ type AcquireSilentOption interface {
|
||||
acquireSilentOption()
|
||||
}
|
||||
|
||||
// AcquireTokenSilentOption changes options inside AcquireTokenSilentOptions used in .AcquireTokenSilent().
|
||||
type AcquireTokenSilentOption func(a *AcquireTokenSilentOptions)
|
||||
|
||||
func (AcquireTokenSilentOption) acquireSilentOption() {}
|
||||
|
||||
// WithSilentAccount uses the passed account during an AcquireTokenSilent() call.
|
||||
func WithSilentAccount(account Account) interface {
|
||||
AcquireSilentOption
|
||||
@@ -598,8 +518,8 @@ func WithSilentAccount(account Account) interface {
|
||||
CallOption: options.NewCallOption(
|
||||
func(a any) error {
|
||||
switch t := a.(type) {
|
||||
case *AcquireTokenSilentOptions:
|
||||
t.Account = account
|
||||
case *acquireTokenSilentOptions:
|
||||
t.account = account
|
||||
default:
|
||||
return fmt.Errorf("unexpected options type %T", a)
|
||||
}
|
||||
@@ -613,7 +533,7 @@ func WithSilentAccount(account Account) interface {
|
||||
//
|
||||
// Options: [WithClaims], [WithSilentAccount], [WithTenantID]
|
||||
func (cca Client) AcquireTokenSilent(ctx context.Context, scopes []string, opts ...AcquireSilentOption) (AuthResult, error) {
|
||||
o := AcquireTokenSilentOptions{}
|
||||
o := acquireTokenSilentOptions{}
|
||||
if err := options.ApplyOptions(&o, opts); err != nil {
|
||||
return AuthResult{}, err
|
||||
}
|
||||
@@ -624,21 +544,19 @@ func (cca Client) AcquireTokenSilent(ctx context.Context, scopes []string, opts
|
||||
|
||||
silentParameters := base.AcquireTokenSilentParameters{
|
||||
Scopes: scopes,
|
||||
Account: o.Account,
|
||||
Account: o.account,
|
||||
RequestType: accesstokens.ATConfidential,
|
||||
Credential: cca.cred,
|
||||
IsAppCache: o.Account.IsZero(),
|
||||
IsAppCache: o.account.IsZero(),
|
||||
TenantID: o.tenantID,
|
||||
}
|
||||
|
||||
return cca.base.AcquireTokenSilent(ctx, silentParameters)
|
||||
}
|
||||
|
||||
// AcquireTokenByAuthCodeOptions contains the optional parameters used to acquire an access token using the authorization code flow.
|
||||
type AcquireTokenByAuthCodeOptions struct {
|
||||
Challenge string
|
||||
|
||||
claims, tenantID string
|
||||
// acquireTokenByAuthCodeOptions contains the optional parameters used to acquire an access token using the authorization code flow.
|
||||
type acquireTokenByAuthCodeOptions struct {
|
||||
challenge, claims, tenantID string
|
||||
}
|
||||
|
||||
// AcquireByAuthCodeOption is implemented by options for AcquireTokenByAuthCode
|
||||
@@ -646,11 +564,6 @@ type AcquireByAuthCodeOption interface {
|
||||
acquireByAuthCodeOption()
|
||||
}
|
||||
|
||||
// AcquireTokenByAuthCodeOption changes options inside AcquireTokenByAuthCodeOptions used in .AcquireTokenByAuthCode().
|
||||
type AcquireTokenByAuthCodeOption func(a *AcquireTokenByAuthCodeOptions)
|
||||
|
||||
func (AcquireTokenByAuthCodeOption) acquireByAuthCodeOption() {}
|
||||
|
||||
// WithChallenge allows you to provide a challenge for the .AcquireTokenByAuthCode() call.
|
||||
func WithChallenge(challenge string) interface {
|
||||
AcquireByAuthCodeOption
|
||||
@@ -663,8 +576,8 @@ func WithChallenge(challenge string) interface {
|
||||
CallOption: options.NewCallOption(
|
||||
func(a any) error {
|
||||
switch t := a.(type) {
|
||||
case *AcquireTokenByAuthCodeOptions:
|
||||
t.Challenge = challenge
|
||||
case *acquireTokenByAuthCodeOptions:
|
||||
t.challenge = challenge
|
||||
default:
|
||||
return fmt.Errorf("unexpected options type %T", a)
|
||||
}
|
||||
@@ -679,7 +592,7 @@ func WithChallenge(challenge string) interface {
|
||||
//
|
||||
// Options: [WithChallenge], [WithClaims], [WithTenantID]
|
||||
func (cca Client) AcquireTokenByAuthCode(ctx context.Context, code string, redirectURI string, scopes []string, opts ...AcquireByAuthCodeOption) (AuthResult, error) {
|
||||
o := AcquireTokenByAuthCodeOptions{}
|
||||
o := acquireTokenByAuthCodeOptions{}
|
||||
if err := options.ApplyOptions(&o, opts); err != nil {
|
||||
return AuthResult{}, err
|
||||
}
|
||||
@@ -687,7 +600,7 @@ func (cca Client) AcquireTokenByAuthCode(ctx context.Context, code string, redir
|
||||
params := base.AcquireTokenAuthCodeParameters{
|
||||
Scopes: scopes,
|
||||
Code: code,
|
||||
Challenge: o.Challenge,
|
||||
Challenge: o.challenge,
|
||||
Claims: o.claims,
|
||||
AppType: accesstokens.ATConfidential,
|
||||
Credential: cca.cred, // This setting differs from public.Client.AcquireTokenByAuthCode
|
||||
@@ -762,12 +675,11 @@ func (cca Client) AcquireTokenOnBehalfOf(ctx context.Context, userAssertion stri
|
||||
}
|
||||
|
||||
// Account gets the account in the token cache with the specified homeAccountID.
|
||||
func (cca Client) Account(homeAccountID string) Account {
|
||||
return cca.base.Account(homeAccountID)
|
||||
func (cca Client) Account(ctx context.Context, accountID string) (Account, error) {
|
||||
return cca.base.Account(ctx, accountID)
|
||||
}
|
||||
|
||||
// RemoveAccount signs the account out and forgets account from token cache.
|
||||
func (cca Client) RemoveAccount(account Account) error {
|
||||
cca.base.RemoveAccount(account)
|
||||
return nil
|
||||
func (cca Client) RemoveAccount(ctx context.Context, account Account) error {
|
||||
return cca.base.RemoveAccount(ctx, account)
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ func (e CallErr) Error() string {
|
||||
|
||||
// Verbose prints a versbose error message with the request or response.
|
||||
func (e CallErr) Verbose() string {
|
||||
e.Resp.Request = nil // This brings in a bunch of TLS crap we don't need
|
||||
e.Resp.Request = nil // This brings in a bunch of TLS stuff we don't need
|
||||
e.Resp.TLS = nil // Same
|
||||
return fmt.Sprintf("%s:\nRequest:\n%s\nResponse:\n%s", e.Err, prettyConf.Sprint(e.Req), prettyConf.Sprint(e.Resp))
|
||||
}
|
||||
|
||||
194
vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/base.go
generated
vendored
194
vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/base.go
generated
vendored
@@ -10,6 +10,7 @@ import (
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/AzureAD/microsoft-authentication-library-for-go/apps/cache"
|
||||
@@ -27,27 +28,21 @@ const (
|
||||
)
|
||||
|
||||
// manager provides an internal cache. It is defined to allow faking the cache in tests.
|
||||
// In all production use it is a *storage.Manager.
|
||||
// In production it's a *storage.Manager or *storage.PartitionedManager.
|
||||
type manager interface {
|
||||
Read(ctx context.Context, authParameters authority.AuthParams, account shared.Account) (storage.TokenResponse, error)
|
||||
Write(authParameters authority.AuthParams, tokenResponse accesstokens.TokenResponse) (shared.Account, error)
|
||||
cache.Serializer
|
||||
Read(context.Context, authority.AuthParams) (storage.TokenResponse, error)
|
||||
Write(authority.AuthParams, accesstokens.TokenResponse) (shared.Account, error)
|
||||
}
|
||||
|
||||
// accountManager is a manager that also caches accounts. In production it's a *storage.Manager.
|
||||
type accountManager interface {
|
||||
manager
|
||||
AllAccounts() []shared.Account
|
||||
Account(homeAccountID string) shared.Account
|
||||
RemoveAccount(account shared.Account, clientID string)
|
||||
}
|
||||
|
||||
// partitionedManager provides an internal cache. It is defined to allow faking the cache in tests.
|
||||
// In all production use it is a *storage.PartitionedManager.
|
||||
type partitionedManager interface {
|
||||
Read(ctx context.Context, authParameters authority.AuthParams) (storage.TokenResponse, error)
|
||||
Write(authParameters authority.AuthParams, tokenResponse accesstokens.TokenResponse) (shared.Account, error)
|
||||
}
|
||||
|
||||
type noopCacheAccessor struct{}
|
||||
|
||||
func (n noopCacheAccessor) Replace(cache cache.Unmarshaler, key string) {}
|
||||
func (n noopCacheAccessor) Export(cache cache.Marshaler, key string) {}
|
||||
|
||||
// AcquireTokenSilentParameters contains the parameters to acquire a token silently (from cache).
|
||||
type AcquireTokenSilentParameters struct {
|
||||
Scopes []string
|
||||
@@ -133,12 +128,14 @@ func NewAuthResult(tokenResponse accesstokens.TokenResponse, account shared.Acco
|
||||
// Client is a base client that provides access to common methods and primatives that
|
||||
// can be used by multiple clients.
|
||||
type Client struct {
|
||||
Token *oauth.Client
|
||||
manager manager // *storage.Manager or fakeManager in tests
|
||||
pmanager partitionedManager // *storage.PartitionedManager or fakeManager in tests
|
||||
Token *oauth.Client
|
||||
manager accountManager // *storage.Manager or fakeManager in tests
|
||||
// pmanager is a partitioned cache for OBO authentication. *storage.PartitionedManager or fakeManager in tests
|
||||
pmanager manager
|
||||
|
||||
AuthParams authority.AuthParams // DO NOT EVER MAKE THIS A POINTER! See "Note" in New().
|
||||
cacheAccessor cache.ExportReplace
|
||||
AuthParams authority.AuthParams // DO NOT EVER MAKE THIS A POINTER! See "Note" in New().
|
||||
cacheAccessor cache.ExportReplace
|
||||
cacheAccessorMu *sync.RWMutex
|
||||
}
|
||||
|
||||
// Option is an optional argument to the New constructor.
|
||||
@@ -210,11 +207,11 @@ func New(clientID string, authorityURI string, token *oauth.Client, options ...O
|
||||
}
|
||||
authParams := authority.NewAuthParams(clientID, authInfo)
|
||||
client := Client{ // Note: Hey, don't even THINK about making Base into *Base. See "design notes" in public.go and confidential.go
|
||||
Token: token,
|
||||
AuthParams: authParams,
|
||||
cacheAccessor: noopCacheAccessor{},
|
||||
manager: storage.New(token),
|
||||
pmanager: storage.NewPartitionedManager(token),
|
||||
Token: token,
|
||||
AuthParams: authParams,
|
||||
cacheAccessorMu: &sync.RWMutex{},
|
||||
manager: storage.New(token),
|
||||
pmanager: storage.NewPartitionedManager(token),
|
||||
}
|
||||
for _, o := range options {
|
||||
if err = o(&client); err != nil {
|
||||
@@ -280,11 +277,12 @@ func (b Client) AuthCodeURL(ctx context.Context, clientID, redirectURI string, s
|
||||
}
|
||||
|
||||
func (b Client) AcquireTokenSilent(ctx context.Context, silent AcquireTokenSilentParameters) (AuthResult, error) {
|
||||
// when tenant == "", the caller didn't specify a tenant and WithTenant will use the client's configured tenant
|
||||
ar := AuthResult{}
|
||||
// when tenant == "", the caller didn't specify a tenant and WithTenant will choose the client's configured tenant
|
||||
tenant := silent.TenantID
|
||||
authParams, err := b.AuthParams.WithTenant(tenant)
|
||||
if err != nil {
|
||||
return AuthResult{}, err
|
||||
return ar, err
|
||||
}
|
||||
authParams.Scopes = silent.Scopes
|
||||
authParams.HomeAccountID = silent.Account.HomeAccountID
|
||||
@@ -292,52 +290,45 @@ func (b Client) AcquireTokenSilent(ctx context.Context, silent AcquireTokenSilen
|
||||
authParams.Claims = silent.Claims
|
||||
authParams.UserAssertion = silent.UserAssertion
|
||||
|
||||
var storageTokenResponse storage.TokenResponse
|
||||
if authParams.AuthorizationType == authority.ATOnBehalfOf {
|
||||
if s, ok := b.pmanager.(cache.Serializer); ok {
|
||||
suggestedCacheKey := authParams.CacheKey(silent.IsAppCache)
|
||||
b.cacheAccessor.Replace(s, suggestedCacheKey)
|
||||
defer b.cacheAccessor.Export(s, suggestedCacheKey)
|
||||
}
|
||||
storageTokenResponse, err = b.pmanager.Read(ctx, authParams)
|
||||
if err != nil {
|
||||
return AuthResult{}, err
|
||||
}
|
||||
} else {
|
||||
if s, ok := b.manager.(cache.Serializer); ok {
|
||||
suggestedCacheKey := authParams.CacheKey(silent.IsAppCache)
|
||||
b.cacheAccessor.Replace(s, suggestedCacheKey)
|
||||
defer b.cacheAccessor.Export(s, suggestedCacheKey)
|
||||
}
|
||||
m := b.pmanager
|
||||
if authParams.AuthorizationType != authority.ATOnBehalfOf {
|
||||
authParams.AuthorizationType = authority.ATRefreshToken
|
||||
storageTokenResponse, err = b.manager.Read(ctx, authParams, silent.Account)
|
||||
if err != nil {
|
||||
return AuthResult{}, err
|
||||
}
|
||||
m = b.manager
|
||||
}
|
||||
if b.cacheAccessor != nil {
|
||||
key := authParams.CacheKey(silent.IsAppCache)
|
||||
b.cacheAccessorMu.RLock()
|
||||
err = b.cacheAccessor.Replace(ctx, m, cache.ReplaceHints{PartitionKey: key})
|
||||
b.cacheAccessorMu.RUnlock()
|
||||
}
|
||||
if err != nil {
|
||||
return ar, err
|
||||
}
|
||||
storageTokenResponse, err := m.Read(ctx, authParams)
|
||||
if err != nil {
|
||||
return ar, err
|
||||
}
|
||||
|
||||
// ignore cached access tokens when given claims
|
||||
if silent.Claims == "" {
|
||||
result, err := AuthResultFromStorage(storageTokenResponse)
|
||||
ar, err = AuthResultFromStorage(storageTokenResponse)
|
||||
if err == nil {
|
||||
return result, nil
|
||||
return ar, err
|
||||
}
|
||||
}
|
||||
|
||||
// redeem a cached refresh token, if available
|
||||
if reflect.ValueOf(storageTokenResponse.RefreshToken).IsZero() {
|
||||
return AuthResult{}, errors.New("no token found")
|
||||
return ar, errors.New("no token found")
|
||||
}
|
||||
var cc *accesstokens.Credential
|
||||
if silent.RequestType == accesstokens.ATConfidential {
|
||||
cc = silent.Credential
|
||||
}
|
||||
|
||||
token, err := b.Token.Refresh(ctx, silent.RequestType, authParams, cc, storageTokenResponse.RefreshToken)
|
||||
if err != nil {
|
||||
return AuthResult{}, err
|
||||
return ar, err
|
||||
}
|
||||
|
||||
return b.AuthResultFromToken(ctx, authParams, token, true)
|
||||
}
|
||||
|
||||
@@ -405,63 +396,72 @@ func (b Client) AuthResultFromToken(ctx context.Context, authParams authority.Au
|
||||
if !cacheWrite {
|
||||
return NewAuthResult(token, shared.Account{})
|
||||
}
|
||||
|
||||
var account shared.Account
|
||||
var err error
|
||||
var m manager = b.manager
|
||||
if authParams.AuthorizationType == authority.ATOnBehalfOf {
|
||||
if s, ok := b.pmanager.(cache.Serializer); ok {
|
||||
suggestedCacheKey := token.CacheKey(authParams)
|
||||
b.cacheAccessor.Replace(s, suggestedCacheKey)
|
||||
defer b.cacheAccessor.Export(s, suggestedCacheKey)
|
||||
}
|
||||
account, err = b.pmanager.Write(authParams, token)
|
||||
if err != nil {
|
||||
return AuthResult{}, err
|
||||
}
|
||||
} else {
|
||||
if s, ok := b.manager.(cache.Serializer); ok {
|
||||
suggestedCacheKey := token.CacheKey(authParams)
|
||||
b.cacheAccessor.Replace(s, suggestedCacheKey)
|
||||
defer b.cacheAccessor.Export(s, suggestedCacheKey)
|
||||
}
|
||||
account, err = b.manager.Write(authParams, token)
|
||||
m = b.pmanager
|
||||
}
|
||||
key := token.CacheKey(authParams)
|
||||
if b.cacheAccessor != nil {
|
||||
b.cacheAccessorMu.Lock()
|
||||
defer b.cacheAccessorMu.Unlock()
|
||||
err := b.cacheAccessor.Replace(ctx, m, cache.ReplaceHints{PartitionKey: key})
|
||||
if err != nil {
|
||||
return AuthResult{}, err
|
||||
}
|
||||
}
|
||||
return NewAuthResult(token, account)
|
||||
account, err := m.Write(authParams, token)
|
||||
if err != nil {
|
||||
return AuthResult{}, err
|
||||
}
|
||||
ar, err := NewAuthResult(token, account)
|
||||
if err == nil && b.cacheAccessor != nil {
|
||||
err = b.cacheAccessor.Export(ctx, b.manager, cache.ExportHints{PartitionKey: key})
|
||||
}
|
||||
return ar, err
|
||||
}
|
||||
|
||||
func (b Client) AllAccounts() []shared.Account {
|
||||
if s, ok := b.manager.(cache.Serializer); ok {
|
||||
suggestedCacheKey := b.AuthParams.CacheKey(false)
|
||||
b.cacheAccessor.Replace(s, suggestedCacheKey)
|
||||
defer b.cacheAccessor.Export(s, suggestedCacheKey)
|
||||
func (b Client) AllAccounts(ctx context.Context) ([]shared.Account, error) {
|
||||
if b.cacheAccessor != nil {
|
||||
b.cacheAccessorMu.RLock()
|
||||
defer b.cacheAccessorMu.RUnlock()
|
||||
key := b.AuthParams.CacheKey(false)
|
||||
err := b.cacheAccessor.Replace(ctx, b.manager, cache.ReplaceHints{PartitionKey: key})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
accounts := b.manager.AllAccounts()
|
||||
return accounts
|
||||
return b.manager.AllAccounts(), nil
|
||||
}
|
||||
|
||||
func (b Client) Account(homeAccountID string) shared.Account {
|
||||
authParams := b.AuthParams // This is a copy, as we dont' have a pointer receiver and .AuthParams is not a pointer.
|
||||
authParams.AuthorizationType = authority.AccountByID
|
||||
authParams.HomeAccountID = homeAccountID
|
||||
if s, ok := b.manager.(cache.Serializer); ok {
|
||||
suggestedCacheKey := b.AuthParams.CacheKey(false)
|
||||
b.cacheAccessor.Replace(s, suggestedCacheKey)
|
||||
defer b.cacheAccessor.Export(s, suggestedCacheKey)
|
||||
func (b Client) Account(ctx context.Context, homeAccountID string) (shared.Account, error) {
|
||||
if b.cacheAccessor != nil {
|
||||
b.cacheAccessorMu.RLock()
|
||||
defer b.cacheAccessorMu.RUnlock()
|
||||
authParams := b.AuthParams // This is a copy, as we don't have a pointer receiver and .AuthParams is not a pointer.
|
||||
authParams.AuthorizationType = authority.AccountByID
|
||||
authParams.HomeAccountID = homeAccountID
|
||||
key := b.AuthParams.CacheKey(false)
|
||||
err := b.cacheAccessor.Replace(ctx, b.manager, cache.ReplaceHints{PartitionKey: key})
|
||||
if err != nil {
|
||||
return shared.Account{}, err
|
||||
}
|
||||
}
|
||||
account := b.manager.Account(homeAccountID)
|
||||
return account
|
||||
return b.manager.Account(homeAccountID), nil
|
||||
}
|
||||
|
||||
// RemoveAccount removes all the ATs, RTs and IDTs from the cache associated with this account.
|
||||
func (b Client) RemoveAccount(account shared.Account) {
|
||||
if s, ok := b.manager.(cache.Serializer); ok {
|
||||
suggestedCacheKey := b.AuthParams.CacheKey(false)
|
||||
b.cacheAccessor.Replace(s, suggestedCacheKey)
|
||||
defer b.cacheAccessor.Export(s, suggestedCacheKey)
|
||||
func (b Client) RemoveAccount(ctx context.Context, account shared.Account) error {
|
||||
if b.cacheAccessor == nil {
|
||||
b.manager.RemoveAccount(account, b.AuthParams.ClientID)
|
||||
return nil
|
||||
}
|
||||
b.cacheAccessorMu.Lock()
|
||||
defer b.cacheAccessorMu.Unlock()
|
||||
key := b.AuthParams.CacheKey(false)
|
||||
err := b.cacheAccessor.Replace(ctx, b.manager, cache.ReplaceHints{PartitionKey: key})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.manager.RemoveAccount(account, b.AuthParams.ClientID)
|
||||
return b.cacheAccessor.Export(ctx, b.manager, cache.ExportHints{PartitionKey: key})
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ func isMatchingScopes(scopesOne []string, scopesTwo string) bool {
|
||||
}
|
||||
|
||||
// Read reads a storage token from the cache if it exists.
|
||||
func (m *Manager) Read(ctx context.Context, authParameters authority.AuthParams, account shared.Account) (TokenResponse, error) {
|
||||
func (m *Manager) Read(ctx context.Context, authParameters authority.AuthParams) (TokenResponse, error) {
|
||||
tr := TokenResponse{}
|
||||
homeAccountID := authParameters.HomeAccountID
|
||||
realm := authParameters.AuthorityInfo.Tenant
|
||||
@@ -103,7 +103,8 @@ func (m *Manager) Read(ctx context.Context, authParameters authority.AuthParams,
|
||||
accessToken := m.readAccessToken(homeAccountID, aliases, realm, clientID, scopes)
|
||||
tr.AccessToken = accessToken
|
||||
|
||||
if account.IsZero() {
|
||||
if homeAccountID == "" {
|
||||
// caller didn't specify a user, so there's no reason to search for an ID or refresh token
|
||||
return tr, nil
|
||||
}
|
||||
// errors returned by read* methods indicate a cache miss and are therefore non-fatal. We continue populating
|
||||
@@ -122,7 +123,7 @@ func (m *Manager) Read(ctx context.Context, authParameters authority.AuthParams,
|
||||
}
|
||||
}
|
||||
|
||||
account, err = m.readAccount(homeAccountID, aliases, realm)
|
||||
account, err := m.readAccount(homeAccountID, aliases, realm)
|
||||
if err == nil {
|
||||
tr.Account = account
|
||||
}
|
||||
@@ -493,6 +494,8 @@ func (m *Manager) update(cache *Contract) {
|
||||
|
||||
// Marshal implements cache.Marshaler.
|
||||
func (m *Manager) Marshal() ([]byte, error) {
|
||||
m.contractMu.RLock()
|
||||
defer m.contractMu.RUnlock()
|
||||
return json.Marshal(m.contract)
|
||||
}
|
||||
|
||||
|
||||
@@ -76,12 +76,17 @@ func (t *Client) ResolveEndpoints(ctx context.Context, authorityInfo authority.I
|
||||
return t.Resolver.ResolveEndpoints(ctx, authorityInfo, userPrincipalName)
|
||||
}
|
||||
|
||||
// AADInstanceDiscovery attempts to discover a tenant endpoint (used in OIDC auth with an authorization endpoint).
|
||||
// This is done by AAD which allows for aliasing of tenants (windows.sts.net is the same as login.windows.com).
|
||||
func (t *Client) AADInstanceDiscovery(ctx context.Context, authorityInfo authority.Info) (authority.InstanceDiscoveryResponse, error) {
|
||||
return t.Authority.AADInstanceDiscovery(ctx, authorityInfo)
|
||||
}
|
||||
|
||||
// AuthCode returns a token based on an authorization code.
|
||||
func (t *Client) AuthCode(ctx context.Context, req accesstokens.AuthCodeRequest) (accesstokens.TokenResponse, error) {
|
||||
if err := scopeError(req.AuthParams); err != nil {
|
||||
return accesstokens.TokenResponse{}, err
|
||||
}
|
||||
if err := t.resolveEndpoint(ctx, &req.AuthParams, ""); err != nil {
|
||||
return accesstokens.TokenResponse{}, err
|
||||
}
|
||||
@@ -107,6 +112,10 @@ func (t *Client) Credential(ctx context.Context, authParams authority.AuthParams
|
||||
}
|
||||
tr, err := cred.TokenProvider(ctx, params)
|
||||
if err != nil {
|
||||
if len(scopes) == 0 {
|
||||
err = fmt.Errorf("token request had an empty authority.AuthParams.Scopes, which may cause the following error: %w", err)
|
||||
return accesstokens.TokenResponse{}, err
|
||||
}
|
||||
return accesstokens.TokenResponse{}, err
|
||||
}
|
||||
return accesstokens.TokenResponse{
|
||||
@@ -134,6 +143,9 @@ func (t *Client) Credential(ctx context.Context, authParams authority.AuthParams
|
||||
|
||||
// Credential acquires a token from the authority using a client credentials grant.
|
||||
func (t *Client) OnBehalfOf(ctx context.Context, authParams authority.AuthParams, cred *accesstokens.Credential) (accesstokens.TokenResponse, error) {
|
||||
if err := scopeError(authParams); err != nil {
|
||||
return accesstokens.TokenResponse{}, err
|
||||
}
|
||||
if err := t.resolveEndpoint(ctx, &authParams, ""); err != nil {
|
||||
return accesstokens.TokenResponse{}, err
|
||||
}
|
||||
@@ -145,20 +157,35 @@ func (t *Client) OnBehalfOf(ctx context.Context, authParams authority.AuthParams
|
||||
if err != nil {
|
||||
return accesstokens.TokenResponse{}, err
|
||||
}
|
||||
return t.AccessTokens.FromUserAssertionClientCertificate(ctx, authParams, authParams.UserAssertion, jwt)
|
||||
tr, err := t.AccessTokens.FromUserAssertionClientCertificate(ctx, authParams, authParams.UserAssertion, jwt)
|
||||
if err != nil {
|
||||
return accesstokens.TokenResponse{}, err
|
||||
}
|
||||
return tr, nil
|
||||
}
|
||||
|
||||
func (t *Client) Refresh(ctx context.Context, reqType accesstokens.AppType, authParams authority.AuthParams, cc *accesstokens.Credential, refreshToken accesstokens.RefreshToken) (accesstokens.TokenResponse, error) {
|
||||
if err := scopeError(authParams); err != nil {
|
||||
return accesstokens.TokenResponse{}, err
|
||||
}
|
||||
if err := t.resolveEndpoint(ctx, &authParams, ""); err != nil {
|
||||
return accesstokens.TokenResponse{}, err
|
||||
}
|
||||
|
||||
return t.AccessTokens.FromRefreshToken(ctx, reqType, authParams, cc, refreshToken.Secret)
|
||||
tr, err := t.AccessTokens.FromRefreshToken(ctx, reqType, authParams, cc, refreshToken.Secret)
|
||||
if err != nil {
|
||||
return accesstokens.TokenResponse{}, err
|
||||
}
|
||||
return tr, nil
|
||||
}
|
||||
|
||||
// UsernamePassword retrieves a token where a username and password is used. However, if this is
|
||||
// a user realm of "Federated", this uses SAML tokens. If "Managed", uses normal username/password.
|
||||
func (t *Client) UsernamePassword(ctx context.Context, authParams authority.AuthParams) (accesstokens.TokenResponse, error) {
|
||||
if err := scopeError(authParams); err != nil {
|
||||
return accesstokens.TokenResponse{}, err
|
||||
}
|
||||
|
||||
if authParams.AuthorityInfo.AuthorityType == authority.ADFS {
|
||||
if err := t.resolveEndpoint(ctx, &authParams, authParams.Username); err != nil {
|
||||
return accesstokens.TokenResponse{}, err
|
||||
@@ -171,22 +198,32 @@ func (t *Client) UsernamePassword(ctx context.Context, authParams authority.Auth
|
||||
|
||||
userRealm, err := t.Authority.UserRealm(ctx, authParams)
|
||||
if err != nil {
|
||||
return accesstokens.TokenResponse{}, fmt.Errorf("problem getting user realm(user: %s) from authority: %w", authParams.Username, err)
|
||||
return accesstokens.TokenResponse{}, fmt.Errorf("problem getting user realm from authority: %w", err)
|
||||
}
|
||||
|
||||
switch userRealm.AccountType {
|
||||
case authority.Federated:
|
||||
mexDoc, err := t.WSTrust.Mex(ctx, userRealm.FederationMetadataURL)
|
||||
if err != nil {
|
||||
return accesstokens.TokenResponse{}, fmt.Errorf("problem getting mex doc from federated url(%s): %w", userRealm.FederationMetadataURL, err)
|
||||
err = fmt.Errorf("problem getting mex doc from federated url(%s): %w", userRealm.FederationMetadataURL, err)
|
||||
return accesstokens.TokenResponse{}, err
|
||||
}
|
||||
|
||||
saml, err := t.WSTrust.SAMLTokenInfo(ctx, authParams, userRealm.CloudAudienceURN, mexDoc.UsernamePasswordEndpoint)
|
||||
if err != nil {
|
||||
return accesstokens.TokenResponse{}, fmt.Errorf("problem getting SAML token info: %w", err)
|
||||
err = fmt.Errorf("problem getting SAML token info: %w", err)
|
||||
return accesstokens.TokenResponse{}, err
|
||||
}
|
||||
return t.AccessTokens.FromSamlGrant(ctx, authParams, saml)
|
||||
tr, err := t.AccessTokens.FromSamlGrant(ctx, authParams, saml)
|
||||
if err != nil {
|
||||
return accesstokens.TokenResponse{}, err
|
||||
}
|
||||
return tr, nil
|
||||
case authority.Managed:
|
||||
if len(authParams.Scopes) == 0 {
|
||||
err = fmt.Errorf("token request had an empty authority.AuthParams.Scopes, which may cause the following error: %w", err)
|
||||
return accesstokens.TokenResponse{}, err
|
||||
}
|
||||
return t.AccessTokens.FromUsernamePassword(ctx, authParams)
|
||||
}
|
||||
return accesstokens.TokenResponse{}, errors.New("unknown account type")
|
||||
@@ -212,7 +249,6 @@ func (d DeviceCode) Token(ctx context.Context) (accesstokens.TokenResponse, erro
|
||||
}
|
||||
|
||||
var cancel context.CancelFunc
|
||||
d.Result.ExpiresOn.Sub(time.Now().UTC())
|
||||
if deadline, ok := ctx.Deadline(); !ok || d.Result.ExpiresOn.Before(deadline) {
|
||||
ctx, cancel = context.WithDeadline(ctx, d.Result.ExpiresOn)
|
||||
} else {
|
||||
@@ -275,6 +311,10 @@ func isWaitDeviceCodeErr(err error) bool {
|
||||
// DeviceCode returns a DeviceCode object that can be used to get the code that must be entered on the second
|
||||
// device and optionally the token once the code has been entered on the second device.
|
||||
func (t *Client) DeviceCode(ctx context.Context, authParams authority.AuthParams) (DeviceCode, error) {
|
||||
if err := scopeError(authParams); err != nil {
|
||||
return DeviceCode{}, err
|
||||
}
|
||||
|
||||
if err := t.resolveEndpoint(ctx, &authParams, ""); err != nil {
|
||||
return DeviceCode{}, err
|
||||
}
|
||||
@@ -295,3 +335,19 @@ func (t *Client) resolveEndpoint(ctx context.Context, authParams *authority.Auth
|
||||
authParams.Endpoints = endpoints
|
||||
return nil
|
||||
}
|
||||
|
||||
// scopeError takes an authority.AuthParams and returns an error
|
||||
// if len(AuthParams.Scope) == 0.
|
||||
func scopeError(a authority.AuthParams) error {
|
||||
// TODO(someone): we could look deeper at the message to determine if
|
||||
// it's a scope error, but this is a good start.
|
||||
/*
|
||||
{error":"invalid_scope","error_description":"AADSTS1002012: The provided value for scope
|
||||
openid offline_access profile is not valid. Client credential flows must have a scope value
|
||||
with /.default suffixed to the resource identifier (application ID URI)...}
|
||||
*/
|
||||
if len(a.Scopes) == 0 {
|
||||
return fmt.Errorf("token request had an empty authority.AuthParams.Scopes, which is invalid")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -28,10 +28,19 @@ const (
|
||||
regionName = "REGION_NAME"
|
||||
defaultAPIVersion = "2021-10-01"
|
||||
imdsEndpoint = "http://169.254.169.254/metadata/instance/compute/location?format=text&api-version=" + defaultAPIVersion
|
||||
defaultHost = "login.microsoftonline.com"
|
||||
autoDetectRegion = "TryAutoDetect"
|
||||
)
|
||||
|
||||
// These are various hosts that host AAD Instance discovery endpoints.
|
||||
const (
|
||||
defaultHost = "login.microsoftonline.com"
|
||||
loginMicrosoft = "login.microsoft.com"
|
||||
loginWindows = "login.windows.net"
|
||||
loginSTSWindows = "sts.windows.net"
|
||||
loginMicrosoftOnline = defaultHost
|
||||
)
|
||||
|
||||
// jsonCaller is an interface that allows us to mock the JSONCall method.
|
||||
type jsonCaller interface {
|
||||
JSONCall(ctx context.Context, endpoint string, headers http.Header, qv url.Values, body, resp interface{}) error
|
||||
}
|
||||
@@ -54,6 +63,8 @@ func TrustedHost(host string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// OAuthResponseBase is the base JSON return message for an OAuth call.
|
||||
// This is embedded in other calls to get the base fields from every response.
|
||||
type OAuthResponseBase struct {
|
||||
Error string `json:"error"`
|
||||
SubError string `json:"suberror"`
|
||||
@@ -309,31 +320,24 @@ func firstPathSegment(u *url.URL) (string, error) {
|
||||
return pathParts[1], nil
|
||||
}
|
||||
|
||||
return "", errors.New("authority does not have two segments")
|
||||
return "", errors.New(`authority must be an https URL such as "https://login.microsoftonline.com/<your tenant>"`)
|
||||
}
|
||||
|
||||
// NewInfoFromAuthorityURI creates an AuthorityInfo instance from the authority URL provided.
|
||||
func NewInfoFromAuthorityURI(authorityURI string, validateAuthority bool, instanceDiscoveryDisabled bool) (Info, error) {
|
||||
authorityURI = strings.ToLower(authorityURI)
|
||||
var authorityType string
|
||||
u, err := url.Parse(authorityURI)
|
||||
if err != nil {
|
||||
return Info{}, fmt.Errorf("authorityURI passed could not be parsed: %w", err)
|
||||
}
|
||||
if u.Scheme != "https" {
|
||||
return Info{}, fmt.Errorf("authorityURI(%s) must have scheme https", authorityURI)
|
||||
func NewInfoFromAuthorityURI(authority string, validateAuthority bool, instanceDiscoveryDisabled bool) (Info, error) {
|
||||
u, err := url.Parse(strings.ToLower(authority))
|
||||
if err != nil || u.Scheme != "https" {
|
||||
return Info{}, errors.New(`authority must be an https URL such as "https://login.microsoftonline.com/<your tenant>"`)
|
||||
}
|
||||
|
||||
tenant, err := firstPathSegment(u)
|
||||
if tenant == "adfs" {
|
||||
authorityType = ADFS
|
||||
} else {
|
||||
authorityType = AAD
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return Info{}, err
|
||||
}
|
||||
authorityType := AAD
|
||||
if tenant == "adfs" {
|
||||
authorityType = ADFS
|
||||
}
|
||||
|
||||
// u.Host includes the port, if any, which is required for private cloud deployments
|
||||
return Info{
|
||||
@@ -449,6 +453,8 @@ func (c Client) GetTenantDiscoveryResponse(ctx context.Context, openIDConfigurat
|
||||
return resp, err
|
||||
}
|
||||
|
||||
// AADInstanceDiscovery attempts to discover a tenant endpoint (used in OIDC auth with an authorization endpoint).
|
||||
// This is done by AAD which allows for aliasing of tenants (windows.sts.net is the same as login.windows.com).
|
||||
func (c Client) AADInstanceDiscovery(ctx context.Context, authorityInfo Info) (InstanceDiscoveryResponse, error) {
|
||||
region := ""
|
||||
var err error
|
||||
@@ -461,9 +467,10 @@ func (c Client) AADInstanceDiscovery(ctx context.Context, authorityInfo Info) (I
|
||||
if region != "" {
|
||||
environment := authorityInfo.Host
|
||||
switch environment {
|
||||
case "login.microsoft.com", "login.windows.net", "sts.windows.net", defaultHost:
|
||||
environment = "r." + defaultHost
|
||||
case loginMicrosoft, loginWindows, loginSTSWindows, defaultHost:
|
||||
environment = loginMicrosoft
|
||||
}
|
||||
|
||||
resp.TenantDiscoveryEndpoint = fmt.Sprintf(tenantDiscoveryEndpointWithRegion, region, environment, authorityInfo.Tenant)
|
||||
metadata := InstanceDiscoveryMetadata{
|
||||
PreferredNetwork: fmt.Sprintf("%v.%v", region, authorityInfo.Host),
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
package version
|
||||
|
||||
// Version is the version of this client package that is communicated to the server.
|
||||
const Version = "0.8.1"
|
||||
const Version = "1.0.0"
|
||||
|
||||
189
vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/public/public.go
generated
vendored
189
vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/public/public.go
generated
vendored
@@ -47,27 +47,17 @@ type AuthResult = base.AuthResult
|
||||
|
||||
type Account = shared.Account
|
||||
|
||||
// Options configures the Client's behavior.
|
||||
type Options struct {
|
||||
// Accessor controls cache persistence. By default there is no cache persistence.
|
||||
// This can be set with the WithCache() option.
|
||||
Accessor cache.ExportReplace
|
||||
|
||||
// The host of the Azure Active Directory authority. The default is https://login.microsoftonline.com/common.
|
||||
// This can be changed with the WithAuthority() option.
|
||||
Authority string
|
||||
|
||||
// The HTTP client used for making requests.
|
||||
// It defaults to a shared http.Client.
|
||||
HTTPClient ops.HTTPClient
|
||||
|
||||
capabilities []string
|
||||
|
||||
// clientOptions configures the Client's behavior.
|
||||
type clientOptions struct {
|
||||
accessor cache.ExportReplace
|
||||
authority string
|
||||
capabilities []string
|
||||
disableInstanceDiscovery bool
|
||||
httpClient ops.HTTPClient
|
||||
}
|
||||
|
||||
func (p *Options) validate() error {
|
||||
u, err := url.Parse(p.Authority)
|
||||
func (p *clientOptions) validate() error {
|
||||
u, err := url.Parse(p.authority)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Authority options cannot be URL parsed: %w", err)
|
||||
}
|
||||
@@ -78,25 +68,25 @@ func (p *Options) validate() error {
|
||||
}
|
||||
|
||||
// Option is an optional argument to the New constructor.
|
||||
type Option func(o *Options)
|
||||
type Option func(o *clientOptions)
|
||||
|
||||
// WithAuthority allows for a custom authority to be set. This must be a valid https url.
|
||||
func WithAuthority(authority string) Option {
|
||||
return func(o *Options) {
|
||||
o.Authority = authority
|
||||
return func(o *clientOptions) {
|
||||
o.authority = authority
|
||||
}
|
||||
}
|
||||
|
||||
// WithCache allows you to set some type of cache for storing authentication tokens.
|
||||
// WithCache provides an accessor that will read and write authentication data to an externally managed cache.
|
||||
func WithCache(accessor cache.ExportReplace) Option {
|
||||
return func(o *Options) {
|
||||
o.Accessor = accessor
|
||||
return func(o *clientOptions) {
|
||||
o.accessor = accessor
|
||||
}
|
||||
}
|
||||
|
||||
// WithClientCapabilities allows configuring one or more client capabilities such as "CP1"
|
||||
func WithClientCapabilities(capabilities []string) Option {
|
||||
return func(o *Options) {
|
||||
return func(o *clientOptions) {
|
||||
// there's no danger of sharing the slice's underlying memory with the application because
|
||||
// this slice is simply passed to base.WithClientCapabilities, which copies its data
|
||||
o.capabilities = capabilities
|
||||
@@ -105,14 +95,14 @@ func WithClientCapabilities(capabilities []string) Option {
|
||||
|
||||
// WithHTTPClient allows for a custom HTTP client to be set.
|
||||
func WithHTTPClient(httpClient ops.HTTPClient) Option {
|
||||
return func(o *Options) {
|
||||
o.HTTPClient = httpClient
|
||||
return func(o *clientOptions) {
|
||||
o.httpClient = httpClient
|
||||
}
|
||||
}
|
||||
|
||||
// WithInstanceDiscovery set to false to disable authority validation (to support private cloud scenarios)
|
||||
func WithInstanceDiscovery(enabled bool) Option {
|
||||
return func(o *Options) {
|
||||
return func(o *clientOptions) {
|
||||
o.disableInstanceDiscovery = !enabled
|
||||
}
|
||||
}
|
||||
@@ -125,9 +115,9 @@ type Client struct {
|
||||
|
||||
// New is the constructor for Client.
|
||||
func New(clientID string, options ...Option) (Client, error) {
|
||||
opts := Options{
|
||||
Authority: base.AuthorityPublicCloud,
|
||||
HTTPClient: shared.DefaultClient,
|
||||
opts := clientOptions{
|
||||
authority: base.AuthorityPublicCloud,
|
||||
httpClient: shared.DefaultClient,
|
||||
}
|
||||
|
||||
for _, o := range options {
|
||||
@@ -137,28 +127,28 @@ func New(clientID string, options ...Option) (Client, error) {
|
||||
return Client{}, err
|
||||
}
|
||||
|
||||
base, err := base.New(clientID, opts.Authority, oauth.New(opts.HTTPClient), base.WithCacheAccessor(opts.Accessor), base.WithClientCapabilities(opts.capabilities), base.WithInstanceDiscovery(!opts.disableInstanceDiscovery))
|
||||
base, err := base.New(clientID, opts.authority, oauth.New(opts.httpClient), base.WithCacheAccessor(opts.accessor), base.WithClientCapabilities(opts.capabilities), base.WithInstanceDiscovery(!opts.disableInstanceDiscovery))
|
||||
if err != nil {
|
||||
return Client{}, err
|
||||
}
|
||||
return Client{base}, nil
|
||||
}
|
||||
|
||||
// createAuthCodeURLOptions contains options for CreateAuthCodeURL
|
||||
type createAuthCodeURLOptions struct {
|
||||
// authCodeURLOptions contains options for AuthCodeURL
|
||||
type authCodeURLOptions struct {
|
||||
claims, loginHint, tenantID, domainHint string
|
||||
}
|
||||
|
||||
// CreateAuthCodeURLOption is implemented by options for CreateAuthCodeURL
|
||||
type CreateAuthCodeURLOption interface {
|
||||
createAuthCodeURLOption()
|
||||
// AuthCodeURLOption is implemented by options for AuthCodeURL
|
||||
type AuthCodeURLOption interface {
|
||||
authCodeURLOption()
|
||||
}
|
||||
|
||||
// CreateAuthCodeURL creates a URL used to acquire an authorization code.
|
||||
// AuthCodeURL creates a URL used to acquire an authorization code.
|
||||
//
|
||||
// Options: [WithClaims], [WithDomainHint], [WithLoginHint], [WithTenantID]
|
||||
func (pca Client) CreateAuthCodeURL(ctx context.Context, clientID, redirectURI string, scopes []string, opts ...CreateAuthCodeURLOption) (string, error) {
|
||||
o := createAuthCodeURLOptions{}
|
||||
func (pca Client) AuthCodeURL(ctx context.Context, clientID, redirectURI string, scopes []string, opts ...AuthCodeURLOption) (string, error) {
|
||||
o := authCodeURLOptions{}
|
||||
if err := options.ApplyOptions(&o, opts); err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -181,7 +171,7 @@ func WithClaims(claims string) interface {
|
||||
AcquireByUsernamePasswordOption
|
||||
AcquireInteractiveOption
|
||||
AcquireSilentOption
|
||||
CreateAuthCodeURLOption
|
||||
AuthCodeURLOption
|
||||
options.CallOption
|
||||
} {
|
||||
return struct {
|
||||
@@ -190,23 +180,23 @@ func WithClaims(claims string) interface {
|
||||
AcquireByUsernamePasswordOption
|
||||
AcquireInteractiveOption
|
||||
AcquireSilentOption
|
||||
CreateAuthCodeURLOption
|
||||
AuthCodeURLOption
|
||||
options.CallOption
|
||||
}{
|
||||
CallOption: options.NewCallOption(
|
||||
func(a any) error {
|
||||
switch t := a.(type) {
|
||||
case *AcquireTokenByAuthCodeOptions:
|
||||
case *acquireTokenByAuthCodeOptions:
|
||||
t.claims = claims
|
||||
case *acquireTokenByDeviceCodeOptions:
|
||||
t.claims = claims
|
||||
case *acquireTokenByUsernamePasswordOptions:
|
||||
t.claims = claims
|
||||
case *AcquireTokenSilentOptions:
|
||||
case *acquireTokenSilentOptions:
|
||||
t.claims = claims
|
||||
case *createAuthCodeURLOptions:
|
||||
case *authCodeURLOptions:
|
||||
t.claims = claims
|
||||
case *InteractiveAuthOptions:
|
||||
case *interactiveAuthOptions:
|
||||
t.claims = claims
|
||||
default:
|
||||
return fmt.Errorf("unexpected options type %T", a)
|
||||
@@ -225,7 +215,7 @@ func WithTenantID(tenantID string) interface {
|
||||
AcquireByUsernamePasswordOption
|
||||
AcquireInteractiveOption
|
||||
AcquireSilentOption
|
||||
CreateAuthCodeURLOption
|
||||
AuthCodeURLOption
|
||||
options.CallOption
|
||||
} {
|
||||
return struct {
|
||||
@@ -234,23 +224,23 @@ func WithTenantID(tenantID string) interface {
|
||||
AcquireByUsernamePasswordOption
|
||||
AcquireInteractiveOption
|
||||
AcquireSilentOption
|
||||
CreateAuthCodeURLOption
|
||||
AuthCodeURLOption
|
||||
options.CallOption
|
||||
}{
|
||||
CallOption: options.NewCallOption(
|
||||
func(a any) error {
|
||||
switch t := a.(type) {
|
||||
case *AcquireTokenByAuthCodeOptions:
|
||||
case *acquireTokenByAuthCodeOptions:
|
||||
t.tenantID = tenantID
|
||||
case *acquireTokenByDeviceCodeOptions:
|
||||
t.tenantID = tenantID
|
||||
case *acquireTokenByUsernamePasswordOptions:
|
||||
t.tenantID = tenantID
|
||||
case *AcquireTokenSilentOptions:
|
||||
case *acquireTokenSilentOptions:
|
||||
t.tenantID = tenantID
|
||||
case *createAuthCodeURLOptions:
|
||||
case *authCodeURLOptions:
|
||||
t.tenantID = tenantID
|
||||
case *InteractiveAuthOptions:
|
||||
case *interactiveAuthOptions:
|
||||
t.tenantID = tenantID
|
||||
default:
|
||||
return fmt.Errorf("unexpected options type %T", a)
|
||||
@@ -261,12 +251,10 @@ func WithTenantID(tenantID string) interface {
|
||||
}
|
||||
}
|
||||
|
||||
// AcquireTokenSilentOptions are all the optional settings to an AcquireTokenSilent() call.
|
||||
// acquireTokenSilentOptions are all the optional settings to an AcquireTokenSilent() call.
|
||||
// These are set by using various AcquireTokenSilentOption functions.
|
||||
type AcquireTokenSilentOptions struct {
|
||||
// Account represents the account to use. To set, use the WithSilentAccount() option.
|
||||
Account Account
|
||||
|
||||
type acquireTokenSilentOptions struct {
|
||||
account Account
|
||||
claims, tenantID string
|
||||
}
|
||||
|
||||
@@ -275,11 +263,6 @@ type AcquireSilentOption interface {
|
||||
acquireSilentOption()
|
||||
}
|
||||
|
||||
// AcquireTokenSilentOption changes options inside AcquireTokenSilentOptions used in .AcquireTokenSilent().
|
||||
type AcquireTokenSilentOption func(a *AcquireTokenSilentOptions)
|
||||
|
||||
func (AcquireTokenSilentOption) acquireSilentOption() {}
|
||||
|
||||
// WithSilentAccount uses the passed account during an AcquireTokenSilent() call.
|
||||
func WithSilentAccount(account Account) interface {
|
||||
AcquireSilentOption
|
||||
@@ -292,8 +275,8 @@ func WithSilentAccount(account Account) interface {
|
||||
CallOption: options.NewCallOption(
|
||||
func(a any) error {
|
||||
switch t := a.(type) {
|
||||
case *AcquireTokenSilentOptions:
|
||||
t.Account = account
|
||||
case *acquireTokenSilentOptions:
|
||||
t.account = account
|
||||
default:
|
||||
return fmt.Errorf("unexpected options type %T", a)
|
||||
}
|
||||
@@ -307,14 +290,14 @@ func WithSilentAccount(account Account) interface {
|
||||
//
|
||||
// Options: [WithClaims], [WithSilentAccount], [WithTenantID]
|
||||
func (pca Client) AcquireTokenSilent(ctx context.Context, scopes []string, opts ...AcquireSilentOption) (AuthResult, error) {
|
||||
o := AcquireTokenSilentOptions{}
|
||||
o := acquireTokenSilentOptions{}
|
||||
if err := options.ApplyOptions(&o, opts); err != nil {
|
||||
return AuthResult{}, err
|
||||
}
|
||||
|
||||
silentParameters := base.AcquireTokenSilentParameters{
|
||||
Scopes: scopes,
|
||||
Account: o.Account,
|
||||
Account: o.account,
|
||||
Claims: o.claims,
|
||||
RequestType: accesstokens.ATPublic,
|
||||
IsAppCache: false,
|
||||
@@ -420,11 +403,9 @@ func (pca Client) AcquireTokenByDeviceCode(ctx context.Context, scopes []string,
|
||||
return DeviceCode{Result: dc.Result, authParams: authParams, client: pca, dc: dc}, nil
|
||||
}
|
||||
|
||||
// AcquireTokenByAuthCodeOptions contains the optional parameters used to acquire an access token using the authorization code flow.
|
||||
type AcquireTokenByAuthCodeOptions struct {
|
||||
Challenge string
|
||||
|
||||
claims, tenantID string
|
||||
// acquireTokenByAuthCodeOptions contains the optional parameters used to acquire an access token using the authorization code flow.
|
||||
type acquireTokenByAuthCodeOptions struct {
|
||||
challenge, claims, tenantID string
|
||||
}
|
||||
|
||||
// AcquireByAuthCodeOption is implemented by options for AcquireTokenByAuthCode
|
||||
@@ -432,11 +413,6 @@ type AcquireByAuthCodeOption interface {
|
||||
acquireByAuthCodeOption()
|
||||
}
|
||||
|
||||
// AcquireTokenByAuthCodeOption changes options inside AcquireTokenByAuthCodeOptions used in .AcquireTokenByAuthCode().
|
||||
type AcquireTokenByAuthCodeOption func(a *AcquireTokenByAuthCodeOptions)
|
||||
|
||||
func (AcquireTokenByAuthCodeOption) acquireByAuthCodeOption() {}
|
||||
|
||||
// WithChallenge allows you to provide a code for the .AcquireTokenByAuthCode() call.
|
||||
func WithChallenge(challenge string) interface {
|
||||
AcquireByAuthCodeOption
|
||||
@@ -449,8 +425,8 @@ func WithChallenge(challenge string) interface {
|
||||
CallOption: options.NewCallOption(
|
||||
func(a any) error {
|
||||
switch t := a.(type) {
|
||||
case *AcquireTokenByAuthCodeOptions:
|
||||
t.Challenge = challenge
|
||||
case *acquireTokenByAuthCodeOptions:
|
||||
t.challenge = challenge
|
||||
default:
|
||||
return fmt.Errorf("unexpected options type %T", a)
|
||||
}
|
||||
@@ -465,7 +441,7 @@ func WithChallenge(challenge string) interface {
|
||||
//
|
||||
// Options: [WithChallenge], [WithClaims], [WithTenantID]
|
||||
func (pca Client) AcquireTokenByAuthCode(ctx context.Context, code string, redirectURI string, scopes []string, opts ...AcquireByAuthCodeOption) (AuthResult, error) {
|
||||
o := AcquireTokenByAuthCodeOptions{}
|
||||
o := acquireTokenByAuthCodeOptions{}
|
||||
if err := options.ApplyOptions(&o, opts); err != nil {
|
||||
return AuthResult{}, err
|
||||
}
|
||||
@@ -473,7 +449,7 @@ func (pca Client) AcquireTokenByAuthCode(ctx context.Context, code string, redir
|
||||
params := base.AcquireTokenAuthCodeParameters{
|
||||
Scopes: scopes,
|
||||
Code: code,
|
||||
Challenge: o.Challenge,
|
||||
Challenge: o.challenge,
|
||||
Claims: o.claims,
|
||||
AppType: accesstokens.ATPublic,
|
||||
RedirectURI: redirectURI,
|
||||
@@ -485,23 +461,18 @@ func (pca Client) AcquireTokenByAuthCode(ctx context.Context, code string, redir
|
||||
|
||||
// Accounts gets all the accounts in the token cache.
|
||||
// If there are no accounts in the cache the returned slice is empty.
|
||||
func (pca Client) Accounts() []Account {
|
||||
return pca.base.AllAccounts()
|
||||
func (pca Client) Accounts(ctx context.Context) ([]Account, error) {
|
||||
return pca.base.AllAccounts(ctx)
|
||||
}
|
||||
|
||||
// RemoveAccount signs the account out and forgets account from token cache.
|
||||
func (pca Client) RemoveAccount(account Account) error {
|
||||
pca.base.RemoveAccount(account)
|
||||
return nil
|
||||
func (pca Client) RemoveAccount(ctx context.Context, account Account) error {
|
||||
return pca.base.RemoveAccount(ctx, account)
|
||||
}
|
||||
|
||||
// InteractiveAuthOptions contains the optional parameters used to acquire an access token for interactive auth code flow.
|
||||
type InteractiveAuthOptions struct {
|
||||
// Used to specify a custom port for the local server. http://localhost:portnumber
|
||||
// All other URI components are ignored.
|
||||
RedirectURI string
|
||||
|
||||
claims, loginHint, tenantID, domainHint string
|
||||
// interactiveAuthOptions contains the optional parameters used to acquire an access token for interactive auth code flow.
|
||||
type interactiveAuthOptions struct {
|
||||
claims, domainHint, loginHint, redirectURI, tenantID string
|
||||
}
|
||||
|
||||
// AcquireInteractiveOption is implemented by options for AcquireTokenInteractive
|
||||
@@ -509,28 +480,23 @@ type AcquireInteractiveOption interface {
|
||||
acquireInteractiveOption()
|
||||
}
|
||||
|
||||
// InteractiveAuthOption changes options inside InteractiveAuthOptions used in .AcquireTokenInteractive().
|
||||
type InteractiveAuthOption func(*InteractiveAuthOptions)
|
||||
|
||||
func (InteractiveAuthOption) acquireInteractiveOption() {}
|
||||
|
||||
// WithLoginHint pre-populates the login prompt with a username.
|
||||
func WithLoginHint(username string) interface {
|
||||
AcquireInteractiveOption
|
||||
CreateAuthCodeURLOption
|
||||
AuthCodeURLOption
|
||||
options.CallOption
|
||||
} {
|
||||
return struct {
|
||||
AcquireInteractiveOption
|
||||
CreateAuthCodeURLOption
|
||||
AuthCodeURLOption
|
||||
options.CallOption
|
||||
}{
|
||||
CallOption: options.NewCallOption(
|
||||
func(a any) error {
|
||||
switch t := a.(type) {
|
||||
case *createAuthCodeURLOptions:
|
||||
case *authCodeURLOptions:
|
||||
t.loginHint = username
|
||||
case *InteractiveAuthOptions:
|
||||
case *interactiveAuthOptions:
|
||||
t.loginHint = username
|
||||
default:
|
||||
return fmt.Errorf("unexpected options type %T", a)
|
||||
@@ -544,20 +510,20 @@ func WithLoginHint(username string) interface {
|
||||
// WithDomainHint adds the IdP domain as domain_hint query parameter in the auth url.
|
||||
func WithDomainHint(domain string) interface {
|
||||
AcquireInteractiveOption
|
||||
CreateAuthCodeURLOption
|
||||
AuthCodeURLOption
|
||||
options.CallOption
|
||||
} {
|
||||
return struct {
|
||||
AcquireInteractiveOption
|
||||
CreateAuthCodeURLOption
|
||||
AuthCodeURLOption
|
||||
options.CallOption
|
||||
}{
|
||||
CallOption: options.NewCallOption(
|
||||
func(a any) error {
|
||||
switch t := a.(type) {
|
||||
case *createAuthCodeURLOptions:
|
||||
case *authCodeURLOptions:
|
||||
t.domainHint = domain
|
||||
case *InteractiveAuthOptions:
|
||||
case *interactiveAuthOptions:
|
||||
t.domainHint = domain
|
||||
default:
|
||||
return fmt.Errorf("unexpected options type %T", a)
|
||||
@@ -568,7 +534,8 @@ func WithDomainHint(domain string) interface {
|
||||
}
|
||||
}
|
||||
|
||||
// WithRedirectURI uses the specified redirect URI for interactive auth.
|
||||
// WithRedirectURI sets a port for the local server used in interactive authentication, for
|
||||
// example http://localhost:port. All URI components other than the port are ignored.
|
||||
func WithRedirectURI(redirectURI string) interface {
|
||||
AcquireInteractiveOption
|
||||
options.CallOption
|
||||
@@ -580,8 +547,8 @@ func WithRedirectURI(redirectURI string) interface {
|
||||
CallOption: options.NewCallOption(
|
||||
func(a any) error {
|
||||
switch t := a.(type) {
|
||||
case *InteractiveAuthOptions:
|
||||
t.RedirectURI = redirectURI
|
||||
case *interactiveAuthOptions:
|
||||
t.redirectURI = redirectURI
|
||||
default:
|
||||
return fmt.Errorf("unexpected options type %T", a)
|
||||
}
|
||||
@@ -596,7 +563,7 @@ func WithRedirectURI(redirectURI string) interface {
|
||||
//
|
||||
// Options: [WithDomainHint], [WithLoginHint], [WithRedirectURI], [WithTenantID]
|
||||
func (pca Client) AcquireTokenInteractive(ctx context.Context, scopes []string, opts ...AcquireInteractiveOption) (AuthResult, error) {
|
||||
o := InteractiveAuthOptions{}
|
||||
o := interactiveAuthOptions{}
|
||||
if err := options.ApplyOptions(&o, opts); err != nil {
|
||||
return AuthResult{}, err
|
||||
}
|
||||
@@ -607,8 +574,8 @@ func (pca Client) AcquireTokenInteractive(ctx context.Context, scopes []string,
|
||||
return AuthResult{}, err
|
||||
}
|
||||
var redirectURL *url.URL
|
||||
if o.RedirectURI != "" {
|
||||
redirectURL, err = url.Parse(o.RedirectURI)
|
||||
if o.redirectURI != "" {
|
||||
redirectURL, err = url.Parse(o.redirectURI)
|
||||
if err != nil {
|
||||
return AuthResult{}, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user