Skip to content

Commit

Permalink
Update Register-PnPAzureADApp and Register-PnPEntraIDAppForInteractiv…
Browse files Browse the repository at this point in the history
…eLogin

- Added support for the `-LaunchBrowser` parameter to automatically launch a browser and copy the code to enter to the clipboard during app registration.
- Updated the documentation to include information about the new `-LaunchBrowser` parameter.

Related work items: #4299
  • Loading branch information
Gautam Sheth committed Sep 27, 2024
1 parent f42f902 commit f7d1660
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 15 deletions.
17 changes: 17 additions & 0 deletions documentation/Register-PnPAzureADApp.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Register-PnPAzureADApp -ApplicationName <String>
[-MicrosoftGraphEndPoint <string>]
[-EntraIDLoginEndPoint <string>]
[-SignInAudience <EntraIDSignInAudience>]
[-LaunchBrowser <SwitchParameter>]
```

### Existing Certificate
Expand All @@ -59,6 +60,7 @@ Register-PnPAzureADApp -CertificatePath <String>
[-CertificatePassword <SecureString>]
[-NoPopup]
[-LogoFilePath <string>]
[-LaunchBrowser <SwitchParameter>]
```

## DESCRIPTION
Expand Down Expand Up @@ -436,6 +438,21 @@ Position: Named
Accept pipeline input: False
```

### -LaunchBrowser
Launch a browser automatically and copy the code to enter to the clipboard

```yaml
Type: SwitchParameter
Parameter Sets: DeviceLogin
Aliases:
Required: False
Position: Named
Default value: False
Accept pipeline input: False
Accept wildcard characters: False
```

## RELATED LINKS

[Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp)
Expand Down
17 changes: 17 additions & 0 deletions documentation/Register-PnPEntraIDAppForInteractiveLogin.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Register-PnPEntraIDAppForInteractiveLogin -ApplicationName <String>
[-MicrosoftGraphEndPoint <string>]
[-EntraIDLoginEndPoint <string>]
[-SignInAudience <EntraIDSignInAudience>]
[-LaunchBrowser <SwitchParameter>]
```

### Generate App using Device Login
Expand All @@ -42,6 +43,7 @@ Register-PnPEntraIDAppForInteractiveLogin -ApplicationName <String>
[-NoPopup]
[-LogoFilePath <string>]
[-SignInAudience <EntraIDSignInAudience>]
[-LaunchBrowser <SwitchParameter>]
```

## DESCRIPTION
Expand Down Expand Up @@ -227,6 +229,21 @@ Position: Named
Accept pipeline input: False
```

### -LaunchBrowser
Launch a browser automatically and copy the code to enter to the clipboard

```yaml
Type: SwitchParameter
Parameter Sets: DeviceLogin
Aliases:
Required: False
Position: Named
Default value: False
Accept pipeline input: False
Accept wildcard characters: False
```

## RELATED LINKS

[Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp)
Expand Down
23 changes: 20 additions & 3 deletions src/Commands/AzureAD/RegisterAzureADApp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
using System.Diagnostics;
using System.Dynamic;
using PnP.PowerShell.Commands.Enums;
using TextCopy;

