Skip to content
This repository was archived by the owner on Jul 22, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion docs/help/Get-PartnerUser.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Gets a list of users from the partner tenant
## SYNTAX

```powershell
Get-PartnerUser [<CommonParameters>]
Get-PartnerUser [-UserId <String>] [-UserPrincipalName <String>] [<CommonParameters>]
```

## DESCRIPTION
Expand All @@ -32,6 +32,36 @@ Gets a list of users from the partner tenant

## PARAMETERS

### -UserId
The identifier for the user.

```yaml
Type: String
Parameter Sets: (All)
Aliases:

Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```

### -UserPrincipalName
The user principal name for the user.

```yaml
Type: String
Parameter Sets: (All)
Aliases: UPN

Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```

### CommonParameters
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).

Expand Down
23 changes: 16 additions & 7 deletions docs/help/Get-PartnerUserSignInActivity.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Get-PartnerUserSignInActivity [-EndDate <DateTime>] [-StartDate <DateTime>] [-Us
```

## DESCRIPTION
Gets the sign activities for the specified user.
Gets the sign-in activities for the specified user.

## EXAMPLES

Expand All @@ -29,23 +29,23 @@ Gets the sign activities for the specified user.
PS C:\> Get-PartnerUserSignInActivity -UserId '3dd89389-b34c-4f5a-975d-516df5694d7e'
```

Gets the sign activities for the specified user.
Gets the sign-in activities for the specified user.

### Example 2
```powershell
PS C:\> Get-PartnerUserSignInActivity -EndDate (Get-Date) -StartDate (Get-Date).AddDays(-7) -UserId '3dd89389-b34c-4f5a-975d-516df5694d7e'
PS C:\> Get-PartnerUserSignInActivity -StartDate (Get-Date).AddDays(-7) -UserId '3dd89389-b34c-4f5a-975d-516df5694d7e'
```

Gets the sign activities from the past seven days for the specified user.
Gets the sign-in activities from the past seven days for the specified user.

### Example 3
```powershell
PS C:\> $users = Get-PartnerUser
PS C:\> $activities = $users.ForEach({Get-PartnerUserSignInActivity -EndDate (Get-Date) -StartDate (Get-Date).AddDays(-7) -UserId $_.Id})
PS C:\> $activities = $users.ForEach({Get-PartnerUserSignInActivity -StartDate (Get-Date).AddDays(-7) -UserId $_.Id})
PS C:\> $activities | ? {$_.AuthenticationDetails | ? {$_.Succeeded -eq $true}}
```

Gets the sign-activities from the past seven days that have successfully authenticated.
Gets the sign-in activities from the past seven days that have successfully authenticated.

### Example 4
```powershell
Expand All @@ -58,9 +58,18 @@ Gets the sign-in activities from the past seven days where the resource being ac

### Example 5
```powershell
PS C:\> $users = Get-PartnerUser
PS C:\> $activities = $users.ForEach({Get-PartnerUserSignInActivity -StartDate (Get-Date).AddDays(-7) -UserId $_.Id})
PS C:\> $activities | ? {$_.AuthenticationDetails | ? {$_.Succeeded -eq $true}} | ? {$_.MfaDetail -eq $null}
```

Gets the sign-in activities from the past seven days that have successfully authenticated, but have not utilized multi-factor authentication.

### Example 6
```powershell
PS C:> $users = Get-PartnerUser
PS C:> $activities = $users.ForEach({Get-PartnerUserSignInActivity -EndDate (Get-Date) -StartDate (Get-Date).AddDays(-7) -UserId $_.Id})
PS C:> $activities | ? {$_.AuthenticationDetails | ? {$_.Succeeded -eq $true}} | ? {$_.MfaDetail | ? {$_.AuthMethod -eq $null}} | ? {$_.ResourceId -eq 'fa3d9a0c-3fb0-42cc-9193-47c7ecd2edbd'}
PS C:> $activities | ? {$_.AuthenticationDetails | ? {$_.Succeeded -eq $true}} | ? {$_.MfaDetail -eq $null} | ? {$_.ResourceId -eq 'fa3d9a0c-3fb0-42cc-9193-47c7ecd2edbd'}
```

Gets the sign-in activities from the past seven days where the resource being accessed was the Partner Center API and the sign-in activity was not challenged for multi-factor authentication.
Expand Down
6 changes: 3 additions & 3 deletions src/PowerShell/Authenticators/InteractiveUserAuthenticator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public override async Task<AuthenticationResult> AuthenticateAsync(Authenticatio
}
catch (Exception ex)
{
promptAction($"Port {port} is taken with exception '{ex.Message}'; trying to connect to the next port.");
Console.WriteLine($"Port {port} is taken with exception '{ex.Message}'; trying to connect to the next port.");
listener?.Stop();
}
}
Expand All @@ -60,7 +60,7 @@ public override async Task<AuthenticationResult> AuthenticateAsync(Authenticatio

if (app is IConfidentialClientApplication)
{
ICustomWebUi customWebUi = new DefaultOsBrowserWebUi(interactiveParameters.Message, promptAction);
ICustomWebUi customWebUi = new DefaultOsBrowserWebUi(interactiveParameters.Message);

Uri authCodeUrl = await customWebUi.AcquireAuthorizationCodeAsync(
await app.AsConfidentialClient().GetAuthorizationRequestUrl(parameters.Scopes).ExecuteAsync(cancellationToken).ConfigureAwait(false),
Expand All @@ -76,7 +76,7 @@ await app.AsConfidentialClient().GetAuthorizationRequestUrl(parameters.Scopes).E
else
{
authResult = await app.AsPublicClient().AcquireTokenInteractive(parameters.Scopes)
.WithCustomWebUi(new DefaultOsBrowserWebUi(interactiveParameters.Message, promptAction))
.WithCustomWebUi(new DefaultOsBrowserWebUi(interactiveParameters.Message))
.WithPrompt(Prompt.ForceLogin)
.ExecuteAsync(cancellationToken).ConfigureAwait(false);
}
Expand Down
1 change: 1 addition & 0 deletions src/PowerShell/Commands/ConnectPartnerCenter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ protected override void ProcessRecord()
new[] { account.GetProperty(PartnerAccountPropertyType.Scope) },
Message,
WriteWarning,
WriteDebug,
CancellationToken);

PartnerSession.Instance.Context = new PartnerContext
Expand Down
2 changes: 1 addition & 1 deletion src/PowerShell/Commands/GetPartnerCustomer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public override void ExecuteCmdlet()
FieldFilterOperation.StartsWith,
Domain))).ConfigureAwait(false).GetAwaiter().GetResult();
}
else
else
{
seekCustomers = Partner.Customers.GetAsync().ConfigureAwait(false).GetAwaiter().GetResult();
}
Expand Down
40 changes: 32 additions & 8 deletions src/PowerShell/Commands/GetPartnerUser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,51 @@ namespace Microsoft.Store.PartnerCenter.PowerShell.Commands
using Graph;
using Models.Authentication;

/// <summary>
/// Command that gets partner level user accounts.
/// </summary>
[Cmdlet(VerbsCommon.Get, "PartnerUser"), OutputType(typeof(User))]
public class GetPartnerUser : PartnerCmdlet
{
/// <summary>
/// Gets or sets the user identifier.
/// </summary>
[Parameter(HelpMessage = "The identifier for the user.", Mandatory = false)]
public string UserId { get; set; }

/// <summary>
/// Gets or sets the user principal name for the user.
/// </summary>
[Parameter(HelpMessage = "The user principal name for the user.", Mandatory = false)]
[Alias("UPN")]
public string UserPrincipalName { get; set; }

/// <summary>
/// Executes the operations associated with the cmdlet.
/// </summary>
public override void ExecuteCmdlet()
{
IGraphServiceClient client = PartnerSession.Instance.ClientFactory.CreateGraphServiceClient();
IGraphServiceUsersCollectionPage data = client.Users.Request().GetAsync().ConfigureAwait(false).GetAwaiter().GetResult();
List<User> users = new List<User>();

users.AddRange(data.CurrentPage);

while (data.NextPageRequest != null)
if (string.IsNullOrEmpty(UserId) && string.IsNullOrEmpty(UserPrincipalName))
{
data = data.NextPageRequest.GetAsync().ConfigureAwait(false).GetAwaiter().GetResult();
users.AddRange(data.CurrentPage);
IGraphServiceUsersCollectionPage data = client.Users.Request().GetAsync().ConfigureAwait(false).GetAwaiter().GetResult();
List<User> users = new List<User>(data.CurrentPage);

while (data.NextPageRequest != null)
{
data = data.NextPageRequest.GetAsync().ConfigureAwait(false).GetAwaiter().GetResult();
users.AddRange(data.CurrentPage);
}

WriteObject(users, true);
}
else
{
User user = client.Users[string.IsNullOrEmpty(UserPrincipalName) ? UserId : UserPrincipalName].Request().GetAsync().ConfigureAwait(false).GetAwaiter().GetResult();

WriteObject(users, true);
WriteObject(user);
}
}
}
}
1 change: 1 addition & 0 deletions src/PowerShell/Commands/NewPartnerAccessToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ protected override void ProcessRecord()
Scopes,
Message,
WriteWarning,
WriteDebug,
CancellationToken);

byte[] cacheData = SharedTokenCacheClientFactory.GetTokenCache(ApplicationId).SerializeMsalV3();
Expand Down
1 change: 1 addition & 0 deletions src/PowerShell/Commands/TestPartnerSecurityRequirement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ protected override void ProcessRecord()
new[] { $"{environment.PartnerCenterEndpoint}/user_impersonation" },
Message,
WriteWarning,
WriteDebug,
CancellationToken);


Expand Down
43 changes: 15 additions & 28 deletions src/PowerShell/Factories/AuthenticationFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,45 +19,32 @@ internal class AuthenticationFactory : IAuthenticationFactory
{
internal IAuthenticatorBuilder Builder => new DefaultAuthenticatorBuilder();

public AuthenticationResult Authenticate(PartnerAccount account, PartnerEnvironment environment, IEnumerable<string> scopes, string message = null, Action<string> promptAction = null, CancellationToken cancellationToken = default)
public AuthenticationResult Authenticate(PartnerAccount account, PartnerEnvironment environment, IEnumerable<string> scopes, string message = null, Action<string> promptAction = null, Action<string> debugAction = null, CancellationToken cancellationToken = default)
{
AuthenticationResult authResult = null;
IAuthenticator processAuthenticator = Builder.Authenticator;
int retries = 5;

while (retries-- > 0)
while (processAuthenticator != null && processAuthenticator.TryAuthenticate(GetAuthenticationParameters(account, environment, scopes, message), out Task<AuthenticationResult> result, promptAction, cancellationToken))
{
try
authResult = result.ConfigureAwait(true).GetAwaiter().GetResult();

if (authResult != null)
{
while (processAuthenticator != null && processAuthenticator.TryAuthenticate(GetAuthenticationParameters(account, environment, scopes, message), out Task<AuthenticationResult> result, promptAction, cancellationToken))
if (authResult.Account?.HomeAccountId != null)
{
authResult = result.ConfigureAwait(true).GetAwaiter().GetResult();

if (authResult != null)
{
if (authResult.Account?.HomeAccountId != null)
{
account.Identifier = authResult.Account.HomeAccountId.Identifier;
account.ObjectId = authResult.Account.HomeAccountId.ObjectId;
}

if (account.Tenant.Equals("common", StringComparison.InvariantCultureIgnoreCase) && !string.IsNullOrEmpty(authResult.TenantId))
{
account.Tenant = authResult.TenantId;
}

break;
}
account.Identifier = authResult.Account.HomeAccountId.Identifier;
account.ObjectId = authResult.Account.HomeAccountId.ObjectId;
}

processAuthenticator = processAuthenticator.Next;
if (account.Tenant.Equals("common", StringComparison.InvariantCultureIgnoreCase) && !string.IsNullOrEmpty(authResult.TenantId))
{
account.Tenant = authResult.TenantId;
}
}
catch (InvalidOperationException)
{
continue;

break;
}

break;
processAuthenticator = processAuthenticator.Next;
}

return authResult ?? null;
Expand Down
2 changes: 1 addition & 1 deletion src/PowerShell/Factories/IAuthenticationFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ public interface IAuthenticationFactory
/// Acquires the security token from the authority.
/// </summary>
/// <returns>The result from the authentication request.</returns>
AuthenticationResult Authenticate(PartnerAccount account, PartnerEnvironment environment, IEnumerable<string> scopes, string message = null, Action<string> promptAction = null, CancellationToken cancellationToken = default);
AuthenticationResult Authenticate(PartnerAccount account, PartnerEnvironment environment, IEnumerable<string> scopes, string message = null, Action<string> promptAction = null, Action<string> debugAction = null, CancellationToken cancellationToken = default);
}
}
16 changes: 4 additions & 12 deletions src/PowerShell/Network/DefaultOsBrowserWebUi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,6 @@ internal class DefaultOsBrowserWebUi : ICustomWebUi
</body>
</html>";

/// <summary>
/// The action used to prompt for interaction.
/// </summary>
private readonly Action<string> promptAction;

/// <summary>
/// The message written to the console.
/// </summary>
Expand All @@ -55,14 +50,11 @@ internal class DefaultOsBrowserWebUi : ICustomWebUi
/// Initializes a new instance of the <see cref="DefaultOsBrowserWebUi" /> class.
/// </summary>
/// <param name="message">The message written to the console.</param>
/// <param name="promptAction">The action used to prompt for interaction.</param>
public DefaultOsBrowserWebUi(string message, Action<string> promptAction)
public DefaultOsBrowserWebUi(string message)
{
message.AssertNotEmpty(nameof(message));
promptAction.AssertNotNull(nameof(promptAction));

this.message = message;
this.promptAction = promptAction;
}

/// <summary>
Expand All @@ -74,14 +66,14 @@ public DefaultOsBrowserWebUi(string message, Action<string> promptAction)
/// <returns>The URI returned back from the STS authorization endpoint. This URI contains a code=CODE parameter that MSAL.NET will extract and redeem.</returns>
public async Task<Uri> AcquireAuthorizationCodeAsync(Uri authorizationUri, Uri redirectUri, CancellationToken cancellationToken)
{
promptAction("Attempting to launch a browser for authorization code login.");
Console.WriteLine("Attempting to launch a browser for authorization code login.");

if (!OpenBrowser(authorizationUri.ToString()))
{
promptAction("Unable to launch a browser for authorization code login. Reverting to device code login.");
Console.WriteLine("Unable to launch a browser for authorization code login. Reverting to device code login.");
}

promptAction(message);
Console.WriteLine(message);

using (SingleMessageTcpListener listener = new SingleMessageTcpListener(redirectUri.Port))
{
Expand Down
2 changes: 2 additions & 0 deletions src/PowerShell/Network/SingleMessageTcpListener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,9 @@ public void Dispose()
protected virtual void Dispose(bool disposing)
{
if (disposed)
{
return;
}

if (disposing)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class MockAuthenticationFactory : IAuthenticationFactory
/// Acquires the security token from the authority.
/// </summary>
/// <returns>The result from the authentication request.</returns>
public AuthenticationResult Authenticate(PartnerAccount account, PartnerEnvironment environment, IEnumerable<string> scopes, string message, Action<string> promptAction = null, CancellationToken cancellationToken = default)
public AuthenticationResult Authenticate(PartnerAccount account, PartnerEnvironment environment, IEnumerable<string> scopes, string message, Action<string> promptAction = null, Action<string> debugAction = null, CancellationToken cancellationToken = default)
{
return new AuthenticationResult(
"STUB_TOKEN",
Expand Down