Bump github.com/Azure/go-autorest/autorest/adal to 0.9.5

This commit is contained in:
Markus Thömmes
2020-10-19 09:46:46 +02:00
parent ac10e4043a
commit e1fd0bd0eb
78 changed files with 2017 additions and 156 deletions

View File

@@ -8,6 +8,8 @@ go_library(
"persist.go",
"sender.go",
"token.go",
"token_1.13.go",
"token_legacy.go",
"version.go",
],
importmap = "k8s.io/kubernetes/vendor/github.com/Azure/go-autorest/autorest/adal",
@@ -16,7 +18,8 @@ go_library(
deps = [
"//vendor/github.com/Azure/go-autorest/autorest/date:go_default_library",
"//vendor/github.com/Azure/go-autorest/tracing:go_default_library",
"//vendor/github.com/dgrijalva/jwt-go:go_default_library",
"//vendor/github.com/form3tech-oss/jwt-go:go_default_library",
"//vendor/golang.org/x/crypto/pkcs12:go_default_library",
],
)

View File

@@ -222,6 +222,10 @@ func CheckForUserCompletionWithContext(ctx context.Context, sender Sender, code
case "code_expired":
return nil, ErrDeviceCodeExpired
default:
// return a more meaningful error message if available
if token.ErrorDescription != nil {
return nil, fmt.Errorf("%s %s: %s", logPrefix, *token.Error, *token.ErrorDescription)
}
return nil, ErrDeviceGeneric
}
}

View File

@@ -5,8 +5,8 @@ go 1.12
require (
github.com/Azure/go-autorest v14.2.0+incompatible
github.com/Azure/go-autorest/autorest/date v0.3.0
github.com/Azure/go-autorest/autorest/mocks v0.4.0
github.com/Azure/go-autorest/autorest/mocks v0.4.1
github.com/Azure/go-autorest/tracing v0.6.0
github.com/dgrijalva/jwt-go v3.2.0+incompatible
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
github.com/form3tech-oss/jwt-go v3.2.2+incompatible
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0
)

View File

@@ -2,16 +2,16 @@ github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
github.com/Azure/go-autorest/autorest/mocks v0.4.0 h1:z20OWOSG5aCye0HEkDp6TPmP17ZcfeMxPi6HnSALa8c=
github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk=
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

View File

@@ -15,11 +15,24 @@ package adal
// limitations under the License.
import (
"crypto/rsa"
"crypto/x509"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"golang.org/x/crypto/pkcs12"
)
var (
// ErrMissingCertificate is returned when no local certificate is found in the provided PFX data.
ErrMissingCertificate = errors.New("adal: certificate missing")
// ErrMissingPrivateKey is returned when no private key is found in the provided PFX data.
ErrMissingPrivateKey = errors.New("adal: private key missing")
)
// LoadToken restores a Token object from a file located at 'path'.
@@ -71,3 +84,52 @@ func SaveToken(path string, mode os.FileMode, token Token) error {
}
return nil
}
// DecodePfxCertificateData extracts the x509 certificate and RSA private key from the provided PFX data.
// The PFX data must contain a private key along with a certificate whose public key matches that of the
// private key or an error is returned.
// If the private key is not password protected pass the empty string for password.
func DecodePfxCertificateData(pfxData []byte, password string) (*x509.Certificate, *rsa.PrivateKey, error) {
blocks, err := pkcs12.ToPEM(pfxData, password)
if err != nil {
return nil, nil, err
}
// first extract the private key
var priv *rsa.PrivateKey
for _, block := range blocks {
if block.Type == "PRIVATE KEY" {
priv, err = x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, nil, err
}
break
}
}
if priv == nil {
return nil, nil, ErrMissingPrivateKey
}
// now find the certificate with the matching public key of our private key
var cert *x509.Certificate
for _, block := range blocks {
if block.Type == "CERTIFICATE" {
pcert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, nil, err
}
certKey, ok := pcert.PublicKey.(*rsa.PublicKey)
if !ok {
// keep looking
continue
}
if priv.E == certKey.E && priv.N.Cmp(certKey.N) == 0 {
// found a match
cert = pcert
break
}
}
}
if cert == nil {
return nil, nil, ErrMissingCertificate
}
return cert, priv, nil
}

View File