namespace PnP.PowerShell.Commands.AzureAD
{
Expand Down Expand Up @@ -104,6 +105,9 @@ public class RegisterAzureADApp : BasePSCmdlet, IDynamicParameters
[Parameter(Mandatory = false)]
public EntraIDSignInAudience SignInAudience;

[Parameter(Mandatory = false, ParameterSetName = "DeviceLogin")]
public SwitchParameter LaunchBrowser;

protected override void ProcessRecord()
{
if (ParameterSpecified(nameof(Store)) && !OperatingSystem.IsWindows())
Expand Down Expand Up @@ -433,7 +437,7 @@ private string GetAuthToken(CmdletMessageWriter messageWriter)
{
Task.Factory.StartNew(() =>
{
token = AzureAuthHelper.AuthenticateDeviceLogin(cancellationTokenSource, messageWriter, NoPopup, AzureEnvironment, MicrosoftGraphEndPoint);
token = AzureAuthHelper.AuthenticateDeviceLogin(cancellationTokenSource, messageWriter, NoPopup, AzureEnvironment, MicrosoftGraphEndPoint, launchBrowser: LaunchBrowser);
if (token == null)
{
messageWriter.WriteWarning("Operation cancelled or no token retrieved.");
Expand Down Expand Up @@ -683,17 +687,30 @@ private void StartConsentFlow(string loginEndPoint, AzureADApp azureApp, string

if (OperatingSystem.IsWindows() && !NoPopup)
{

if (!Stopping)
{

if (ParameterSpecified(nameof(Interactive)))
{
using (var authManager = AuthenticationManager.CreateWithInteractiveLogin(azureApp.AppId, (url, port) =>
{
BrowserHelper.OpenBrowserForInteractiveLogin(url, port, true, cancellationTokenSource);
}, Tenant, "You successfully provided consent", "You failed to provide consent.", AzureEnvironment))
{
authManager.ClearTokenCache();
authManager.GetAccessToken(resource, Microsoft.Identity.Client.Prompt.Consent);
}
}
else if (ParameterSpecified(nameof(DeviceLogin)) && LaunchBrowser)
{
using (var authManager = AuthenticationManager.CreateWithDeviceLogin(azureApp.AppId, Tenant, (deviceCodeResult) =>
{
ClipboardService.SetText(deviceCodeResult.UserCode);
messageWriter.WriteWarning($"\n\nCode {deviceCodeResult.UserCode} has been copied to your clipboard and a new tab in the browser has been opened. Please paste this code in there and proceed.\n\n");
BrowserHelper.OpenBrowserForInteractiveLogin(deviceCodeResult.VerificationUrl, BrowserHelper.FindFreeLocalhostRedirectUri(), false, cancellationTokenSource);
return Task.FromResult(0);
}, AzureEnvironment))
{
authManager.ClearTokenCache();
authManager.GetAccessToken(resource, Microsoft.Identity.Client.Prompt.Consent);
}
}
Expand Down
24 changes: 20 additions & 4 deletions src/Commands/AzureAD/RegisterEntraIDAppForInteractiveLogin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using System.Diagnostics;
using System.Dynamic;
using PnP.PowerShell.Commands.Enums;
using TextCopy;

namespace PnP.PowerShell.Commands.AzureAD
{
Expand Down Expand Up @@ -53,6 +54,9 @@ public class RegisterEntraIDAppForInteractiveLogin : BasePSCmdlet, IDynamicParam
[Parameter(Mandatory = false)]
public EntraIDSignInAudience SignInAudience;

[Parameter(Mandatory = false, ParameterSetName = "DeviceLogin")]
public SwitchParameter LaunchBrowser;

protected override void ProcessRecord()
{
var redirectUri = "http://localhost";
Expand Down Expand Up @@ -354,7 +358,7 @@ private string GetAuthToken(CmdletMessageWriter messageWriter)
{
Task.Factory.StartNew(() =>
{
token = AzureAuthHelper.AuthenticateDeviceLogin(cancellationTokenSource, messageWriter, NoPopup, AzureEnvironment, MicrosoftGraphEndPoint);
token = AzureAuthHelper.AuthenticateDeviceLogin(cancellationTokenSource, messageWriter, NoPopup, AzureEnvironment, MicrosoftGraphEndPoint, launchBrowser: LaunchBrowser);
if (token == null)
{
messageWriter.WriteWarning("Operation cancelled or no token retrieved.");
Expand Down Expand Up @@ -497,20 +501,32 @@ private void StartConsentFlow(string loginEndPoint, AzureADApp azureApp, string
progressRecord.RecordType = ProgressRecordType.Completed;
WriteProgress(progressRecord);


if (OperatingSystem.IsWindows() && !NoPopup)
{

if (!Stopping)
{

if (ParameterSpecified(nameof(Interactive)))
{
using (var authManager = AuthenticationManager.CreateWithInteractiveLogin(azureApp.AppId, (url, port) =>
{
BrowserHelper.OpenBrowserForInteractiveLogin(url, port, true, cancellationTokenSource);
}, Tenant, "You successfully provided consent", "You failed to provide consent.", AzureEnvironment))
{
authManager.ClearTokenCache();
authManager.GetAccessToken(resource, Microsoft.Identity.Client.Prompt.Consent);
}
}
else if (ParameterSpecified(nameof(DeviceLogin)) && LaunchBrowser)
{
using (var authManager = AuthenticationManager.CreateWithDeviceLogin(azureApp.AppId, Tenant, (deviceCodeResult) =>
{
ClipboardService.SetText(deviceCodeResult.UserCode);
messageWriter.WriteWarning($"\n\nCode {deviceCodeResult.UserCode} has been copied to your clipboard and a new tab in the browser has been opened. Please paste this code in there and proceed.\n\n");
BrowserHelper.OpenBrowserForInteractiveLogin(deviceCodeResult.VerificationUrl, BrowserHelper.FindFreeLocalhostRedirectUri(), false, cancellationTokenSource);
return Task.FromResult(0);
}, AzureEnvironment))
{
authManager.ClearTokenCache();
authManager.GetAccessToken(resource, Microsoft.Identity.Client.Prompt.Consent);
}
}
Expand Down
21 changes: 13 additions & 8 deletions src/Commands/Utilities/AzureAuthHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ internal static async Task<string> AuthenticateAsync(string tenantId, string use
throw new ArgumentException($"{nameof(tenantId)} is required");
}

using (var authManager = PnP.Framework.AuthenticationManager.CreateWithCredentials(CLIENTID , username, password, azureEnvironment: azureEnvironment))
using (var authManager = PnP.Framework.AuthenticationManager.CreateWithCredentials(CLIENTID, username, password, azureEnvironment: azureEnvironment))
{
var graphEndpoint = $"https://{AuthenticationManager.GetGraphEndPoint(azureEnvironment)}";
if (azureEnvironment == AzureEnvironment.Custom)
Expand All @@ -28,17 +28,22 @@ internal static async Task<string> AuthenticateAsync(string tenantId, string use
}
}

internal static string AuthenticateDeviceLogin(CancellationTokenSource cancellationTokenSource, CmdletMessageWriter messageWriter, bool noPopup, AzureEnvironment azureEnvironment, string clientId = "1950a258-227b-4e31-a9cf-717495945fc2", string customGraphEndpoint = "")
internal static string AuthenticateDeviceLogin(CancellationTokenSource cancellationTokenSource, CmdletMessageWriter messageWriter, bool noPopup, AzureEnvironment azureEnvironment, string clientId = "1950a258-227b-4e31-a9cf-717495945fc2", string customGraphEndpoint = "", bool launchBrowser = false)
{
try
{
using (var authManager = PnP.Framework.AuthenticationManager.CreateWithDeviceLogin("1950a258-227b-4e31-a9cf-717495945fc2", (result) =>
{
using (var authManager = PnP.Framework.AuthenticationManager.CreateWithDeviceLogin(CLIENTID, (result) =>
{
if (Utilities.OperatingSystem.IsWindows() && !noPopup)
if (launchBrowser)
{
ClipboardService.SetText(result.UserCode);
messageWriter.WriteWarning($"Please login.\n\nWe opened a browser and navigated to {result.VerificationUrl}\n\nEnter code: {result.UserCode} (we copied this code to your clipboard)\n\nNOTICE: close the browser tab after you authenticated successfully to continue the process.");
BrowserHelper.OpenBrowserForInteractiveLogin(result.VerificationUrl, BrowserHelper.FindFreeLocalhostRedirectUri(), false, cancellationTokenSource);
}
else if (!noPopup)
{
ClipboardService.SetText(result.UserCode);
messageWriter.WriteWarning($"Please login.\n\nWe opened a browser and navigated to {result.VerificationUrl}\n\nEnter code: {result.UserCode} (we copied this code to your clipboard)\n\nNOTICE: close the popup after you authenticated successfully to continue the process.");
messageWriter.WriteWarning($"Please login.\n\nWe opened a popup window and navigated to {result.VerificationUrl}\n\nEnter code: {result.UserCode} (we copied this code to your clipboard)\n\nNOTICE: close the popup after you authenticated successfully to continue the process.");
BrowserHelper.GetWebBrowserPopup(result.VerificationUrl, "Please login for PnP PowerShell", cancellationTokenSource: cancellationTokenSource, cancelOnClose: false);
}
else
Expand Down Expand Up @@ -106,6 +111,6 @@ internal static string AuthenticateInteractive(CancellationTokenSource cancellat
cancellationTokenSource.Cancel();
}
return null;
}
}
}
}

0 comments on commit f7d1660

Please sign in to comment.