From 6788b77e7039585f5c0dcc48196987cbd024fb02 Mon Sep 17 00:00:00 2001 From: Joel Hendrix Date: Fri, 4 Dec 2020 14:14:33 -0800 Subject: [PATCH] Add multi-tenant certificate auth support Added field AuxTenants to ClientCertificateConfig type, allowing for certificate-based authorization across multiple tenants. This builds on new functionality in the latest adal module. --- autorest/azure/auth/auth.go | 31 ++++++++++++++++++++++++++++--- autorest/azure/auth/go.mod | 4 ++-- autorest/azure/auth/go.sum | 6 ++++-- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/autorest/azure/auth/auth.go b/autorest/azure/auth/auth.go index d4f0c4421..5b1f5a2a2 100644 --- a/autorest/azure/auth/auth.go +++ b/autorest/azure/auth/auth.go @@ -610,6 +610,7 @@ type ClientCertificateConfig struct { CertificatePath string CertificatePassword string TenantID string + AuxTenants []string AADEndpoint string Resource string } @@ -631,13 +632,37 @@ func (ccc ClientCertificateConfig) ServicePrincipalToken() (*adal.ServicePrincip return adal.NewServicePrincipalTokenFromCertificate(*oauthConfig, ccc.ClientID, certificate, rsaPrivateKey, ccc.Resource) } +// MultiTenantServicePrincipalToken creates a MultiTenantServicePrincipalToken from client certificate. +func (ccc ClientCertificateConfig) MultiTenantServicePrincipalToken() (*adal.MultiTenantServicePrincipalToken, error) { + oauthConfig, err := adal.NewMultiTenantOAuthConfig(ccc.AADEndpoint, ccc.TenantID, ccc.AuxTenants, adal.OAuthOptions{}) + if err != nil { + return nil, err + } + certData, err := ioutil.ReadFile(ccc.CertificatePath) + if err != nil { + return nil, fmt.Errorf("failed to read the certificate file (%s): %v", ccc.CertificatePath, err) + } + certificate, rsaPrivateKey, err := adal.DecodePfxCertificateData(certData, ccc.CertificatePassword) + if err != nil { + return nil, fmt.Errorf("failed to decode pkcs12 certificate while creating spt: %v", err) + } + return adal.NewMultiTenantServicePrincipalTokenFromCertificate(oauthConfig, ccc.ClientID, certificate, rsaPrivateKey, ccc.Resource) +} + // Authorizer gets an authorizer object from client certificate. func (ccc ClientCertificateConfig) Authorizer() (autorest.Authorizer, error) { - spToken, err := ccc.ServicePrincipalToken() + if len(ccc.AuxTenants) == 0 { + spToken, err := ccc.ServicePrincipalToken() + if err != nil { + return nil, fmt.Errorf("failed to get oauth token from certificate auth: %v", err) + } + return autorest.NewBearerAuthorizer(spToken), nil + } + mtSPT, err := ccc.MultiTenantServicePrincipalToken() if err != nil { - return nil, fmt.Errorf("failed to get oauth token from certificate auth: %v", err) + return nil, fmt.Errorf("failed to get multitenant SPT from certificate auth: %v", err) } - return autorest.NewBearerAuthorizer(spToken), nil + return autorest.NewMultiTenantServicePrincipalTokenAuthorizer(mtSPT), nil } // DeviceFlowConfig provides the options to get a bearer authorizer using device flow authentication. diff --git a/autorest/azure/auth/go.mod b/autorest/azure/auth/go.mod index 882b9cc73..c95c64663 100644 --- a/autorest/azure/auth/go.mod +++ b/autorest/azure/auth/go.mod @@ -4,8 +4,8 @@ go 1.12 require ( github.com/Azure/go-autorest v14.2.0+incompatible - github.com/Azure/go-autorest/autorest v0.11.9 - github.com/Azure/go-autorest/autorest/adal v0.9.5 + github.com/Azure/go-autorest/autorest v0.11.13 + github.com/Azure/go-autorest/autorest/adal v0.9.8 github.com/Azure/go-autorest/autorest/azure/cli v0.4.2 github.com/Azure/go-autorest/logger v0.2.0 github.com/dimchansky/utfbom v1.1.0 diff --git a/autorest/azure/auth/go.sum b/autorest/azure/auth/go.sum index 9b3ea4aae..3a85288af 100644 --- a/autorest/azure/auth/go.sum +++ b/autorest/azure/auth/go.sum @@ -1,9 +1,11 @@ github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.11.9 h1:P0ZF0dEYoUPUVDQo3mA1CvH5b8mKev7DDcmTwauuNME= -github.com/Azure/go-autorest/autorest v0.11.9/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= +github.com/Azure/go-autorest/autorest v0.11.13 h1:XKx/sB3bfadpXBBHPc7tP2XPKhzVyrdhxpDC3T0wqjs= +github.com/Azure/go-autorest/autorest v0.11.13/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= github.com/Azure/go-autorest/autorest/adal v0.9.5 h1:Y3bBUV4rTuxenJJs41HU3qmqsb+auo+a3Lz+PlJPpL0= github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/adal v0.9.8 h1:bW6ZdxqMYWsxGikpM62SSE3jnvOXVu9SXzJTuj1WM3Y= +github.com/Azure/go-autorest/autorest/adal v0.9.8/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= github.com/Azure/go-autorest/autorest/azure/cli v0.4.2 h1:dMOmEJfkLKW/7JsokJqkyoYSgmR08hi9KrhjZb+JALY= github.com/Azure/go-autorest/autorest/azure/cli v0.4.2/go.mod h1:7qkJkT+j6b+hIpzMOwPChJhTqS8VbsqqgULzMNRugoM= github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=