Esempio n. 1
0
// tokenFromDeviceFlow prints a message to the screen for user to take action to
// consent application on a browser and in the meanwhile the authentication
// endpoint is polled until user gives consent, denies or the flow times out.
// Returned token must be saved.
func tokenFromDeviceFlow(oauthCfg azure.OAuthConfig, tokenPath, clientID, resource string) (*azure.ServicePrincipalToken, error) {
	cl := oauthClient()
	deviceCode, err := azure.InitiateDeviceAuth(&cl, oauthCfg, clientID, resource)
	if err != nil {
		return nil, fmt.Errorf("Failed to start device auth: %v", err)
	}
	log.Debug("Retrieved device code.", logutil.Fields{
		"expires_in": to.Int64(deviceCode.ExpiresIn),
		"interval":   to.Int64(deviceCode.Interval),
	})

	// Example message: “To sign in, open https://aka.ms/devicelogin and enter
	// the code 0000000 to authenticate.”
	log.Infof("Microsoft Azure: %s", to.String(deviceCode.Message))

	token, err := azure.WaitForUserCompletion(&cl, deviceCode)
	if err != nil {
		return nil, fmt.Errorf("Failed to complete device auth: %v", err)
	}

	spt, err := azure.NewServicePrincipalTokenFromManualToken(oauthCfg, clientID, resource, *token)
	if err != nil {
		return nil, fmt.Errorf("Error constructing service principal token: %v", err)
	}
	return spt, nil
}
Esempio n. 2
0
func getSptFromDeviceFlow(oauthConfig azure.OAuthConfig, clientID, resource string, callbacks ...azure.TokenRefreshCallback) (*azure.ServicePrincipalToken, error) {
	oauthClient := &autorest.Client{}
	deviceCode, err := azure.InitiateDeviceAuth(oauthClient, oauthConfig, clientID, resource)
	if err != nil {
		return nil, fmt.Errorf("failed to start device auth flow: %s", err)
	}

	fmt.Println(*deviceCode.Message)

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

	spt, err := azure.NewServicePrincipalTokenFromManualToken(
		oauthConfig,
		clientID,
		resource,
		*token,
		callbacks...)
	if err != nil {
		return nil, fmt.Errorf("failed to get oauth token from device flow: %v", err)
	}

	return spt, nil
}
Esempio n. 3
0
func getSptFromCachedToken(oauthConfig azure.OAuthConfig, clientID, resource string, callbacks ...azure.TokenRefreshCallback) (*azure.ServicePrincipalToken, error) {
	token, err := azure.LoadToken(tokenCachePath)
	if err != nil {
		return nil, fmt.Errorf("failed to load token from cache: %v", err)
	}

	spt, _ := azure.NewServicePrincipalTokenFromManualToken(
		oauthConfig,
		clientID,
		resource,
		*token,
		callbacks...)

	return spt, nil
}
Esempio n. 4
0
// tokenFromFile returns a token from the specified file if it is found, otherwise
// returns nil. Any error retrieving or creating the token is returned as an error.
func tokenFromFile(say func(string), oauthCfg azure.OAuthConfig, tokenPath, clientID, resource string,
	callback azure.TokenRefreshCallback) (*azure.ServicePrincipalToken, error) {
	say(fmt.Sprintf("Loading auth token from file: %s", tokenPath))
	if _, err := os.Stat(tokenPath); err != nil {
		if os.IsNotExist(err) { // file not found
			return nil, nil
		}
		return nil, err
	}

	token, err := azure.LoadToken(tokenPath)
	if err != nil {
		return nil, fmt.Errorf("Failed to load token from file: %v", err)
	}

	spt, err := azure.NewServicePrincipalTokenFromManualToken(oauthCfg, clientID, resource, *token, callback)
	if err != nil {
		return nil, fmt.Errorf("Error constructing service principal token: %v", err)
	}
	return spt, nil
}
Esempio n. 5
0
// tokenFromDeviceFlow prints a message to the screen for user to take action to
// consent application on a browser and in the meanwhile the authentication
// endpoint is polled until user gives consent, denies or the flow times out.
// Returned token must be saved.
func tokenFromDeviceFlow(say func(string), oauthCfg azure.OAuthConfig, tokenPath, clientID, resource string) (*azure.ServicePrincipalToken, error) {
	cl := autorest.NewClientWithUserAgent(userAgent)
	deviceCode, err := azure.InitiateDeviceAuth(&cl, oauthCfg, clientID, resource)
	if err != nil {
		return nil, fmt.Errorf("Failed to start device auth: %v", err)
	}

	// Example message: “To sign in, open https://aka.ms/devicelogin and enter
	// the code 0000000 to authenticate.”
	say(fmt.Sprintf("Microsoft Azure: %s", to.String(deviceCode.Message)))

	token, err := azure.WaitForUserCompletion(&cl, deviceCode)
	if err != nil {
		return nil, fmt.Errorf("Failed to complete device auth: %v", err)
	}

	spt, err := azure.NewServicePrincipalTokenFromManualToken(oauthCfg, clientID, resource, *token)
	if err != nil {
		return nil, fmt.Errorf("Error constructing service principal token: %v", err)
	}
	return spt, nil
}
Esempio n. 6
0
// InteractiveCreateServicePrincipal interactively creates service
// principals for a subscription.
func InteractiveCreateServicePrincipal(
	stderr io.Writer,
	sender autorest.Sender,
	requestInspector autorest.PrepareDecorator,
	resourceManagerEndpoint string,
	graphEndpoint string,
	subscriptionId string,
	clock clock.Clock,
	newUUID func() (utils.UUID, error),
) (appId, password string, _ error) {

	subscriptionsClient := subscriptions.Client{
		subscriptions.NewWithBaseURI(resourceManagerEndpoint),
	}
	subscriptionsClient.Sender = sender
	setClientInspectors(&subscriptionsClient.Client, requestInspector, "azure.subscriptions")

	oauthConfig, tenantId, err := OAuthConfig(
		subscriptionsClient,
		resourceManagerEndpoint,
		subscriptionId,
	)
	if err != nil {
		return "", "", errors.Trace(err)
	}

	client := autorest.NewClientWithUserAgent("juju")
	client.Sender = sender
	setClientInspectors(&client, requestInspector, "azure.autorest")

	// Perform the interactive authentication. The user will be prompted to
	// open a URL and input a device code, after which they will have to
	// enter their username and password if they are not already
	// authenticated with Azure.
	fmt.Fprintln(stderr, "Initiating interactive authentication.")
	fmt.Fprintln(stderr)
	armResource := TokenResource(resourceManagerEndpoint)
	clientId := jujuApplicationId
	deviceCode, err := azure.InitiateDeviceAuth(&client, *oauthConfig, clientId, armResource)
	if err != nil {
		return "", "", errors.Annotate(err, "initiating interactive authentication")
	}
	fmt.Fprintln(stderr, to.String(deviceCode.Message)+"\n")
	token, err := azure.WaitForUserCompletion(&client, deviceCode)
	if err != nil {
		return "", "", errors.Annotate(err, "waiting for interactive authentication to completed")
	}

	// Create service principal tokens that we can use to authorize API
	// requests to Active Directory and Resource Manager. These tokens
	// are only valid for a short amount of time, so we must create a
	// service principal password that can be used to obtain new tokens.
	armSpt, err := azure.NewServicePrincipalTokenFromManualToken(*oauthConfig, clientId, armResource, *token)
	if err != nil {
		return "", "", errors.Annotate(err, "creating temporary ARM service principal token")
	}
	if client.Sender != nil {
		armSpt.SetSender(client.Sender)
	}
	if err := armSpt.Refresh(); err != nil {
		return "", "", errors.Trace(err)
	}

	// The application requires permissions for both ARM and AD, so we
	// can use the token for both APIs.
	graphResource := TokenResource(graphEndpoint)
	graphToken := armSpt.Token
	graphToken.Resource = graphResource
	graphSpt, err := azure.NewServicePrincipalTokenFromManualToken(*oauthConfig, clientId, graphResource, graphToken)
	if err != nil {
		return "", "", errors.Annotate(err, "creating temporary Graph service principal token")
	}
	if client.Sender != nil {
		graphSpt.SetSender(client.Sender)
	}
	if err := graphSpt.Refresh(); err != nil {
		return "", "", errors.Trace(err)
	}

	directoryURL, err := url.Parse(graphEndpoint)
	if err != nil {
		return "", "", errors.Annotate(err, "parsing identity endpoint")
	}
	directoryURL.Path = path.Join(directoryURL.Path, tenantId)
	directoryClient := ad.NewManagementClient(directoryURL.String())
	authorizationClient := authorization.NewWithBaseURI(resourceManagerEndpoint, subscriptionId)
	directoryClient.Authorizer = graphSpt
	authorizationClient.Authorizer = armSpt
	authorizationClient.Sender = client.Sender
	directoryClient.Sender = client.Sender
	setClientInspectors(&directoryClient.Client, requestInspector, "azure.directory")
	setClientInspectors(&authorizationClient.Client, requestInspector, "azure.authorization")

	userObject, err := ad.UsersClient{directoryClient}.GetCurrentUser()
	if err != nil {
		return "", "", errors.Trace(err)
	}
	fmt.Fprintf(stderr, "Authenticated as %q.\n", userObject.DisplayName)

	fmt.Fprintln(stderr, "Creating/updating service principal.")
	servicePrincipalObjectId, password, err := createOrUpdateServicePrincipal(
		ad.ServicePrincipalsClient{directoryClient},
		subscriptionId,
		clock,
		newUUID,
	)
	if err != nil {
		return "", "", errors.Trace(err)
	}

	fmt.Fprintln(stderr, "Assigning Owner role to service principal.")
	if err := createRoleAssignment(
		authorizationClient,
		subscriptionId,
		servicePrincipalObjectId,
		newUUID,
	); err != nil {
		return "", "", errors.Trace(err)
	}
	return jujuApplicationId, password, nil
}