fix(deps): update module github.com/ibm/go-sdk-core/v5 to v5.20.0 (main) (#17924)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
pull/17925/head
renovate[bot] 7 months ago committed by GitHub
parent 25473e8587
commit 7a95f666e8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      go.mod
  2. 4
      go.sum
  3. 4
      vendor/github.com/IBM/go-sdk-core/v5/core/authenticator_factory.go
  4. 43
      vendor/github.com/IBM/go-sdk-core/v5/core/constants.go
  5. 0
      vendor/github.com/IBM/go-sdk-core/v5/core/mcsp_v1_authenticator.go
  6. 618
      vendor/github.com/IBM/go-sdk-core/v5/core/mcsp_v2_authenticator.go
  7. 2
      vendor/github.com/IBM/go-sdk-core/v5/core/version.go
  8. 2
      vendor/modules.txt

@ -115,7 +115,7 @@ require (
github.com/Azure/go-autorest/autorest v0.11.30
github.com/DataDog/sketches-go v1.4.7
github.com/DmitriyVTitov/size v1.5.0
github.com/IBM/go-sdk-core/v5 v5.19.1
github.com/IBM/go-sdk-core/v5 v5.20.0
github.com/IBM/ibm-cos-sdk-go v1.12.2
github.com/apache/arrow-go/v18 v18.2.0
github.com/axiomhq/hyperloglog v0.2.5

@ -134,8 +134,8 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapp
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0/go.mod h1:otE2jQekW/PqXk1Awf5lmfokJx4uwuqcj1ab5SpGeW0=
github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM=
github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
github.com/IBM/go-sdk-core/v5 v5.19.1 h1:sleVks1O4XjgF4YEGvyDh6PZbP6iZhlTPeDkQc8nWDs=
github.com/IBM/go-sdk-core/v5 v5.19.1/go.mod h1:Q3BYO6iDA2zweQPDGbNTtqft5tDcEpm6RTuqMlPcvbw=
github.com/IBM/go-sdk-core/v5 v5.20.0 h1:rG1fn5GmJfFzVtpDKndsk6MgcarluG8YIWf89rVqLP8=
github.com/IBM/go-sdk-core/v5 v5.20.0/go.mod h1:Q3BYO6iDA2zweQPDGbNTtqft5tDcEpm6RTuqMlPcvbw=
github.com/IBM/ibm-cos-sdk-go v1.12.2 h1:71A4tDl8u6BZ548h71ecEe7fw5bBA7ECTVqYmeSQWQA=
github.com/IBM/ibm-cos-sdk-go v1.12.2/go.mod h1:ODYcmrmdpjo5hVguq9RbD6xmC8xb1XZMG7NefUbJNcc=
github.com/IBM/sarama v1.45.2 h1:8m8LcMCu3REcwpa7fCP6v2fuPuzVwXDAM2DOv3CBrKw=

@ -1,6 +1,6 @@
package core
// (C) Copyright IBM Corp. 2019, 2024.
// (C) Copyright IBM Corp. 2019, 2025.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -63,6 +63,8 @@ func GetAuthenticatorFromEnvironment(credentialKey string) (authenticator Authen
authenticator, err = newCloudPakForDataAuthenticatorFromMap(properties)
} else if strings.EqualFold(authType, AUTHTYPE_MCSP) {
authenticator, err = newMCSPAuthenticatorFromMap(properties)
} else if strings.EqualFold(authType, AUTHTYPE_MCSPV2) {
authenticator, err = newMCSPV2AuthenticatorFromMap(properties)
} else if strings.EqualFold(authType, AUTHTYPE_NOAUTH) {
authenticator, err = NewNoAuthAuthenticator()
} else {

@ -1,6 +1,6 @@
package core
// (C) Copyright IBM Corp. 2019, 2023.
// (C) Copyright IBM Corp. 2019, 2025.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -25,6 +25,7 @@ const (
AUTHTYPE_CONTAINER = "container"
AUTHTYPE_VPC = "vpc"
AUTHTYPE_MCSP = "mcsp"
AUTHTYPE_MCSPV2 = "mcspv2"
// Names of properties that can be defined as part of an external configuration (credential file, env vars, etc.).
// Example: export MYSERVICE_URL=https://myurl
@ -38,22 +39,29 @@ const (
PROPNAME_SVC_RETRY_INTERVAL = "RETRY_INTERVAL"
// Authenticator properties.
PROPNAME_AUTH_TYPE = "AUTH_TYPE"
PROPNAME_USERNAME = "USERNAME"
PROPNAME_PASSWORD = "PASSWORD"
PROPNAME_BEARER_TOKEN = "BEARER_TOKEN"
PROPNAME_AUTH_URL = "AUTH_URL"
PROPNAME_AUTH_DISABLE_SSL = "AUTH_DISABLE_SSL"
PROPNAME_APIKEY = "APIKEY"
PROPNAME_REFRESH_TOKEN = "REFRESH_TOKEN" // #nosec G101
PROPNAME_CLIENT_ID = "CLIENT_ID"
PROPNAME_CLIENT_SECRET = "CLIENT_SECRET"
PROPNAME_SCOPE = "SCOPE"
PROPNAME_CRTOKEN_FILENAME = "CR_TOKEN_FILENAME" // #nosec G101
PROPNAME_IAM_PROFILE_CRN = "IAM_PROFILE_CRN"
PROPNAME_IAM_PROFILE_NAME = "IAM_PROFILE_NAME"
PROPNAME_IAM_PROFILE_ID = "IAM_PROFILE_ID"
PROPNAME_IAM_ACCOUNT_ID = "IAM_ACCOUNT_ID"
PROPNAME_AUTH_TYPE = "AUTH_TYPE"
PROPNAME_USERNAME = "USERNAME"
PROPNAME_PASSWORD = "PASSWORD"
PROPNAME_BEARER_TOKEN = "BEARER_TOKEN"
PROPNAME_AUTH_URL = "AUTH_URL"
PROPNAME_AUTH_DISABLE_SSL = "AUTH_DISABLE_SSL"
PROPNAME_APIKEY = "APIKEY"
PROPNAME_REFRESH_TOKEN = "REFRESH_TOKEN" // #nosec G101
PROPNAME_CLIENT_ID = "CLIENT_ID"
PROPNAME_CLIENT_SECRET = "CLIENT_SECRET"
PROPNAME_SCOPE = "SCOPE"
PROPNAME_CRTOKEN_FILENAME = "CR_TOKEN_FILENAME" // #nosec G101
PROPNAME_IAM_PROFILE_CRN = "IAM_PROFILE_CRN"
PROPNAME_IAM_PROFILE_NAME = "IAM_PROFILE_NAME"
PROPNAME_IAM_PROFILE_ID = "IAM_PROFILE_ID"
PROPNAME_IAM_ACCOUNT_ID = "IAM_ACCOUNT_ID"
PROPNAME_SCOPE_COLLECTION_TYPE = "SCOPE_COLLECTION_TYPE"
PROPNAME_SCOPE_ID = "SCOPE_ID"
PROPNAME_INCLUDE_BUILTIN_ACTIONS = "INCLUDE_BUILTIN_ACTIONS"
PROPNAME_INCLUDE_CUSTOM_ACTIONS = "INCLUDE_CUSTOM_ACTIONS"
PROPNAME_INCLUDE_ROLES = "INCLUDE_ROLES"
PROPNAME_PREFIX_ROLES = "PREFIX_ROLES"
PROPNAME_CALLER_EXT_CLAIM = "CALLER_EXT_CLAIM"
// SSL error
SSL_CERTIFICATION_ERROR = "x509: certificate"
@ -86,6 +94,7 @@ const (
ERRORMSG_UNABLE_RETRIEVE_IITOKEN = "unable to retrieve instance identity token value: %s" // #nosec G101
ERRORMSG_VPCMDS_OPERATION_ERROR = "VPC metadata service error, status code %d received from '%s': %s"
ERRORMSG_ACCOUNTID_PROP_ERROR = "IAMAccountID must be specified if and only if IAMProfileName is specified"
ERRORMSG_PROP_PARSE_ERROR = "error parsing configuration property %s, value=%s"
// The name of this module - matches the value in the go.mod file.
MODULE_NAME = "github.com/IBM/go-sdk-core/v5"

@ -0,0 +1,618 @@
package core
// (C) Copyright IBM Corp. 2025.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import (
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"net/http"
"net/http/httputil"
"strconv"
"sync"
"time"
)
// MCSPV2Authenticator invokes the MCSP v2 token-exchange operation (POST /api/2.0/{scopeCollectionType}/{scopeId}/apikeys/token)
// to obtain an access token for an apikey, and adds the access token to requests via an Authorization header
// of the form: "Authorization: Bearer <access-token>"
type MCSPV2Authenticator struct {
// [Required] The apikey used to fetch the access token from the token server.
ApiKey string
// [Required] The endpoint base URL for the token server.
URL string
// [Required] The scope collection type of item(s).
// Valid values are: "accounts", "subscriptions", "services".
ScopeCollectionType string
// [Required] The scope identifier of item(s).
ScopeID string
// [Optional] A flag to include builtin actions in the "actions" claim in the MCSP access token (default: false).
IncludeBuiltinActions bool
// [Optional] A flag to include custom actions in the "actions" claim in the MCSP access token (default: false).
IncludeCustomActions bool
// [Optional] A flag to include the "roles" claim in the MCSP access token (default: true).
IncludeRoles bool
// [Optional] A flag to add a prefix with the scope level where the role is defined in the "roles" claim (default: false).
PrefixRoles bool
// [Optional] A map containing keys and values to be injected into the access token as the "callerExt" claim.
// The keys used in this map must be enabled in the apikey by setting the "callerExtClaimNames" property when the apikey is created.
// This property is typically only used in scenarios involving an apikey with identityType `SERVICEID`.
CallerExtClaim map[string]string
// [Optional] A flag that indicates whether verification of the token server's SSL certificate
// should be disabled; defaults to false.
DisableSSLVerification bool
// [Optional] A set of key/value pairs that will be sent as HTTP headers in requests
// made to the token server.
Headers map[string]string
// [Optional] The http.Client object used to invoke token server requests.
// If not specified by the user, a suitable default Client will be constructed.
Client *http.Client
clientInit sync.Once
// The User-Agent header value to be included with each token request.
userAgent string
userAgentInit sync.Once
// The cached token and expiration time.
tokenData *mcspv2TokenData
// Mutex to make the tokenData field thread safe.
tokenDataMutex sync.Mutex
}
var (
mcspv2RequestTokenMutex sync.Mutex
mcspv2NeedsRefreshMutex sync.Mutex
)
const (
mcspv2AuthOperationPath = "/api/2.0/{scopeCollectionType}/{scopeId}/apikeys/token"
)
// MCSPV2AuthenticatorBuilder is used to construct an MCSPV2Authenticator instance.
type MCSPV2AuthenticatorBuilder struct {
MCSPV2Authenticator
}
// NewMCSPV2AuthenticatorBuilder returns a new builder struct that
// can be used to construct an MCSPV2Authenticator instance.
func NewMCSPV2AuthenticatorBuilder() *MCSPV2AuthenticatorBuilder {
auth := &MCSPV2AuthenticatorBuilder{}
// Set fields whose default value is not the "zero value".
auth.MCSPV2Authenticator.IncludeRoles = true
return auth
}
// SetApiKey sets the ApiKey field in the builder.
func (builder *MCSPV2AuthenticatorBuilder) SetApiKey(s string) *MCSPV2AuthenticatorBuilder {
builder.MCSPV2Authenticator.ApiKey = s
return builder
}
// SetURL sets the URL field in the builder.
func (builder *MCSPV2AuthenticatorBuilder) SetURL(s string) *MCSPV2AuthenticatorBuilder {
builder.MCSPV2Authenticator.URL = s
return builder
}
// SetScopeCollectionType sets the ScopeCollectionType field in the builder.
func (builder *MCSPV2AuthenticatorBuilder) SetScopeCollectionType(s string) *MCSPV2AuthenticatorBuilder {
builder.MCSPV2Authenticator.ScopeCollectionType = s
return builder
}
// SetScopeID sets the ScopeID field in the builder.
func (builder *MCSPV2AuthenticatorBuilder) SetScopeID(s string) *MCSPV2AuthenticatorBuilder {
builder.MCSPV2Authenticator.ScopeID = s
return builder
}
// SetIncludeBuiltinActions sets the IncludeBuiltinActions field in the builder.
func (builder *MCSPV2AuthenticatorBuilder) SetIncludeBuiltinActions(b bool) *MCSPV2AuthenticatorBuilder {
builder.MCSPV2Authenticator.IncludeBuiltinActions = b
return builder
}
// SetIncludeCustomActions sets the IncludeCustomActions field in the builder.
func (builder *MCSPV2AuthenticatorBuilder) SetIncludeCustomActions(b bool) *MCSPV2AuthenticatorBuilder {
builder.MCSPV2Authenticator.IncludeCustomActions = b
return builder
}
// SetIncludeRoles sets the IncludeRoles field in the builder.
func (builder *MCSPV2AuthenticatorBuilder) SetIncludeRoles(b bool) *MCSPV2AuthenticatorBuilder {
builder.MCSPV2Authenticator.IncludeRoles = b
return builder
}
// SetPrefixRoles sets the PrefixRoles field in the builder.
func (builder *MCSPV2AuthenticatorBuilder) SetPrefixRoles(b bool) *MCSPV2AuthenticatorBuilder {
builder.MCSPV2Authenticator.PrefixRoles = b
return builder
}
// SetCallerExtClaim sets the CallerExtClaim field in the builder.
func (builder *MCSPV2AuthenticatorBuilder) SetCallerExtClaim(m map[string]string) *MCSPV2AuthenticatorBuilder {
builder.MCSPV2Authenticator.CallerExtClaim = m
return builder
}
// SetDisableSSLVerification sets the DisableSSLVerification field in the builder.
func (builder *MCSPV2AuthenticatorBuilder) SetDisableSSLVerification(b bool) *MCSPV2AuthenticatorBuilder {
builder.MCSPV2Authenticator.DisableSSLVerification = b
return builder
}
// SetHeaders sets the Headers field in the builder.
func (builder *MCSPV2AuthenticatorBuilder) SetHeaders(headers map[string]string) *MCSPV2AuthenticatorBuilder {
builder.MCSPV2Authenticator.Headers = headers
return builder
}
// SetClient sets the Client field in the builder.
func (builder *MCSPV2AuthenticatorBuilder) SetClient(client *http.Client) *MCSPV2AuthenticatorBuilder {
builder.MCSPV2Authenticator.Client = client
return builder
}
// Build returns a validated instance of the MCSPV2Authenticator with the config that was set in the builder.
func (builder *MCSPV2AuthenticatorBuilder) Build() (*MCSPV2Authenticator, error) {
// Make sure the config is valid.
err := builder.MCSPV2Authenticator.Validate()
if err != nil {
return nil, RepurposeSDKProblem(err, "validation-failed")
}
return &builder.MCSPV2Authenticator, nil
}
// Validate the authenticator's configuration.
func (authenticator *MCSPV2Authenticator) Validate() error {
if authenticator.ApiKey == "" {
err := fmt.Errorf(ERRORMSG_PROP_MISSING, "ApiKey")
return SDKErrorf(err, "", "missing-api-key", getComponentInfo())
}
if authenticator.URL == "" {
err := fmt.Errorf(ERRORMSG_PROP_MISSING, "URL")
return SDKErrorf(err, "", "missing-url", getComponentInfo())
}
if authenticator.ScopeCollectionType == "" {
err := fmt.Errorf(ERRORMSG_PROP_MISSING, "ScopeCollectionType")
return SDKErrorf(err, "", "missing-scope-collection-type", getComponentInfo())
}
if authenticator.ScopeID == "" {
err := fmt.Errorf(ERRORMSG_PROP_MISSING, "ScopeID")
return SDKErrorf(err, "", "missing-scope-id", getComponentInfo())
}
return nil
}
// client returns the authenticator's http client after potentially initializing it.
func (authenticator *MCSPV2Authenticator) client() *http.Client {
authenticator.clientInit.Do(func() {
if authenticator.Client == nil {
authenticator.Client = DefaultHTTPClient()
authenticator.Client.Timeout = time.Second * 30
// If the user told us to disable SSL verification, then do it now.
if authenticator.DisableSSLVerification {
transport := &http.Transport{
// #nosec G402
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
authenticator.Client.Transport = transport
}
}
})
return authenticator.Client
}
// getUserAgent returns the User-Agent header value to be included in each token request invoked by the authenticator.
func (authenticator *MCSPV2Authenticator) getUserAgent() string {
authenticator.userAgentInit.Do(func() {
authenticator.userAgent = fmt.Sprintf("%s/%s-%s %s", sdkName, "mcspv2-authenticator", __VERSION__, SystemInfo())
})
return authenticator.userAgent
}
// newMCSPV2AuthenticatorFromMap constructs a new MCSPV2Authenticator instance from a map.
func newMCSPV2AuthenticatorFromMap(properties map[string]string) (authenticator *MCSPV2Authenticator, err error) {
if properties == nil {
err = errors.New(ERRORMSG_PROPS_MAP_NIL)
return nil, SDKErrorf(err, "", "missing-props", getComponentInfo())
}
// Initialize the builder first with the required properties.
builder := NewMCSPV2AuthenticatorBuilder().
SetApiKey(properties[PROPNAME_APIKEY]).
SetURL(properties[PROPNAME_AUTH_URL]).
SetScopeCollectionType(properties[PROPNAME_SCOPE_COLLECTION_TYPE]).
SetScopeID(properties[PROPNAME_SCOPE_ID])
// Now add the optional properties to the builder.
var strValue string
var boolValue bool
strValue = properties[PROPNAME_INCLUDE_BUILTIN_ACTIONS]
if strValue != "" {
boolValue, err = strconv.ParseBool(strValue)
if err != nil {
err = SDKErrorf(err,
fmt.Sprintf(ERRORMSG_PROP_PARSE_ERROR, PROPNAME_INCLUDE_BUILTIN_ACTIONS, strValue),
"validation-error", getComponentInfo())
return
}
builder.SetIncludeBuiltinActions(boolValue)
}
strValue = properties[PROPNAME_INCLUDE_CUSTOM_ACTIONS]
if strValue != "" {
boolValue, err = strconv.ParseBool(strValue)
if err != nil {
err = SDKErrorf(err,
fmt.Sprintf(ERRORMSG_PROP_PARSE_ERROR, PROPNAME_INCLUDE_CUSTOM_ACTIONS, strValue),
"validation-error", getComponentInfo())
return
}
builder.SetIncludeCustomActions(boolValue)
}
strValue = properties[PROPNAME_INCLUDE_ROLES]
if strValue != "" {
boolValue, err = strconv.ParseBool(strValue)
if err != nil {
err = SDKErrorf(err,
fmt.Sprintf(ERRORMSG_PROP_PARSE_ERROR, PROPNAME_INCLUDE_ROLES, strValue),
"validation-error", getComponentInfo())
return
}
builder.SetIncludeRoles(boolValue)
}
strValue = properties[PROPNAME_PREFIX_ROLES]
if strValue != "" {
boolValue, err = strconv.ParseBool(strValue)
if err != nil {
err = SDKErrorf(err,
fmt.Sprintf(ERRORMSG_PROP_PARSE_ERROR, PROPNAME_PREFIX_ROLES, strValue),
"validation-error", getComponentInfo())
return
}
builder.SetPrefixRoles(boolValue)
}
strValue = properties[PROPNAME_AUTH_DISABLE_SSL]
if strValue != "" {
boolValue, err = strconv.ParseBool(strValue)
if err != nil {
err = SDKErrorf(err,
fmt.Sprintf(ERRORMSG_PROP_PARSE_ERROR, PROPNAME_AUTH_DISABLE_SSL, strValue),
"validation-error", getComponentInfo())
return
}
builder.SetDisableSSLVerification(boolValue)
}
// The CallerExtClaim property is a map[string]string and we allow the
// user to set it as a JSON string when using an external config property.
// Here we retrieve it from the config as a string and unmarshal into a map.
strValue = properties[PROPNAME_CALLER_EXT_CLAIM]
if strValue != "" {
var m map[string]string
err = json.Unmarshal([]byte(strValue), &m)
if err != nil {
err = SDKErrorf(err,
fmt.Sprintf(ERRORMSG_PROP_PARSE_ERROR, PROPNAME_CALLER_EXT_CLAIM, strValue),
"validation-error", getComponentInfo())
return
}
builder.SetCallerExtClaim(m)
}
authenticator, err = builder.Build()
return
}
// AuthenticationType returns the authentication type for this authenticator.
func (*MCSPV2Authenticator) AuthenticationType() string {
return AUTHTYPE_MCSPV2
}
// Authenticate adds the Authorization header to the request.
// The value will be of the form: "Authorization: Bearer <bearer-token>""
func (authenticator *MCSPV2Authenticator) Authenticate(request *http.Request) error {
token, err := authenticator.GetToken()
if err != nil {
return RepurposeSDKProblem(err, "get-token-fail")
}
request.Header.Set("Authorization", "Bearer "+token)
GetLogger().Debug("Authenticated outbound request (type=%s)\n", authenticator.AuthenticationType())
return nil
}
// getTokenData returns the tokenData field from the authenticator.
func (authenticator *MCSPV2Authenticator) getTokenData() *mcspv2TokenData {
authenticator.tokenDataMutex.Lock()
defer authenticator.tokenDataMutex.Unlock()
return authenticator.tokenData
}
// setTokenData sets the given mcspv2TokenData to the tokenData field of the authenticator.
func (authenticator *MCSPV2Authenticator) setTokenData(tokenData *mcspv2TokenData) {
authenticator.tokenDataMutex.Lock()
defer authenticator.tokenDataMutex.Unlock()
authenticator.tokenData = tokenData
GetLogger().Debug("setTokenData: expiration=%d, refreshTime=%d",
authenticator.tokenData.Expiration, authenticator.tokenData.RefreshTime)
}
// GetToken: returns an access token to be used in an Authorization header.
// Whenever a new token is needed (when a token doesn't yet exist, needs to be refreshed,
// or the existing token has expired), a new access token is fetched from the token server.
func (authenticator *MCSPV2Authenticator) GetToken() (string, error) {
if authenticator.getTokenData() == nil || !authenticator.getTokenData().isTokenValid() {
GetLogger().Debug("Performing synchronous token fetch...")
// synchronously request the token
err := authenticator.synchronizedRequestToken()
if err != nil {
return "", RepurposeSDKProblem(err, "request-token-fail")
}
} else if authenticator.getTokenData().needsRefresh() {
GetLogger().Debug("Performing background asynchronous token fetch...")
// If refresh needed, kick off a go routine in the background to get a new token.
//nolint: errcheck
go authenticator.invokeRequestTokenData()
} else {
GetLogger().Debug("Using cached access token...")
}
// return an error if the access token is not valid or was not fetched
if authenticator.getTokenData() == nil || authenticator.getTokenData().AccessToken == "" {
err := errors.New("Error while trying to get access token")
return "", SDKErrorf(err, "", "no-token", getComponentInfo())
}
return authenticator.getTokenData().AccessToken, nil
}
// synchronizedRequestToken: synchronously checks if the current token in cache
// is valid. If token is not valid or does not exist, it will fetch a new token.
func (authenticator *MCSPV2Authenticator) synchronizedRequestToken() error {
mcspv2RequestTokenMutex.Lock()
defer mcspv2RequestTokenMutex.Unlock()
// if cached token is still valid, then just continue to use it
if authenticator.getTokenData() != nil && authenticator.getTokenData().isTokenValid() {
return nil
}
return authenticator.invokeRequestTokenData()
}
// invokeRequestTokenData: requests a new token from the access server and
// unmarshals the token information to the tokenData cache. Returns
// an error if the token was unable to be fetched, otherwise returns nil
func (authenticator *MCSPV2Authenticator) invokeRequestTokenData() error {
tokenResponse, err := authenticator.RequestToken()
if err != nil {
return err
}
GetLogger().Debug("invokeRequestTokenData(): RequestToken returned tokenResponse:\n%+v", *tokenResponse)
tokenData, err := newMCSPV2TokenData(tokenResponse)
if err != nil {
tokenData = &mcspv2TokenData{}
}
authenticator.setTokenData(tokenData)
return nil
}
// RequestToken fetches a new access token from the token server.
func (authenticator *MCSPV2Authenticator) RequestToken() (*MCSPV2TokenServerResponse, error) {
builder := NewRequestBuilder(POST)
pathParams := map[string]string{
"scopeCollectionType": authenticator.ScopeCollectionType,
"scopeId": authenticator.ScopeID,
}
_, err := builder.ResolveRequestURL(authenticator.URL, mcspv2AuthOperationPath, pathParams)
if err != nil {
err = RepurposeSDKProblem(err, "url-resolve-error")
return nil, err
}
// Add the request headers.
builder.AddHeader(CONTENT_TYPE, APPLICATION_JSON)
builder.AddHeader(Accept, APPLICATION_JSON)
builder.AddHeader(headerNameUserAgent, authenticator.getUserAgent())
// Add the query params.
builder.AddQuery("includeBuiltinActions", strconv.FormatBool(authenticator.IncludeBuiltinActions))
builder.AddQuery("includeCustomActions", strconv.FormatBool(authenticator.IncludeCustomActions))
builder.AddQuery("includeRoles", strconv.FormatBool(authenticator.IncludeRoles))
builder.AddQuery("prefixRolesWithDefinitionScope", strconv.FormatBool(authenticator.PrefixRoles))
// The requestBody will consist of the apikey and (optionally) the callerExtClaim map.
requestBody := make(map[string]any)
requestBody["apikey"] = authenticator.ApiKey
if len(authenticator.CallerExtClaim) > 0 {
requestBody["callerExtClaim"] = authenticator.CallerExtClaim
}
_, _ = builder.SetBodyContentJSON(requestBody)
// Add user-defined headers to request.
for headerName, headerValue := range authenticator.Headers {
builder.AddHeader(headerName, headerValue)
}
req, err := builder.Build()
if err != nil {
return nil, RepurposeSDKProblem(err, "request-build-error")
}
// If debug is enabled, then dump the request.
if GetLogger().IsLogLevelEnabled(LevelDebug) {
buf, dumpErr := httputil.DumpRequestOut(req, req.Body != nil)
if dumpErr == nil {
GetLogger().Debug("Request:\n%s\n", RedactSecrets(string(buf)))
} else {
GetLogger().Debug(fmt.Sprintf("error while attempting to log outbound request: %s", dumpErr.Error()))
}
}
GetLogger().Debug("Invoking MCSP 'get token' operation: %s", builder.URL)
resp, err := authenticator.client().Do(req)
if err != nil {
err = SDKErrorf(err, "", "request-error", getComponentInfo())
return nil, err
}
GetLogger().Debug("Returned from MCSP 'get token' operation, received status code %d", resp.StatusCode)
// If debug is enabled, then dump the response.
if GetLogger().IsLogLevelEnabled(LevelDebug) {
buf, dumpErr := httputil.DumpResponse(resp, req.Body != nil)
if dumpErr == nil {
GetLogger().Debug("Response:\n%s\n", RedactSecrets(string(buf)))
} else {
GetLogger().Debug(fmt.Sprintf("error while attempting to log inbound response: %s", dumpErr.Error()))
}
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
detailedResponse, err := processErrorResponse(resp)
authError := authenticationErrorf(err, detailedResponse, "get_token", authenticator.getComponentInfo())
// The err Summary is typically the message computed for the HTTPError instance in
// processErrorResponse(). If the response body is non-JSON, the message will be generic
// text based on the status code but authenticators have always used the stringified
// RawResult, so update that here for compatilibility.
errorMsg := err.Summary
if detailedResponse.RawResult != nil {
// RawResult is only populated if the response body is
// non-JSON and we couldn't extract a message.
errorMsg = string(detailedResponse.RawResult)
}
authError.Summary = errorMsg
return nil, authError
}
tokenResponse := &MCSPV2TokenServerResponse{}
_ = json.NewDecoder(resp.Body).Decode(tokenResponse)
defer resp.Body.Close() // #nosec G307
return tokenResponse, nil
}
func (authenticator *MCSPV2Authenticator) getComponentInfo() *ProblemComponent {
return NewProblemComponent("mscp_token_server", "1.0")
}
// MCSPTokenServerResponse : This struct models a response received from the token server.
type MCSPV2TokenServerResponse struct {
Token string `json:"token"`
TokenType string `json:"token_type"`
ExpiresIn int64 `json:"expires_in"`
Expiration int64 `json:"expiration"`
}
// mcspv2TokenData : This struct represents the cached information related to a fetched access token.
type mcspv2TokenData struct {
AccessToken string
RefreshTime int64
Expiration int64
}
// newMCSPV2TokenData: constructs a new mcspv2TokenData instance from the specified
// MCSPV2TokenServerResponse instance.
func newMCSPV2TokenData(tokenResponse *MCSPV2TokenServerResponse) (*mcspv2TokenData, error) {
if tokenResponse == nil || tokenResponse.Token == "" {
err := errors.New("Error while trying to parse access token!")
return nil, SDKErrorf(err, "", "token-parse", getComponentInfo())
}
// Need to crack open the access token (a JWT) to get the expiration and issued-at times
// so that we can compute the refresh time.
claims, err := parseJWT(tokenResponse.Token)
if err != nil {
return nil, err
}
// Compute the adjusted refresh time (expiration time - 20% of timeToLive)
timeToLive := claims.ExpiresAt - claims.IssuedAt
expireTime := claims.ExpiresAt
refreshTime := expireTime - int64(float64(timeToLive)*0.2)
tokenData := &mcspv2TokenData{
AccessToken: tokenResponse.Token,
Expiration: expireTime,
RefreshTime: refreshTime,
}
GetLogger().Debug("newMCSPV2TokenData: expiration=%d, refreshTime=%d", tokenData.Expiration, tokenData.RefreshTime)
return tokenData, nil
}
// isTokenValid: returns true iff the mcspv2TokenData instance represents a valid (non-expired) access token.
func (tokenData *mcspv2TokenData) isTokenValid() bool {
if tokenData.AccessToken != "" && GetCurrentTime() < tokenData.Expiration {
GetLogger().Debug("isTokenValid: Token is valid!")
return true
}
GetLogger().Debug("isTokenValid: Token is NOT valid!")
GetLogger().Debug("isTokenValid: expiration=%d, refreshTime=%d", tokenData.Expiration, tokenData.RefreshTime)
GetLogger().Debug("GetCurrentTime(): %d\n", GetCurrentTime())
return false
}
// needsRefresh: synchronously returns true iff the currently stored access token should be refreshed. This method also
// updates the refresh time if it determines the token needs refreshed to prevent other threads from
// making multiple refresh calls.
func (tokenData *mcspv2TokenData) needsRefresh() bool {
mcspv2NeedsRefreshMutex.Lock()
defer mcspv2NeedsRefreshMutex.Unlock()
// Advance refresh by one minute
if tokenData.RefreshTime >= 0 && GetCurrentTime() > tokenData.RefreshTime {
tokenData.RefreshTime = GetCurrentTime() + 60
return true
}
return false
}

@ -15,4 +15,4 @@ package core
// limitations under the License.
// Version of the SDK
const __VERSION__ = "5.19.1"
const __VERSION__ = "5.20.0"

@ -219,7 +219,7 @@ github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric
# github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0
## explicit; go 1.22
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping
# github.com/IBM/go-sdk-core/v5 v5.19.1
# github.com/IBM/go-sdk-core/v5 v5.20.0
## explicit; go 1.23.0
github.com/IBM/go-sdk-core/v5/core
# github.com/IBM/ibm-cos-sdk-go v1.12.2

Loading…
Cancel
Save