github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/provider/azure/credentials.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package azure
     5  
     6  import (
     7  	"github.com/Azure/go-autorest/autorest"
     8  	"github.com/juju/errors"
     9  	"github.com/juju/utils"
    10  	"github.com/juju/utils/clock"
    11  
    12  	"github.com/juju/juju/cloud"
    13  	"github.com/juju/juju/environs"
    14  	"github.com/juju/juju/provider/azure/internal/azureauth"
    15  )
    16  
    17  const (
    18  	credAttrAppId          = "application-id"
    19  	credAttrSubscriptionId = "subscription-id"
    20  	credAttrTenantId       = "tenant-id"
    21  	credAttrAppPassword    = "application-password"
    22  
    23  	// clientCredentialsAuthType is the auth-type for the
    24  	// "client credentials" OAuth flow, which requires a
    25  	// service principal with a password.
    26  	clientCredentialsAuthType cloud.AuthType = "service-principal-secret"
    27  
    28  	// deviceCodeAuthType is the auth-type for the interactive
    29  	// "device code" OAuth flow.
    30  	deviceCodeAuthType cloud.AuthType = "interactive"
    31  )
    32  
    33  // environPoviderCredentials is an implementation of
    34  // environs.ProviderCredentials for the Azure Resource
    35  // Manager cloud provider.
    36  type environProviderCredentials struct {
    37  	sender                            autorest.Sender
    38  	requestInspector                  autorest.PrepareDecorator
    39  	interactiveCreateServicePrincipal azureauth.InteractiveCreateServicePrincipalFunc
    40  }
    41  
    42  // CredentialSchemas is part of the environs.ProviderCredentials interface.
    43  func (environProviderCredentials) CredentialSchemas() map[cloud.AuthType]cloud.CredentialSchema {
    44  	return map[cloud.AuthType]cloud.CredentialSchema{
    45  		// deviceCodeAuthType is the interactive device-code oauth
    46  		// flow. This is only supported on the client side; it will
    47  		// be used to generate a service principal, and transformed
    48  		// into clientCredentialsAuthType.
    49  		deviceCodeAuthType: {{
    50  			credAttrSubscriptionId, cloud.CredentialAttr{Description: "Azure subscription ID"},
    51  		}},
    52  
    53  		// clientCredentialsAuthType is the "client credentials"
    54  		// oauth flow, which requires a service principal with a
    55  		// password.
    56  		clientCredentialsAuthType: {
    57  			{
    58  				credAttrAppId, cloud.CredentialAttr{Description: "Azure Active Directory application ID"},
    59  			}, {
    60  				credAttrSubscriptionId, cloud.CredentialAttr{Description: "Azure subscription ID"},
    61  			}, {
    62  				credAttrAppPassword, cloud.CredentialAttr{
    63  					Description: "Azure Active Directory application password",
    64  					Hidden:      true,
    65  				},
    66  			},
    67  		},
    68  	}
    69  }
    70  
    71  // DetectCredentials is part of the environs.ProviderCredentials interface.
    72  func (environProviderCredentials) DetectCredentials() (*cloud.CloudCredential, error) {
    73  	return nil, errors.NotFoundf("credentials")
    74  }
    75  
    76  // FinalizeCredential is part of the environs.ProviderCredentials interface.
    77  func (c environProviderCredentials) FinalizeCredential(
    78  	ctx environs.FinalizeCredentialContext,
    79  	args environs.FinalizeCredentialParams,
    80  ) (*cloud.Credential, error) {
    81  	switch authType := args.Credential.AuthType(); authType {
    82  	case deviceCodeAuthType:
    83  		subscriptionId := args.Credential.Attributes()[credAttrSubscriptionId]
    84  		applicationId, password, err := c.interactiveCreateServicePrincipal(
    85  			ctx.GetStderr(),
    86  			c.sender,
    87  			c.requestInspector,
    88  			args.CloudEndpoint,
    89  			args.CloudIdentityEndpoint,
    90  			subscriptionId,
    91  			clock.WallClock,
    92  			utils.NewUUID,
    93  		)
    94  		if err != nil {
    95  			return nil, errors.Trace(err)
    96  		}
    97  		out := cloud.NewCredential(clientCredentialsAuthType, map[string]string{
    98  			credAttrSubscriptionId: subscriptionId,
    99  			credAttrAppId:          applicationId,
   100  			credAttrAppPassword:    password,
   101  		})
   102  		out.Label = args.Credential.Label
   103  		return &out, nil
   104  
   105  	case clientCredentialsAuthType:
   106  		return &args.Credential, nil
   107  	default:
   108  		return nil, errors.NotSupportedf("%q auth-type", authType)
   109  	}
   110  }