mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-14 18:53:35 +00:00
rebase: bump the github-dependencies group with 3 updates
Bumps the github-dependencies group with 3 updates: [github.com/Azure/azure-sdk-for-go/sdk/azidentity](https://github.com/Azure/azure-sdk-for-go), [github.com/aws/aws-sdk-go-v2/service/sts](https://github.com/aws/aws-sdk-go-v2) and [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang). Updates `github.com/Azure/azure-sdk-for-go/sdk/azidentity` from 1.8.2 to 1.9.0 - [Release notes](https://github.com/Azure/azure-sdk-for-go/releases) - [Changelog](https://github.com/Azure/azure-sdk-for-go/blob/main/documentation/release.md) - [Commits](https://github.com/Azure/azure-sdk-for-go/compare/sdk/azidentity/v1.8.2...sdk/azcore/v1.9.0) Updates `github.com/aws/aws-sdk-go-v2/service/sts` from 1.33.18 to 1.33.19 - [Release notes](https://github.com/aws/aws-sdk-go-v2/releases) - [Changelog](https://github.com/aws/aws-sdk-go-v2/blob/main/changelog-template.json) - [Commits](https://github.com/aws/aws-sdk-go-v2/compare/service/sns/v1.33.18...service/sns/v1.33.19) Updates `github.com/prometheus/client_golang` from 1.21.1 to 1.22.0 - [Release notes](https://github.com/prometheus/client_golang/releases) - [Changelog](https://github.com/prometheus/client_golang/blob/main/CHANGELOG.md) - [Commits](https://github.com/prometheus/client_golang/compare/v1.21.1...v1.22.0) --- updated-dependencies: - dependency-name: github.com/Azure/azure-sdk-for-go/sdk/azidentity dependency-version: 1.9.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-dependencies - dependency-name: github.com/aws/aws-sdk-go-v2/service/sts dependency-version: 1.33.19 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-dependencies - dependency-name: github.com/prometheus/client_golang dependency-version: 1.22.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-dependencies ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
committed by
mergify[bot]
parent
0b811ff8b1
commit
72c19ab743
@ -5,16 +5,17 @@ package base
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/AzureAD/microsoft-authentication-library-for-go/apps/cache"
|
||||
"github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/internal/storage"
|
||||
"github.com/AzureAD/microsoft-authentication-library-for-go/apps/errors"
|
||||
"github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/base/storage"
|
||||
"github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth"
|
||||
"github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens"
|
||||
"github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/authority"
|
||||
@ -94,6 +95,7 @@ type AuthResult struct {
|
||||
|
||||
// AuthResultMetadata which contains meta data for the AuthResult
|
||||
type AuthResultMetadata struct {
|
||||
RefreshOn time.Time
|
||||
TokenSource TokenSource
|
||||
}
|
||||
|
||||
@ -101,9 +103,8 @@ type TokenSource int
|
||||
|
||||
// These are all the types of token flows.
|
||||
const (
|
||||
SourceUnknown TokenSource = 0
|
||||
IdentityProvider TokenSource = 1
|
||||
Cache TokenSource = 2
|
||||
TokenSourceIdentityProvider TokenSource = 0
|
||||
TokenSourceCache TokenSource = 1
|
||||
)
|
||||
|
||||
// AuthResultFromStorage creates an AuthResult from a storage token response (which is generated from the cache).
|
||||
@ -111,7 +112,6 @@ func AuthResultFromStorage(storageTokenResponse storage.TokenResponse) (AuthResu
|
||||
if err := storageTokenResponse.AccessToken.Validate(); err != nil {
|
||||
return AuthResult{}, fmt.Errorf("problem with access token in StorageTokenResponse: %w", err)
|
||||
}
|
||||
|
||||
account := storageTokenResponse.Account
|
||||
accessToken := storageTokenResponse.AccessToken.Secret
|
||||
grantedScopes := strings.Split(storageTokenResponse.AccessToken.Scopes, scopeSeparator)
|
||||
@ -132,7 +132,8 @@ func AuthResultFromStorage(storageTokenResponse storage.TokenResponse) (AuthResu
|
||||
GrantedScopes: grantedScopes,
|
||||
DeclinedScopes: nil,
|
||||
Metadata: AuthResultMetadata{
|
||||
TokenSource: Cache,
|
||||
TokenSource: TokenSourceCache,
|
||||
RefreshOn: storageTokenResponse.AccessToken.RefreshOn.T,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
@ -146,10 +147,11 @@ func NewAuthResult(tokenResponse accesstokens.TokenResponse, account shared.Acco
|
||||
Account: account,
|
||||
IDToken: tokenResponse.IDToken,
|
||||
AccessToken: tokenResponse.AccessToken,
|
||||
ExpiresOn: tokenResponse.ExpiresOn.T,
|
||||
ExpiresOn: tokenResponse.ExpiresOn,
|
||||
GrantedScopes: tokenResponse.GrantedScopes.Slice,
|
||||
Metadata: AuthResultMetadata{
|
||||
TokenSource: IdentityProvider,
|
||||
TokenSource: TokenSourceIdentityProvider,
|
||||
RefreshOn: tokenResponse.RefreshOn.T,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
@ -165,6 +167,8 @@ type Client struct {
|
||||
AuthParams authority.AuthParams // DO NOT EVER MAKE THIS A POINTER! See "Note" in New().
|
||||
cacheAccessor cache.ExportReplace
|
||||
cacheAccessorMu *sync.RWMutex
|
||||
canRefresh map[string]*atomic.Value
|
||||
canRefreshMu *sync.Mutex
|
||||
}
|
||||
|
||||
// Option is an optional argument to the New constructor.
|
||||
@ -241,6 +245,8 @@ func New(clientID string, authorityURI string, token *oauth.Client, options ...O
|
||||
cacheAccessorMu: &sync.RWMutex{},
|
||||
manager: storage.New(token),
|
||||
pmanager: storage.NewPartitionedManager(token),
|
||||
canRefresh: make(map[string]*atomic.Value),
|
||||
canRefreshMu: &sync.Mutex{},
|
||||
}
|
||||
for _, o := range options {
|
||||
if err = o(&client); err != nil {
|
||||
@ -345,6 +351,28 @@ func (b Client) AcquireTokenSilent(ctx context.Context, silent AcquireTokenSilen
|
||||
if silent.Claims == "" {
|
||||
ar, err = AuthResultFromStorage(storageTokenResponse)
|
||||
if err == nil {
|
||||
if rt := storageTokenResponse.AccessToken.RefreshOn.T; !rt.IsZero() && Now().After(rt) {
|
||||
b.canRefreshMu.Lock()
|
||||
refreshValue, ok := b.canRefresh[tenant]
|
||||
if !ok {
|
||||
refreshValue = &atomic.Value{}
|
||||
refreshValue.Store(false)
|
||||
b.canRefresh[tenant] = refreshValue
|
||||
}
|
||||
b.canRefreshMu.Unlock()
|
||||
if refreshValue.CompareAndSwap(false, true) {
|
||||
defer refreshValue.Store(false)
|
||||
// Added a check to see if the token is still same because there is a chance
|
||||
// that the token is already refreshed by another thread.
|
||||
// If the token is not same, we don't need to refresh it.
|
||||
// Which means it refreshed.
|
||||
if str, err := m.Read(ctx, authParams); err == nil && str.AccessToken.Secret == ar.AccessToken {
|
||||
if tr, er := b.Token.Credential(ctx, authParams, silent.Credential); er == nil {
|
||||
return b.AuthResultFromToken(ctx, authParams, tr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ar.AccessToken, err = authParams.AuthnScheme.FormatAccessToken(ar.AccessToken)
|
||||
return ar, err
|
||||
}
|
||||
@ -362,7 +390,7 @@ func (b Client) AcquireTokenSilent(ctx context.Context, silent AcquireTokenSilen
|
||||
if err != nil {
|
||||
return ar, err
|
||||
}
|
||||
return b.AuthResultFromToken(ctx, authParams, token, true)
|
||||
return b.AuthResultFromToken(ctx, authParams, token)
|
||||
}
|
||||
|
||||
func (b Client) AcquireTokenByAuthCode(ctx context.Context, authCodeParams AcquireTokenAuthCodeParameters) (AuthResult, error) {
|
||||
@ -391,7 +419,7 @@ func (b Client) AcquireTokenByAuthCode(ctx context.Context, authCodeParams Acqui
|
||||
return AuthResult{}, err
|
||||
}
|
||||
|
||||
return b.AuthResultFromToken(ctx, authParams, token, true)
|
||||
return b.AuthResultFromToken(ctx, authParams, token)
|
||||
}
|
||||
|
||||
// AcquireTokenOnBehalfOf acquires a security token for an app using middle tier apps access token.
|
||||
@ -420,15 +448,12 @@ func (b Client) AcquireTokenOnBehalfOf(ctx context.Context, onBehalfOfParams Acq
|
||||
authParams.UserAssertion = onBehalfOfParams.UserAssertion
|
||||
token, err := b.Token.OnBehalfOf(ctx, authParams, onBehalfOfParams.Credential)
|
||||
if err == nil {
|
||||
ar, err = b.AuthResultFromToken(ctx, authParams, token, true)
|
||||
ar, err = b.AuthResultFromToken(ctx, authParams, token)
|
||||
}
|
||||
return ar, err
|
||||
}
|
||||
|
||||
func (b Client) AuthResultFromToken(ctx context.Context, authParams authority.AuthParams, token accesstokens.TokenResponse, cacheWrite bool) (AuthResult, error) {
|
||||
if !cacheWrite {
|
||||
return NewAuthResult(token, shared.Account{})
|
||||
}
|
||||
func (b Client) AuthResultFromToken(ctx context.Context, authParams authority.AuthParams, token accesstokens.TokenResponse) (AuthResult, error) {
|
||||
var m manager = b.manager
|
||||
if authParams.AuthorizationType == authority.ATOnBehalfOf {
|
||||
m = b.pmanager
|
||||
@ -458,6 +483,10 @@ func (b Client) AuthResultFromToken(ctx context.Context, authParams authority.Au
|
||||
return ar, err
|
||||
}
|
||||
|
||||
// This function wraps time.Now() and is used for refreshing the application
|
||||
// was created to test the function against refreshin
|
||||
var Now = time.Now
|
||||
|
||||
func (b Client) AllAccounts(ctx context.Context) ([]shared.Account, error) {
|
||||
if b.cacheAccessor != nil {
|
||||
b.cacheAccessorMu.RLock()
|
||||
|
@ -72,6 +72,7 @@ type AccessToken struct {
|
||||
ClientID string `json:"client_id,omitempty"`
|
||||
Secret string `json:"secret,omitempty"`
|
||||
Scopes string `json:"target,omitempty"`
|
||||
RefreshOn internalTime.Unix `json:"refresh_on,omitempty"`
|
||||
ExpiresOn internalTime.Unix `json:"expires_on,omitempty"`
|
||||
ExtendedExpiresOn internalTime.Unix `json:"extended_expires_on,omitempty"`
|
||||
CachedAt internalTime.Unix `json:"cached_at,omitempty"`
|
||||
@ -83,7 +84,7 @@ type AccessToken struct {
|
||||
}
|
||||
|
||||
// NewAccessToken is the constructor for AccessToken.
|
||||
func NewAccessToken(homeID, env, realm, clientID string, cachedAt, expiresOn, extendedExpiresOn time.Time, scopes, token, tokenType, authnSchemeKeyID string) AccessToken {
|
||||
func NewAccessToken(homeID, env, realm, clientID string, cachedAt, refreshOn, expiresOn, extendedExpiresOn time.Time, scopes, token, tokenType, authnSchemeKeyID string) AccessToken {
|
||||
return AccessToken{
|
||||
HomeAccountID: homeID,
|
||||
Environment: env,
|
||||
@ -93,6 +94,7 @@ func NewAccessToken(homeID, env, realm, clientID string, cachedAt, expiresOn, ex
|
||||
Secret: token,
|
||||
Scopes: scopes,
|
||||
CachedAt: internalTime.Unix{T: cachedAt.UTC()},
|
||||
RefreshOn: internalTime.Unix{T: refreshOn.UTC()},
|
||||
ExpiresOn: internalTime.Unix{T: expiresOn.UTC()},
|
||||
ExtendedExpiresOn: internalTime.Unix{T: extendedExpiresOn.UTC()},
|
||||
TokenType: tokenType,
|
||||
@ -102,8 +104,9 @@ func NewAccessToken(homeID, env, realm, clientID string, cachedAt, expiresOn, ex
|
||||
|
||||
// Key outputs the key that can be used to uniquely look up this entry in a map.
|
||||
func (a AccessToken) Key() string {
|
||||
ks := []string{a.HomeAccountID, a.Environment, a.CredentialType, a.ClientID, a.Realm, a.Scopes}
|
||||
key := strings.Join(
|
||||
[]string{a.HomeAccountID, a.Environment, a.CredentialType, a.ClientID, a.Realm, a.Scopes},
|
||||
ks,
|
||||
shared.CacheKeySeparator,
|
||||
)
|
||||
// add token type to key for new access tokens types. skip for bearer token type to
|
@ -114,7 +114,8 @@ func (m *PartitionedManager) Write(authParameters authority.AuthParams, tokenRes
|
||||
realm,
|
||||
clientID,
|
||||
cachedAt,
|
||||
tokenResponse.ExpiresOn.T,
|
||||
tokenResponse.RefreshOn.T,
|
||||
tokenResponse.ExpiresOn,
|
||||
tokenResponse.ExtExpiresOn.T,
|
||||
target,
|
||||
tokenResponse.AccessToken,
|
@ -173,6 +173,7 @@ func (m *Manager) Write(authParameters authority.AuthParams, tokenResponse acces
|
||||
environment := authParameters.AuthorityInfo.Host
|
||||
realm := authParameters.AuthorityInfo.Tenant
|
||||
clientID := authParameters.ClientID
|
||||
|
||||
target := strings.Join(tokenResponse.GrantedScopes.Slice, scopeSeparator)
|
||||
cachedAt := time.Now()
|
||||
authnSchemeKeyID := authParameters.AuthnScheme.KeyID()
|
||||
@ -193,7 +194,8 @@ func (m *Manager) Write(authParameters authority.AuthParams, tokenResponse acces
|
||||
realm,
|
||||
clientID,
|
||||
cachedAt,
|
||||
tokenResponse.ExpiresOn.T,
|
||||
tokenResponse.RefreshOn.T,
|
||||
tokenResponse.ExpiresOn,
|
||||
tokenResponse.ExtExpiresOn.T,
|
||||
target,
|
||||
tokenResponse.AccessToken,
|
||||
@ -265,6 +267,9 @@ func (m *Manager) aadMetadataFromCache(ctx context.Context, authorityInfo author
|
||||
}
|
||||
|
||||
func (m *Manager) aadMetadata(ctx context.Context, authorityInfo authority.Info) (authority.InstanceDiscoveryMetadata, error) {
|
||||
if m.requests == nil {
|
||||
return authority.InstanceDiscoveryMetadata{}, fmt.Errorf("httpclient in oauth instance for fetching metadata is nil")
|
||||
}
|
||||
m.aadCacheMu.Lock()
|
||||
defer m.aadCacheMu.Unlock()
|
||||
discoveryResponse, err := m.requests.AADInstanceDiscovery(ctx, authorityInfo)
|
||||
@ -459,6 +464,7 @@ func (m *Manager) readAccount(homeAccountID string, envAliases []string, realm s
|
||||
|
||||
func (m *Manager) writeAccount(account shared.Account) error {
|
||||
key := account.Key()
|
||||
|
||||
m.contractMu.Lock()
|
||||
defer m.contractMu.Unlock()
|
||||
m.contract.Accounts[key] = account
|
@ -31,4 +31,6 @@ type TokenProviderResult struct {
|
||||
AccessToken string
|
||||
// ExpiresInSeconds is the lifetime of the token in seconds
|
||||
ExpiresInSeconds int
|
||||
// RefreshInSeconds indicates the suggested time to refresh the token, if any
|
||||
RefreshInSeconds int
|
||||
}
|
||||
|
@ -146,7 +146,8 @@ func (s *Server) handler(w http.ResponseWriter, r *http.Request) {
|
||||
// Note: It is a little weird we handle some errors by not going to the failPage. If they all should,
|
||||
// change this to s.error() and make s.error() write the failPage instead of an error code.
|
||||
_, _ = w.Write([]byte(fmt.Sprintf(failPage, headerErr, desc)))
|
||||
s.putResult(Result{Err: fmt.Errorf(desc)})
|
||||
s.putResult(Result{Err: fmt.Errorf("%s", desc)})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -111,7 +111,7 @@ func (t *Client) Credential(ctx context.Context, authParams authority.AuthParams
|
||||
Scopes: scopes,
|
||||
TenantID: authParams.AuthorityInfo.Tenant,
|
||||
}
|
||||
tr, err := cred.TokenProvider(ctx, params)
|
||||
pr, 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)
|
||||
@ -119,14 +119,18 @@ func (t *Client) Credential(ctx context.Context, authParams authority.AuthParams
|
||||
}
|
||||
return accesstokens.TokenResponse{}, err
|
||||
}
|
||||
return accesstokens.TokenResponse{
|
||||
TokenType: authParams.AuthnScheme.AccessTokenType(),
|
||||
AccessToken: tr.AccessToken,
|
||||
ExpiresOn: internalTime.DurationTime{
|
||||
T: now.Add(time.Duration(tr.ExpiresInSeconds) * time.Second),
|
||||
},
|
||||
tr := accesstokens.TokenResponse{
|
||||
TokenType: authParams.AuthnScheme.AccessTokenType(),
|
||||
AccessToken: pr.AccessToken,
|
||||
ExpiresOn: now.Add(time.Duration(pr.ExpiresInSeconds) * time.Second),
|
||||
GrantedScopes: accesstokens.Scopes{Slice: authParams.Scopes},
|
||||
}, nil
|
||||
}
|
||||
if pr.RefreshInSeconds > 0 {
|
||||
tr.RefreshOn = internalTime.DurationTime{
|
||||
T: now.Add(time.Duration(pr.RefreshInSeconds) * time.Second),
|
||||
}
|
||||
}
|
||||
return tr, nil
|
||||
}
|
||||
|
||||
if err := t.resolveEndpoint(ctx, &authParams, ""); err != nil {
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
|
||||
/* #nosec */
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
@ -68,7 +69,7 @@ type DeviceCodeResponse struct {
|
||||
|
||||
UserCode string `json:"user_code"`
|
||||
DeviceCode string `json:"device_code"`
|
||||
VerificationURL string `json:"verification_url"`
|
||||
VerificationURL string `json:"verification_uri"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
Interval int `json:"interval"`
|
||||
Message string `json:"message"`
|
||||
@ -112,19 +113,31 @@ func (c *Credential) JWT(ctx context.Context, authParams authority.AuthParams) (
|
||||
}
|
||||
return c.AssertionCallback(ctx, options)
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
|
||||
claims := jwt.MapClaims{
|
||||
"aud": authParams.Endpoints.TokenEndpoint,
|
||||
"exp": json.Number(strconv.FormatInt(time.Now().Add(10*time.Minute).Unix(), 10)),
|
||||
"iss": authParams.ClientID,
|
||||
"jti": uuid.New().String(),
|
||||
"nbf": json.Number(strconv.FormatInt(time.Now().Unix(), 10)),
|
||||
"sub": authParams.ClientID,
|
||||
})
|
||||
}
|
||||
|
||||
isADFSorDSTS := authParams.AuthorityInfo.AuthorityType == authority.ADFS ||
|
||||
authParams.AuthorityInfo.AuthorityType == authority.DSTS
|
||||
|
||||
var signingMethod jwt.SigningMethod = jwt.SigningMethodPS256
|
||||
thumbprintKey := "x5t#S256"
|
||||
|
||||
if isADFSorDSTS {
|
||||
signingMethod = jwt.SigningMethodRS256
|
||||
thumbprintKey = "x5t"
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(signingMethod, claims)
|
||||
token.Header = map[string]interface{}{
|
||||
"alg": "RS256",
|
||||
"typ": "JWT",
|
||||
"x5t": base64.StdEncoding.EncodeToString(thumbprint(c.Cert)),
|
||||
"alg": signingMethod.Alg(),
|
||||
"typ": "JWT",
|
||||
thumbprintKey: base64.StdEncoding.EncodeToString(thumbprint(c.Cert, signingMethod.Alg())),
|
||||
}
|
||||
|
||||
if authParams.SendX5C {
|
||||
@ -133,17 +146,23 @@ func (c *Credential) JWT(ctx context.Context, authParams authority.AuthParams) (
|
||||
|
||||
assertion, err := token.SignedString(c.Key)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to sign a JWT token using private key: %w", err)
|
||||
return "", fmt.Errorf("unable to sign JWT token: %w", err)
|
||||
}
|
||||
|
||||
return assertion, nil
|
||||
}
|
||||
|
||||
// thumbprint runs the asn1.Der bytes through sha1 for use in the x5t parameter of JWT.
|
||||
// https://tools.ietf.org/html/rfc7517#section-4.8
|
||||
func thumbprint(cert *x509.Certificate) []byte {
|
||||
/* #nosec */
|
||||
a := sha1.Sum(cert.Raw)
|
||||
return a[:]
|
||||
func thumbprint(cert *x509.Certificate, alg string) []byte {
|
||||
switch alg {
|
||||
case jwt.SigningMethodRS256.Name: // identity providers like ADFS don't support SHA256 assertions, so need to support this
|
||||
hash := sha1.Sum(cert.Raw) /* #nosec */
|
||||
return hash[:]
|
||||
default:
|
||||
hash := sha256.Sum256(cert.Raw)
|
||||
return hash[:]
|
||||
}
|
||||
}
|
||||
|
||||
// Client represents the REST calls to get tokens from token generator backends.
|
||||
@ -262,11 +281,7 @@ func (c Client) FromClientSecret(ctx context.Context, authParameters authority.A
|
||||
qv.Set(clientID, authParameters.ClientID)
|
||||
addScopeQueryParam(qv, authParameters)
|
||||
|
||||
token, err := c.doTokenResp(ctx, authParameters, qv)
|
||||
if err != nil {
|
||||
return token, fmt.Errorf("FromClientSecret(): %w", err)
|
||||
}
|
||||
return token, nil
|
||||
return c.doTokenResp(ctx, authParameters, qv)
|
||||
}
|
||||
|
||||
func (c Client) FromAssertion(ctx context.Context, authParameters authority.AuthParams, assertion string) (TokenResponse, error) {
|
||||
@ -281,11 +296,7 @@ func (c Client) FromAssertion(ctx context.Context, authParameters authority.Auth
|
||||
qv.Set(clientInfo, clientInfoVal)
|
||||
addScopeQueryParam(qv, authParameters)
|
||||
|
||||
token, err := c.doTokenResp(ctx, authParameters, qv)
|
||||
if err != nil {
|
||||
return token, fmt.Errorf("FromAssertion(): %w", err)
|
||||
}
|
||||
return token, nil
|
||||
return c.doTokenResp(ctx, authParameters, qv)
|
||||
}
|
||||
|
||||
func (c Client) FromUserAssertionClientSecret(ctx context.Context, authParameters authority.AuthParams, userAssertion string, clientSecret string) (TokenResponse, error) {
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -173,14 +174,75 @@ type TokenResponse struct {
|
||||
FamilyID string `json:"foci"`
|
||||
IDToken IDToken `json:"id_token"`
|
||||
ClientInfo ClientInfo `json:"client_info"`
|
||||
ExpiresOn internalTime.DurationTime `json:"expires_in"`
|
||||
RefreshOn internalTime.DurationTime `json:"refresh_in,omitempty"`
|
||||
ExpiresOn time.Time `json:"-"`
|
||||
ExtExpiresOn internalTime.DurationTime `json:"ext_expires_in"`
|
||||
GrantedScopes Scopes `json:"scope"`
|
||||
DeclinedScopes []string // This is derived
|
||||
|
||||
AdditionalFields map[string]interface{}
|
||||
scopesComputed bool
|
||||
}
|
||||
|
||||
scopesComputed bool
|
||||
func (tr *TokenResponse) UnmarshalJSON(data []byte) error {
|
||||
type Alias TokenResponse
|
||||
aux := &struct {
|
||||
ExpiresIn internalTime.DurationTime `json:"expires_in,omitempty"`
|
||||
ExpiresOn any `json:"expires_on,omitempty"`
|
||||
*Alias
|
||||
}{
|
||||
Alias: (*Alias)(tr),
|
||||
}
|
||||
|
||||
// Unmarshal the JSON data into the aux struct
|
||||
if err := json.Unmarshal(data, &aux); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Function to parse different date formats
|
||||
// This is a workaround for the issue described here:
|
||||
// https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/4963
|
||||
parseExpiresOn := func(expiresOn string) (time.Time, error) {
|
||||
var formats = []string{
|
||||
"01/02/2006 15:04:05", // MM/dd/yyyy HH:mm:ss
|
||||
"2006-01-02 15:04:05", // yyyy-MM-dd HH:mm:ss
|
||||
time.RFC3339Nano, // ISO 8601 (with nanosecond precision)
|
||||
}
|
||||
|
||||
for _, format := range formats {
|
||||
if t, err := time.Parse(format, expiresOn); err == nil {
|
||||
return t, nil
|
||||
}
|
||||
}
|
||||
return time.Time{}, fmt.Errorf("invalid ExpiresOn format: %s", expiresOn)
|
||||
}
|
||||
|
||||
if expiresOnStr, ok := aux.ExpiresOn.(string); ok {
|
||||
if ts, err := strconv.ParseInt(expiresOnStr, 10, 64); err == nil {
|
||||
tr.ExpiresOn = time.Unix(ts, 0)
|
||||
return nil
|
||||
}
|
||||
if expiresOnStr != "" {
|
||||
if t, err := parseExpiresOn(expiresOnStr); err != nil {
|
||||
return err
|
||||
} else {
|
||||
tr.ExpiresOn = t
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if ExpiresOn is a number (Unix timestamp or ISO 8601)
|
||||
if expiresOnNum, ok := aux.ExpiresOn.(float64); ok {
|
||||
tr.ExpiresOn = time.Unix(int64(expiresOnNum), 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
if !aux.ExpiresIn.T.IsZero() {
|
||||
tr.ExpiresOn = aux.ExpiresIn.T
|
||||
return nil
|
||||
}
|
||||
return errors.New("expires_in and expires_on are both missing or invalid")
|
||||
}
|
||||
|
||||
// ComputeScope computes the final scopes based on what was granted by the server and
|
||||
|
@ -98,7 +98,7 @@ func (c *Client) JSONCall(ctx context.Context, endpoint string, headers http.Hea
|
||||
|
||||
if resp != nil {
|
||||
if err := unmarshal(data, resp); err != nil {
|
||||
return fmt.Errorf("json decode error: %w\njson message bytes were: %s", err, string(data))
|
||||
return errors.InvalidJsonErr{Err: fmt.Errorf("json decode error: %w\njson message bytes were: %s", err, string(data))}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@ -221,7 +221,7 @@ func (c *Client) URLFormCall(ctx context.Context, endpoint string, qv url.Values
|
||||
}
|
||||
if resp != nil {
|
||||
if err := unmarshal(data, resp); err != nil {
|
||||
return fmt.Errorf("json decode error: %w\nraw message was: %s", err, string(data))
|
||||
return errors.InvalidJsonErr{Err: fmt.Errorf("json decode error: %w\nraw message was: %s", err, string(data))}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -5,4 +5,4 @@
|
||||
package version
|
||||
|
||||
// Version is the version of this client package that is communicated to the server.
|
||||
const Version = "1.2.0"
|
||||
const Version = "1.4.2"
|
||||
|
Reference in New Issue
Block a user