Skip to content

Commit

Permalink
More refactoring of the auth package (#368)
Browse files Browse the repository at this point in the history
Add methods to obtain a ServicePrincipalToken from file or environment
credential stores.
  • Loading branch information
jhendrixMSFT committed Mar 26, 2019
1 parent 8ac2172 commit 3b1641e
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 32 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# CHANGELOG

## v11.7.0

## New Features

- Added methods to obtain a ServicePrincipalToken on the various credential configuration types in the `auth` package.

## v11.6.1

### Bug Fixes
Expand Down
110 changes: 79 additions & 31 deletions autorest/azure/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,15 @@ func (settings FileSettings) getAADEndpoint() string {
return azure.PublicCloud.ActiveDirectoryEndpoint
}

// ServicePrincipalTokenFromClientCredentials creates a ServicePrincipalToken from the available client credentials.
func (settings FileSettings) ServicePrincipalTokenFromClientCredentials(baseURI string) (*adal.ServicePrincipalToken, error) {
resource, err := settings.getResourceForToken(baseURI)
if err != nil {
return nil, err
}
return settings.ServicePrincipalTokenFromClientCredentialsWithResource(resource)
}

// ClientCredentialsAuthorizer creates an authorizer from the available client credentials.
func (settings FileSettings) ClientCredentialsAuthorizer(baseURI string) (autorest.Authorizer, error) {
resource, err := settings.getResourceForToken(baseURI)
Expand All @@ -358,24 +367,47 @@ func (settings FileSettings) ClientCredentialsAuthorizer(baseURI string) (autore
return settings.ClientCredentialsAuthorizerWithResource(resource)
}

// ClientCredentialsAuthorizerWithResource creates an authorizer from the available client credentials and the specified resource.
func (settings FileSettings) ClientCredentialsAuthorizerWithResource(resource string) (autorest.Authorizer, error) {
// ServicePrincipalTokenFromClientCredentialsWithResource creates a ServicePrincipalToken
// from the available client credentials and the specified resource.
func (settings FileSettings) ServicePrincipalTokenFromClientCredentialsWithResource(resource string) (*adal.ServicePrincipalToken, error) {
if _, ok := settings.Values[ClientSecret]; !ok {
return nil, errors.New("missing client secret")
}
config, err := adal.NewOAuthConfig(settings.getAADEndpoint(), settings.Values[TenantID])
if err != nil {
return nil, err
}
return adal.NewServicePrincipalToken(*config, settings.Values[ClientID], settings.Values[ClientSecret], resource)
}

spToken, err := adal.NewServicePrincipalToken(*config, settings.Values[ClientID], settings.Values[ClientSecret], resource)
func (settings FileSettings) clientCertificateConfigWithResource(resource string) (ClientCertificateConfig, error) {
if _, ok := settings.Values[CertificatePath]; !ok {
return ClientCertificateConfig{}, errors.New("missing certificate path")
}
cfg := NewClientCertificateConfig(settings.Values[CertificatePath], settings.Values[CertificatePassword], settings.Values[ClientID], settings.Values[TenantID])
cfg.AADEndpoint = settings.getAADEndpoint()
cfg.Resource = resource
return cfg, nil
}

// ClientCredentialsAuthorizerWithResource creates an authorizer from the available client credentials and the specified resource.
func (settings FileSettings) ClientCredentialsAuthorizerWithResource(resource string) (autorest.Authorizer, error) {
spToken, err := settings.ServicePrincipalTokenFromClientCredentialsWithResource(resource)
if err != nil {
return nil, err
}

return autorest.NewBearerAuthorizer(spToken), nil
}

// ServicePrincipalTokenFromClientCertificate creates a ServicePrincipalToken from the available certificate credentials.
func (settings FileSettings) ServicePrincipalTokenFromClientCertificate(baseURI string) (*adal.ServicePrincipalToken, error) {
resource, err := settings.getResourceForToken(baseURI)
if err != nil {
return nil, err
}
return settings.ServicePrincipalTokenFromClientCertificateWithResource(resource)
}

// ClientCertificateAuthorizer creates an authorizer from the available certificate credentials.
func (settings FileSettings) ClientCertificateAuthorizer(baseURI string) (autorest.Authorizer, error) {
resource, err := settings.getResourceForToken(baseURI)
Expand All @@ -385,14 +417,21 @@ func (settings FileSettings) ClientCertificateAuthorizer(baseURI string) (autore
return settings.ClientCertificateAuthorizerWithResource(resource)
}

// ServicePrincipalTokenFromClientCertificateWithResource creates a ServicePrincipalToken from the available certificate credentials.
func (settings FileSettings) ServicePrincipalTokenFromClientCertificateWithResource(resource string) (*adal.ServicePrincipalToken, error) {
cfg, err := settings.clientCertificateConfigWithResource(resource)
if err != nil {
return nil, err
}
return cfg.ServicePrincipalToken()
}

// ClientCertificateAuthorizerWithResource creates an authorizer from the available certificate credentials and the specified resource.
func (settings FileSettings) ClientCertificateAuthorizerWithResource(resource string) (autorest.Authorizer, error) {
if _, ok := settings.Values[CertificatePath]; !ok {
return nil, errors.New("missing certificate path")
cfg, err := settings.clientCertificateConfigWithResource(resource)
if err != nil {
return nil, err
}
cfg := NewClientCertificateConfig(settings.Values[CertificatePath], settings.Values[CertificatePassword], settings.Values[ClientID], settings.Values[TenantID])
cfg.AADEndpoint = settings.getAADEndpoint()
cfg.Resource = resource
return cfg.Authorizer()
}

Expand Down Expand Up @@ -511,18 +550,21 @@ type ClientCredentialsConfig struct {
Resource string
}

// Authorizer gets the authorizer from client credentials.
func (ccc ClientCredentialsConfig) Authorizer() (autorest.Authorizer, error) {
// ServicePrincipalToken creates a ServicePrincipalToken from client credentials.
func (ccc ClientCredentialsConfig) ServicePrincipalToken() (*adal.ServicePrincipalToken, error) {
oauthConfig, err := adal.NewOAuthConfig(ccc.AADEndpoint, ccc.TenantID)
if err != nil {
return nil, err
}
return adal.NewServicePrincipalToken(*oauthConfig, ccc.ClientID, ccc.ClientSecret, ccc.Resource)
}

spToken, err := adal.NewServicePrincipalToken(*oauthConfig, ccc.ClientID, ccc.ClientSecret, ccc.Resource)
// Authorizer gets the authorizer from client credentials.
func (ccc ClientCredentialsConfig) Authorizer() (autorest.Authorizer, error) {
spToken, err := ccc.ServicePrincipalToken()
if err != nil {
return nil, fmt.Errorf("failed to get oauth token from client credentials: %v", err)
}

return autorest.NewBearerAuthorizer(spToken), nil
}

Expand All @@ -536,26 +578,29 @@ type ClientCertificateConfig struct {
Resource string
}

// Authorizer gets an authorizer object from client certificate.
func (ccc ClientCertificateConfig) Authorizer() (autorest.Authorizer, error) {
// ServicePrincipalToken creates a ServicePrincipalToken from client certificate.
func (ccc ClientCertificateConfig) ServicePrincipalToken() (*adal.ServicePrincipalToken, error) {
oauthConfig, err := adal.NewOAuthConfig(ccc.AADEndpoint, ccc.TenantID)

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 := decodePkcs12(certData, ccc.CertificatePassword)
if err != nil {
return nil, fmt.Errorf("failed to decode pkcs12 certificate while creating spt: %v", err)
}
return adal.NewServicePrincipalTokenFromCertificate(*oauthConfig, ccc.ClientID, certificate, rsaPrivateKey, ccc.Resource)
}

spToken, err := adal.NewServicePrincipalTokenFromCertificate(*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 err != nil {
return nil, fmt.Errorf("failed to get oauth token from certificate auth: %v", err)
}

return autorest.NewBearerAuthorizer(spToken), nil
}

Expand All @@ -573,26 +618,25 @@ func (dfc DeviceFlowConfig) Authorizer() (autorest.Authorizer, error) {
if err != nil {
return nil, fmt.Errorf("failed to get oauth token from device flow: %v", err)
}

return autorest.NewBearerAuthorizer(spToken), nil
}

// ServicePrincipalToken gets the service principal token from device flow.
func (dfc DeviceFlowConfig) ServicePrincipalToken() (*adal.ServicePrincipalToken, error) {
oauthClient := &autorest.Client{}
oauthConfig, err := adal.NewOAuthConfig(dfc.AADEndpoint, dfc.TenantID)
if err != nil {
return nil, err
}
oauthClient := &autorest.Client{}
deviceCode, err := adal.InitiateDeviceAuth(oauthClient, *oauthConfig, dfc.ClientID, dfc.Resource)
if err != nil {
return nil, fmt.Errorf("failed to start device auth flow: %s", err)
}

log.Println(*deviceCode.Message)

token, err := adal.WaitForUserCompletion(oauthClient, deviceCode)
if err != nil {
return nil, fmt.Errorf("failed to finish device auth flow: %s", err)
}

return adal.NewServicePrincipalTokenFromManualToken(*oauthConfig, dfc.ClientID, dfc.Resource, *token)
}

Expand Down Expand Up @@ -620,17 +664,21 @@ type UsernamePasswordConfig struct {
Resource string
}

// Authorizer gets the authorizer from a username and a password.
func (ups UsernamePasswordConfig) Authorizer() (autorest.Authorizer, error) {

// ServicePrincipalToken creates a ServicePrincipalToken from username and password.
func (ups UsernamePasswordConfig) ServicePrincipalToken() (*adal.ServicePrincipalToken, error) {
oauthConfig, err := adal.NewOAuthConfig(ups.AADEndpoint, ups.TenantID)
if err != nil {
return nil, err
}
return adal.NewServicePrincipalTokenFromUsernamePassword(*oauthConfig, ups.ClientID, ups.Username, ups.Password, ups.Resource)
}

spToken, err := adal.NewServicePrincipalTokenFromUsernamePassword(*oauthConfig, ups.ClientID, ups.Username, ups.Password, ups.Resource)

// Authorizer gets the authorizer from a username and a password.
func (ups UsernamePasswordConfig) Authorizer() (autorest.Authorizer, error) {
spToken, err := ups.ServicePrincipalToken()
if err != nil {
return nil, fmt.Errorf("failed to get oauth token from username and password auth: %v", err)
}

return autorest.NewBearerAuthorizer(spToken), nil
}

Expand Down
2 changes: 1 addition & 1 deletion autorest/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
"runtime"
)

const number = "v11.6.1"
const number = "v11.7.0"

var (
userAgent = fmt.Sprintf("Go/%s (%s-%s) go-autorest/%s",
Expand Down

0 comments on commit 3b1641e

Please sign in to comment.