@@ -35,7 +35,7 @@ import (
"time"
"github.com/Azure/go-autorest/autorest/date"
"github.com/dgrijalva/jwt-go"
"github.com/form3tech-oss/jwt-go"
)
const (
@@ -62,6 +62,9 @@ const (
// msiEndpoint is the well known endpoint for getting MSI authentications tokens
msiEndpoint = "http://169.254.169.254/metadata/identity/oauth2/token"
// the API version to use for the MSI endpoint
msiAPIVersion = "2018-02-01"
// the default number of attempts to refresh an MSI authentication token
defaultMaxMSIRefreshAttempts = 5
@@ -70,6 +73,9 @@ const (
// asMSISecretEnv is the environment variable used to store the request secret on App Service and Functions
asMSISecretEnv = "MSI_SECRET"
// the API version to use for the App Service MSI endpoint
appServiceAPIVersion = "2017-09-01"
)
// OAuthTokenProvider is an interface which should be implemented by an access token retriever
@@ -354,6 +360,7 @@ type ServicePrincipalToken struct {
customRefreshFunc TokenRefresh
refreshCallbacks []TokenRefreshCallback
// MaxMSIRefreshAttempts is the maximum number of attempts to refresh an MSI token.
// Settings this to a value less than 1 will use the default value.
MaxMSIRefreshAttempts int
}
@@ -650,6 +657,8 @@ func GetMSIVMEndpoint() (string, error) {
return msiEndpoint, nil
}
// NOTE: this only indicates if the ASE environment credentials have been set
// which does not necessarily mean that the caller is authenticating via ASE!
func isAppService() bool {
_, asMSIEndpointEnvExists := os.LookupEnv(asMSIEndpointEnv)
_, asMSISecretEnvExists := os.LookupEnv(asMSISecretEnv)
@@ -678,16 +687,22 @@ func GetMSIEndpoint() (string, error) {
// NewServicePrincipalTokenFromMSI creates a ServicePrincipalToken via the MSI VM Extension.
// It will use the system assigned identity when creating the token.
func NewServicePrincipalTokenFromMSI(msiEndpoint, resource string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
return newServicePrincipalTokenFromMSI(msiEndpoint, resource, nil, callbacks...)
return newServicePrincipalTokenFromMSI(msiEndpoint, resource, nil, nil, callbacks...)
}
// NewServicePrincipalTokenFromMSIWithUserAssignedID creates a ServicePrincipalToken via the MSI VM Extension.
// It will use the specified user assigned identity when creating the token.
// It will use the clientID of specified user assigned identity when creating the token.
func NewServicePrincipalTokenFromMSIWithUserAssignedID(msiEndpoint, resource string, userAssignedID string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
return newServicePrincipalTokenFromMSI(msiEndpoint, resource, &userAssignedID, callbacks...)
return newServicePrincipalTokenFromMSI(msiEndpoint, resource, &userAssignedID, nil, callbacks...)
}
func newServicePrincipalTokenFromMSI(msiEndpoint, resource string, userAssignedID *string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
// NewServicePrincipalTokenFromMSIWithIdentityResourceID creates a ServicePrincipalToken via the MSI VM Extension.
// It will use the azure resource id of user assigned identity when creating the token.
func NewServicePrincipalTokenFromMSIWithIdentityResourceID(msiEndpoint, resource string, identityResourceID string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
return newServicePrincipalTokenFromMSI(msiEndpoint, resource, nil, &identityResourceID, callbacks...)
}
func newServicePrincipalTokenFromMSI(msiEndpoint, resource string, userAssignedID *string, identityResourceID *string, callbacks ...TokenRefreshCallback) (*ServicePrincipalToken, error) {
if err := validateStringParam(msiEndpoint, "msiEndpoint"); err != nil {
return nil, err
}
@@ -699,6 +714,11 @@ func newServicePrincipalTokenFromMSI(msiEndpoint, resource string, userAssignedI
return nil, err
}
}
if identityResourceID != nil {
if err := validateStringParam(*identityResourceID, "identityResourceID"); err != nil {
return nil, err
}
}
// We set the oauth config token endpoint to be MSI's endpoint
msiEndpointURL, err := url.Parse(msiEndpoint)
if err != nil {
@@ -709,13 +729,16 @@ func newServicePrincipalTokenFromMSI(msiEndpoint, resource string, userAssignedI
v.Set("resource", resource)
// App Service MSI currently only supports token API version 2017-09-01
if isAppService() {
v.Set("api-version", "2017-09-01")
v.Set("api-version", appServiceAPIVersion)
} else {
v.Set("api-version", "2018-02-01")
v.Set("api-version", msiAPIVersion)
}
if userAssignedID != nil {
v.Set("client_id", *userAssignedID)
}
if identityResourceID != nil {
v.Set("mi_res_id", *identityResourceID)
}
msiEndpointURL.RawQuery = v.Encode()
spt := &ServicePrincipalToken{
@@ -836,11 +859,28 @@ func (spt *ServicePrincipalToken) getGrantType() string {
}
func isIMDS(u url.URL) bool {
imds, err := url.Parse(msiEndpoint)
return isMSIEndpoint(u) == true || isASEEndpoint(u) == true
}
func isMSIEndpoint(endpoint url.URL) bool {
msi, err := url.Parse(msiEndpoint)
if err != nil {
return false
}
return (u.Host == imds.Host && u.Path == imds.Path) || isAppService()
return endpoint.Host == msi.Host && endpoint.Path == msi.Path
}
func isASEEndpoint(endpoint url.URL) bool {
aseEndpoint, err := GetMSIAppServiceEndpoint()
if err != nil {
// app service environment isn't enabled
return false
}
ase, err := url.Parse(aseEndpoint)
if err != nil {
return false
}
return endpoint.Host == ase.Host && endpoint.Path == ase.Path
}
func (spt *ServicePrincipalToken) refreshInternal(ctx context.Context, resource string) error {
@@ -859,7 +899,7 @@ func (spt *ServicePrincipalToken) refreshInternal(ctx context.Context, resource
}
req.Header.Add("User-Agent", UserAgent())
// Add header when runtime is on App Service or Functions
if isAppService() {
if isASEEndpoint(spt.inner.OauthConfig.TokenEndpoint) {
asMSISecret, _ := os.LookupEnv(asMSISecretEnv)
req.Header.Add("Secret", asMSISecret)
}
@@ -901,6 +941,14 @@ func (spt *ServicePrincipalToken) refreshInternal(ctx context.Context, resource
}
var resp *http.Response
if isMSIEndpoint(spt.inner.OauthConfig.TokenEndpoint) {
resp, err = getMSIEndpoint(ctx, spt.sender)
if err != nil {
// return a TokenRefreshError here so that we don't keep retrying
return newTokenRefreshError(fmt.Sprintf("the MSI endpoint is not available. Failed HTTP request to MSI endpoint: %v", err), nil)
}
resp.Body.Close()
}
if isIMDS(spt.inner.OauthConfig.TokenEndpoint) {
resp, err = retryForIMDS(spt.sender, req, spt.MaxMSIRefreshAttempts)
} else {
@@ -973,6 +1021,11 @@ func retryForIMDS(sender Sender, req *http.Request, maxAttempts int) (resp *http
attempt := 0
delay := time.Duration(0)
// maxAttempts is user-specified, ensure that its value is greater than zero else no request will be made
if maxAttempts < 1 {
maxAttempts = defaultMaxMSIRefreshAttempts
}
for attempt < maxAttempts {
if resp != nil && resp.Body != nil {
io.Copy(ioutil.Discard, resp.Body)
@@ -1134,3 +1187,12 @@ func NewMultiTenantServicePrincipalToken(multiTenantCfg MultiTenantOAuthConfig,
}
return &m, nil
}
// MSIAvailable returns true if the MSI endpoint is available for authentication.
func MSIAvailable(ctx context.Context, sender Sender) bool {
resp, err := getMSIEndpoint(ctx, sender)
if err == nil {
resp.Body.Close()
}
return err == nil
}

View File

@@ -0,0 +1,36 @@
// +build go1.13
// Copyright 2017 Microsoft Corporation
//
// 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.
package adal
import (
"context"
"net/http"
"time"
)
func getMSIEndpoint(ctx context.Context, sender Sender) (*http.Response, error) {
// this cannot fail, the return sig is due to legacy reasons
msiEndpoint, _ := GetMSIVMEndpoint()
tempCtx, cancel := context.WithTimeout(ctx, 500*time.Millisecond)
defer cancel()
// http.NewRequestWithContext() was added in Go 1.13
req, _ := http.NewRequestWithContext(tempCtx, http.MethodGet, msiEndpoint, nil)
q := req.URL.Query()
q.Add("api-version", msiAPIVersion)
req.URL.RawQuery = q.Encode()
return sender.Do(req)
}

View File

@@ -0,0 +1,36 @@
// +build !go1.13
// Copyright 2017 Microsoft Corporation
//
// 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.
package adal
import (
"context"
"net/http"
"time"
)
func getMSIEndpoint(ctx context.Context, sender Sender) (*http.Response, error) {
// this cannot fail, the return sig is due to legacy reasons
msiEndpoint, _ := GetMSIVMEndpoint()
tempCtx, cancel := context.WithTimeout(ctx, 500*time.Millisecond)
defer cancel()
req, _ := http.NewRequest(http.MethodGet, msiEndpoint, nil)
req = req.WithContext(tempCtx)
q := req.URL.Query()
q.Add("api-version", msiAPIVersion)
req.URL.RawQuery = q.Encode()
return sender.Do(req)
}