func()

in cli/azd/cmd/auth_login.go [441:586]


func (la *loginAction) login(ctx context.Context) error {
	if la.flags.federatedTokenProvider == azurePipelinesProvider {
		if la.flags.clientID == "" {
			log.Printf("setting client id from environment variable %s", azurePipelinesClientIDEnvVarName)
			la.flags.clientID = os.Getenv(azurePipelinesClientIDEnvVarName)
		}

		if la.flags.tenantID == "" {
			log.Printf("setting tenant id from environment variable %s", azurePipelinesClientIDEnvVarName)
			la.flags.tenantID = os.Getenv(azurePipelinesTenantIDEnvVarName)
		}
	}

	if la.flags.managedIdentity {
		if _, err := la.authManager.LoginWithManagedIdentity(
			ctx, la.flags.clientID,
		); err != nil {
			return fmt.Errorf("logging in: %w", err)
		}

		return nil
	}

	if !la.flags.managedIdentity && la.flags.clientID != "" {
		if la.flags.tenantID == "" {
			return errors.New("must set both `client-id` and `tenant-id` for service principal login")
		}

		if countTrue(
			la.flags.clientSecret.ptr != nil,
			la.flags.clientCertificate != "",
			la.flags.federatedTokenProvider != "",
		) != 1 {
			return fmt.Errorf(
				"must set exactly one of %s for service principal", strings.Join([]string{
					cClientSecretFlagName,
					cClientCertificateFlagName,
					cFederatedCredentialProviderFlagName,
				}, ", "))
		}

		switch {
		case la.flags.clientSecret.ptr != nil:
			if *la.flags.clientSecret.ptr == "" {
				v, err := la.console.Prompt(ctx, input.ConsoleOptions{
					Message: "Enter your client secret",
				})
				if err != nil {
					return fmt.Errorf("prompting for client secret: %w", err)
				}
				la.flags.clientSecret.ptr = &v
			}

			if _, err := la.authManager.LoginWithServicePrincipalSecret(
				ctx, la.flags.tenantID, la.flags.clientID, *la.flags.clientSecret.ptr,
			); err != nil {
				return fmt.Errorf("logging in: %w", err)
			}
		case la.flags.clientCertificate != "":
			certFile, err := os.Open(la.flags.clientCertificate)
			if err != nil {
				return fmt.Errorf("reading certificate: %w", err)
			}
			defer certFile.Close()

			cert, err := io.ReadAll(certFile)
			if err != nil {
				return fmt.Errorf("reading certificate: %w", err)
			}

			if _, err := la.authManager.LoginWithServicePrincipalCertificate(
				ctx, la.flags.tenantID, la.flags.clientID, cert,
			); err != nil {
				return fmt.Errorf("logging in: %w", err)
			}
		case la.flags.federatedTokenProvider == "github":
			if _, err := la.authManager.LoginWithGitHubFederatedTokenProvider(
				ctx, la.flags.tenantID, la.flags.clientID,
			); err != nil {
				return fmt.Errorf("logging in: %w", err)
			}
		case la.flags.federatedTokenProvider == azurePipelinesProvider:
			serviceConnectionID := os.Getenv(azurePipelinesServiceConnectionIDEnvVarName)

			if serviceConnectionID == "" {
				return fmt.Errorf("must set %s for azure-pipelines federated token provider",
					azurePipelinesServiceConnectionIDEnvVarName)
			}

			if _, err := la.authManager.LoginWithAzurePipelinesFederatedTokenProvider(
				ctx, la.flags.tenantID, la.flags.clientID, serviceConnectionID,
			); err != nil {
				return fmt.Errorf("logging in: %w", err)
			}
		}

		return nil
	}

	if la.authManager.UseExternalAuth() {
		// Request a token and assume the external auth system will prompt the user to log in.
		//
		// TODO(ellismg): We may want instead to call some explicit `/login` endpoint on the external auth system instead
		// of abusing the token request in this manner. This would allow the other end to provide a more tailored experience.
		_, err := la.verifyLoggedIn(ctx)
		return err
	}

	useDevCode, err := parseUseDeviceCode(ctx, la.flags.useDeviceCode, la.commandRunner)
	if err != nil {
		return err
	}
	if useDevCode {
		_, err = la.authManager.LoginWithDeviceCode(ctx, la.flags.tenantID, la.flags.scopes, func(url string) error {
			if !la.flags.global.NoPrompt {
				la.console.Message(ctx, "Then press enter and continue to log in from your browser...")
				la.console.WaitForEnter()
				openWithDefaultBrowser(ctx, la.console, url)
				return nil
			}
			// For no-prompt, Just provide instructions without trying to open the browser
			// If manual browsing is enabled, we don't want to open the browser automatically
			la.console.Message(ctx, fmt.Sprintf("Then, go to: %s", url))
			return nil
		})
		return err
	}

	if oneauth.Supported && !la.flags.browser {
		err = la.authManager.LoginWithOneAuth(ctx, la.flags.tenantID, la.flags.scopes)
	} else {
		_, err = la.authManager.LoginInteractive(ctx, la.flags.scopes,
			&auth.LoginInteractiveOptions{
				TenantID:     la.flags.tenantID,
				RedirectPort: la.flags.redirectPort,
				WithOpenUrl: func(url string) error {
					openWithDefaultBrowser(ctx, la.console, url)
					return nil
				},
			})
	}
	if err != nil {
		err = fmt.Errorf("logging in: %w", err)
	}
	return err
}