added --list-tenants internal command + unit test (#1538)

* added --list-tenants internal command + unit test

* cleaning up imports.

* PR fixes
This commit is contained in:
Deep Choudhery 2021-03-29 18:12:37 -07:00 коммит произвёл GitHub
Родитель 4d0fcb6048
Коммит be2470ed5f
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
22 изменённых файлов: 344 добавлений и 68 удалений

21
All.sln
Просмотреть файл

@ -116,6 +116,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.MsIdentity
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-msidentity", "tools\dotnet-msidentity\dotnet-msidentity.csproj", "{1DB98E3A-0749-4ACE-9EF2-EF6BC2C6648B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.DotNet.MsIdentity.UnitTests.Tests", "test\MsIdentityScaffolding\Microsoft.DotNet.MsIdentity.UnitTests.Tests\Microsoft.DotNet.MsIdentity.UnitTests.Tests.csproj", "{0711777C-64C2-49DC-A9CE-67BD641AA7A6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
debug_x86|Any CPU = debug_x86|Any CPU
@ -705,6 +707,24 @@ Global
{1DB98E3A-0749-4ACE-9EF2-EF6BC2C6648B}.Release|x64.Build.0 = Release|Any CPU
{1DB98E3A-0749-4ACE-9EF2-EF6BC2C6648B}.Release|x86.ActiveCfg = Release|Any CPU
{1DB98E3A-0749-4ACE-9EF2-EF6BC2C6648B}.Release|x86.Build.0 = Release|Any CPU
{0711777C-64C2-49DC-A9CE-67BD641AA7A6}.debug_x86|Any CPU.ActiveCfg = Debug|Any CPU
{0711777C-64C2-49DC-A9CE-67BD641AA7A6}.debug_x86|Any CPU.Build.0 = Debug|Any CPU
{0711777C-64C2-49DC-A9CE-67BD641AA7A6}.debug_x86|x64.ActiveCfg = Debug|Any CPU
{0711777C-64C2-49DC-A9CE-67BD641AA7A6}.debug_x86|x64.Build.0 = Debug|Any CPU
{0711777C-64C2-49DC-A9CE-67BD641AA7A6}.debug_x86|x86.ActiveCfg = Debug|Any CPU
{0711777C-64C2-49DC-A9CE-67BD641AA7A6}.debug_x86|x86.Build.0 = Debug|Any CPU
{0711777C-64C2-49DC-A9CE-67BD641AA7A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0711777C-64C2-49DC-A9CE-67BD641AA7A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0711777C-64C2-49DC-A9CE-67BD641AA7A6}.Debug|x64.ActiveCfg = Debug|Any CPU
{0711777C-64C2-49DC-A9CE-67BD641AA7A6}.Debug|x64.Build.0 = Debug|Any CPU
{0711777C-64C2-49DC-A9CE-67BD641AA7A6}.Debug|x86.ActiveCfg = Debug|Any CPU
{0711777C-64C2-49DC-A9CE-67BD641AA7A6}.Debug|x86.Build.0 = Debug|Any CPU
{0711777C-64C2-49DC-A9CE-67BD641AA7A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0711777C-64C2-49DC-A9CE-67BD641AA7A6}.Release|Any CPU.Build.0 = Release|Any CPU
{0711777C-64C2-49DC-A9CE-67BD641AA7A6}.Release|x64.ActiveCfg = Release|Any CPU
{0711777C-64C2-49DC-A9CE-67BD641AA7A6}.Release|x64.Build.0 = Release|Any CPU
{0711777C-64C2-49DC-A9CE-67BD641AA7A6}.Release|x86.ActiveCfg = Release|Any CPU
{0711777C-64C2-49DC-A9CE-67BD641AA7A6}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -747,6 +767,7 @@ Global
{35BA8FDE-4AF3-4EF5-94B3-123B4702AF7E} = {3354705C-5C05-41C3-95E1-31A45141A6C2}
{6B863A66-CFFC-42B4-9316-13B168CB6C62} = {49D385E7-A045-4C54-868F-CEA8F67EDBA8}
{1DB98E3A-0749-4ACE-9EF2-EF6BC2C6648B} = {4B56CCB9-2693-492A-A0C5-B4D15DDF00A4}
{0711777C-64C2-49DC-A9CE-67BD641AA7A6} = {49D385E7-A045-4C54-868F-CEA8F67EDBA8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {26BCDDB3-5505-4903-9D87-C942ED0D03E6}

Просмотреть файл

@ -2,9 +2,10 @@
"solution": {
"path": "All.sln",
"projects": [
"src\\MsIdentityScaffolding\\Microsoft.DotNet.MsIdentity\\Microsoft.DotNet.MsIdentity.csproj",
"tools\\dotnet-msidentity\\dotnet-msidentity.csproj",
"test\\MsIdentityScaffolding\\Microsoft.DotNet.MsIdentity.Tests\\Microsoft.DotNet.MsIdentity.Tests.csproj"
"src\\MsIdentityScaffolding\\Microsoft.DotNet.MsIdentity\\Microsoft.DotNet.MsIdentity.csproj",
"test\\MsIdentityScaffolding\\Microsoft.DotNet.MsIdentity.Tests\\Microsoft.DotNet.MsIdentity.Tests.csproj",
"test\\MsIdentityScaffolding\\Microsoft.DotNet.MsIdentity.UnitTests.Tests\\Microsoft.DotNet.MsIdentity.UnitTests.Tests.csproj",
"tools\\dotnet-msidentity\\dotnet-msidentity.csproj"
]
}
}

Просмотреть файл

@ -1,5 +1,4 @@
set VERSION=0.0.1-dev
set DEFAULT_NUPKG_PATH=%userprofile%/.nuget/packages
set SRC_DIR=%cd%
set NUPKG=artifacts/packages/Debug/Shipping/
@ -8,8 +7,8 @@ call rd /Q /S artifacts
call dotnet build MsIdentityScaffolding.slnf
call dotnet pack MsIdentityScaffolding.slnf
call dotnet tool uninstall -g dotnet-msidentity
call dotnet tool uninstall -g Microsoft.dotnet-msidentity
call cd %SRC_DIR%/%NUPKG%
call dotnet tool install -g dotnet-msidentity --add-source %SRC_DIR%\%NUPKG% --version %VERSION%
call dotnet tool install -g Microsoft.dotnet-msidentity --add-source %SRC_DIR%\%NUPKG% --version %VERSION%
call cd %SRC_DIR%

Просмотреть файл

@ -6,7 +6,7 @@ NUPKG=artifacts/packages/Debug/Shipping/
pkill -f dotnet
rm -rf artifacts
./build.sh
dotnet tool uninstall -g dotnet-msidentity
dotnet tool uninstall -g Microsoft.dotnet-msidentity
cd $SRC_DIR/$NUPKG
dotnet tool install -g dotnet-msidentity --add-source $SRC_DIR/$NUPKG --version $VERSION
dotnet tool install -g Microsoft.dotnet-msidentity --add-source $SRC_DIR/$NUPKG --version $VERSION
cd "$OLDPWD"

Просмотреть файл

@ -6,7 +6,7 @@ call taskkill /f /im dotnet.exe
call rd /Q /S artifacts
call dotnet build Scaffolding.slnf
call dotnet pack Scaffolding.slnf
call dotnet tool uninstall -g dotnet-scaffold
call dotnet tool uninstall -g Microsoft.dotnet-scaffold
call cd %DEFAULT_NUPKG_PATH%
call rd /Q /S microsoft.visualstudio.web.codegeneration
@ -19,5 +19,5 @@ call rd /Q /S microsoft.visualstudio.web.codegeneration.utils
call rd /Q /S microsoft.visualstudio.web.codegenerators.mvc
call cd %SRC_DIR%/%NUPKG%
call dotnet tool install -g dotnet-scaffold --add-source %SRC_DIR%\%NUPKG% --version %VERSION%
call dotnet tool install -g Microsoft.dotnet-scaffold --add-source %SRC_DIR%\%NUPKG% --version %VERSION%
call cd %SRC_DIR%

Просмотреть файл

@ -10,7 +10,7 @@ NUPKG=artifacts/packages/Debug/Shipping/
pkill -f dotnet
rm -rf artifacts
./build.sh
dotnet tool uninstall -g dotnet-scaffold
dotnet tool uninstall -g Microsoft.dotnet-scaffold
cd $DEFAULT_NUPKG_PATH
rm -rf microsoft.visualstudio.web.codegeneration
rm -rf microsoft.visualstudio.web.codegeneration.contracts
@ -21,5 +21,5 @@ rm -rf microsoft.visualstudio.web.codegeneration.templating
rm -rf microsoft.visualstudio.web.codegeneration.utils
rm -rf microsoft.visualstudio.web.codegenerators.mvc
cd "$OLDPWD"/$NUPKG
dotnet tool install -g dotnet-scaffold --add-source $SRC_DIR/$NUPKG --version $VERSION
dotnet tool install -g Microsoft.dotnet-scaffold --add-source $SRC_DIR/$NUPKG --version $VERSION
cd "$OLDPWD"

Просмотреть файл

@ -0,0 +1,59 @@
using Azure.Core;
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.DotNet.MsIdentity.DeveloperCredentials
{
internal class AzureManagementAuthenticationProvider : IAzureManagementAuthenticationProvider
{
readonly TokenCredential _tokenCredentials;
readonly string[] _initialScopes;
private const string AzureManagementAPIDefault = "https://management.azure.com/.default";
private const string AzureManagementTenantsAPI = "https://management.azure.com/tenants?api-version=2020-01-01";
public AzureManagementAuthenticationProvider(TokenCredential tokenCredentials)
{
_tokenCredentials = tokenCredentials;
_initialScopes = new string[] { AzureManagementAPIDefault };
}
private async Task<HttpRequestMessage> AuthenticateRequestAsync(HttpRequestMessage request)
{
HttpRequestMessage authenticatedRequest = request;
TokenRequestContext context = new TokenRequestContext(_initialScopes);
AccessToken token = await _tokenCredentials.GetTokenAsync(context, CancellationToken.None);
authenticatedRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.Token);
return authenticatedRequest;
}
public async Task<string> ListTenantsAsync()
{
string content = string.Empty;
var httpRequest = new HttpRequestMessage()
{
RequestUri = new Uri(AzureManagementTenantsAPI),
Method = HttpMethod.Get
};
httpRequest = await AuthenticateRequestAsync(httpRequest);
using (var client = new HttpClient())
{
var task = await client.SendAsync(httpRequest)
.ContinueWith(async (taskWithMssg) =>
{
var response = taskWithMssg.Result;
response.EnsureSuccessStatusCode();
if (response.IsSuccessStatusCode)
{
content = await response.Content.ReadAsStringAsync();
}
});
await task;
}
return content;
}
}
}

Просмотреть файл

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace Microsoft.DotNet.MsIdentity.DeveloperCredentials
{
public interface IAzureManagementAuthenticationProvider
{
Task<string> ListTenantsAsync();
}
}

Просмотреть файл

@ -0,0 +1,10 @@
namespace Microsoft.DotNet.MsIdentity.MicrosoftIdentityPlatformApplication
{
internal class TenantInformation
{
public string? TenantId { get; set; }
public string? DisplayName { get; set; }
public string? DefaultDomain { get; set; }
public string? TenantType { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,9 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.DotNet.MsIdentity.UnitTests.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("dotnet-msidentity, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

Просмотреть файл

@ -4,9 +4,10 @@ namespace Microsoft.DotNet.MsIdentity
{
public const string LIST_AAD_APPS_COMMAND = "--list-aad-apps";
public const string LIST_SERVICE_PRINCIPALS_COMMAND = "--list-service-principals";
public const string LIST_TENANTS_COMMAND = "--list-tenants";
public const string REGISTER_APPLICATIION_COMMAND = "--register-application";
public const string UPDATE_APPLICATION_COMMAND = "--update-application";
public const string UNREGISTER_COMMAND = "--unregister";
public const string VALIDATE_APP_PARAMS_COMMAND = "--validate-app-params";
}
}
}

Просмотреть файл

@ -6,61 +6,66 @@ using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.Graph;
using Microsoft.DotNet.MsIdentity;
using Microsoft.DotNet.MsIdentity.AuthenticationParameters;
using Microsoft.DotNet.MsIdentity.DeveloperCredentials;
using Microsoft.DotNet.MsIdentity.MicrosoftIdentityPlatformApplication;
namespace Microsoft.DotNet.MsIdentity
{
public class MsAADTool : IMsAADTool
internal class MsAADTool : IMsAADTool
{
private ProvisioningToolOptions ProvisioningToolOptions { get; set; }
private string _commandName { get; set; }
private GraphServiceClient _graphServiceClient;
private MsalTokenCredential _tokenCredential;
public IGraphServiceClient GraphServiceClient { get; set; }
public IAzureManagementAuthenticationProvider AzureManagementAPI { get; set;}
private MsalTokenCredential TokenCredential { get; set; }
public MsAADTool(string commandName, ProvisioningToolOptions provisioningToolOptions)
{
ProvisioningToolOptions = provisioningToolOptions;
_commandName = commandName;
_tokenCredential = new MsalTokenCredential(provisioningToolOptions.TenantId, provisioningToolOptions.Username);
_graphServiceClient = new GraphServiceClient(new TokenCredentialAuthenticationProvider(_tokenCredential));
TokenCredential = new MsalTokenCredential(ProvisioningToolOptions.TenantId, ProvisioningToolOptions.Username);
GraphServiceClient = new GraphServiceClient(new TokenCredentialAuthenticationProvider(TokenCredential));
AzureManagementAPI = new AzureManagementAuthenticationProvider(TokenCredential);
}
public async Task<ApplicationParameters?> Run()
{
if (_tokenCredential != null && _graphServiceClient != null)
string outputJsonString = string.Empty;
if (TokenCredential != null && GraphServiceClient != null)
{
var graphObjects = await _graphServiceClient.Me.OwnedObjects
.Request()
.GetAsync();
if (graphObjects.Any())
switch(_commandName)
{
switch(_commandName)
{
//--list-aad-apps
case Commands.LIST_AAD_APPS_COMMAND:
PrintApplicationsList(graphObjects.ToList(), ProvisioningToolOptions.Json ?? false);
break;
//--list-service-principals
case Commands.LIST_SERVICE_PRINCIPALS_COMMAND:
PrintServicePrincipalList(graphObjects.ToList(), ProvisioningToolOptions.Json ?? false);
break;
default:
break;
}
//--list-aad-apps
case Commands.LIST_AAD_APPS_COMMAND:
outputJsonString = await PrintApplicationsList();
break;
//--list-service-principals
case Commands.LIST_SERVICE_PRINCIPALS_COMMAND:
outputJsonString = await PrintServicePrincipalList();
break;
//list-tenants
case Commands.LIST_TENANTS_COMMAND:
outputJsonString = await PrintTenantsList();
break;
default:
break;
}
if (ProvisioningToolOptions.Json.HasValue && ProvisioningToolOptions.Json.Value)
{
Console.WriteLine(outputJsonString);
}
}
return null;
}
private void PrintApplicationsList(IList<DirectoryObject> graphObjects, bool outputJson)
internal async Task<string> PrintApplicationsList()
{
string outputJsonString = string.Empty;
var graphObjects = await GraphServiceClient.Me.OwnedObjects
.Request()
.GetAsync();
IList<Application> applicationList = new List<Application>();
if (graphObjects != null)
if (graphObjects != null && graphObjects.Any())
{
foreach (var graphObj in graphObjects)
{
@ -74,11 +79,9 @@ namespace Microsoft.DotNet.MsIdentity
if (applicationList.Any())
{
if (outputJson)
if (ProvisioningToolOptions.Json.HasValue && ProvisioningToolOptions.Json.Value)
{
string outputString = JsonSerializer.Serialize(applicationList);
Console.WriteLine(outputString);
}
outputJsonString = JsonSerializer.Serialize(applicationList); }
else
{
Console.Write(
@ -92,12 +95,17 @@ namespace Microsoft.DotNet.MsIdentity
}
}
}
return outputJsonString;
}
private void PrintServicePrincipalList(IList<DirectoryObject> graphObjects, bool outputJson)
internal async Task<string> PrintServicePrincipalList()
{
string outputJsonString = string.Empty;
IList<ServicePrincipal> servicePrincipalList = new List<ServicePrincipal>();
if (graphObjects != null)
var graphObjects = await GraphServiceClient.Me.OwnedObjects
.Request()
.GetAsync();
if (graphObjects != null && graphObjects.Any())
{
foreach (var graphObj in graphObjects)
{
@ -106,13 +114,11 @@ namespace Microsoft.DotNet.MsIdentity
servicePrincipalList.Add(servicePrincipal);
}
}
string outputString = string.Empty;
if (servicePrincipalList.Any())
{
if (outputJson)
if (ProvisioningToolOptions.Json.HasValue && ProvisioningToolOptions.Json.Value)
{
outputString = JsonSerializer.Serialize(servicePrincipalList);
outputJsonString = JsonSerializer.Serialize(servicePrincipalList);
}
else
{
@ -125,10 +131,66 @@ namespace Microsoft.DotNet.MsIdentity
Console.WriteLine($"{app.DisplayName.PadRight(35)}\t\t{app.AppId}");
}
}
//TODO do we need an else scenario where we list Service Principals for the command line experience.
}
Console.WriteLine(outputString);
}
return outputJsonString;
}
internal async Task<string> PrintTenantsList()
{
string outputJsonString = string.Empty;
IList<TenantInformation> tenantList = new List<TenantInformation>();
if (AzureManagementAPI != null)
{
var tenantsJsonString = await AzureManagementAPI.ListTenantsAsync();
if (!string.IsNullOrEmpty(tenantsJsonString))
{
using (JsonDocument document = JsonDocument.Parse(tenantsJsonString))
{
if (document.RootElement.TryGetProperty("value", out JsonElement jsonTenantElement))
{
var jsonTenantEnumerator = jsonTenantElement.EnumerateArray();
if (jsonTenantEnumerator.Any())
{
while (jsonTenantEnumerator.MoveNext())
{
JsonElement current = jsonTenantEnumerator.Current;
string? tenantId = current.GetProperty("tenantId").GetString();
string? tenantType = current.GetProperty("tenantType").GetString();
string? defaultDomain = current.GetProperty("defaultDomain").GetString();
string? displayName = current.GetProperty("displayName").GetString();
tenantList.Add(
new TenantInformation()
{
TenantId = tenantId,
TenantType = tenantType,
DefaultDomain = defaultDomain,
DisplayName = displayName
});
}
}
}
}
}
}
if (ProvisioningToolOptions.Json.HasValue && ProvisioningToolOptions.Json.Value)
{
outputJsonString = JsonSerializer.Serialize(tenantList);
}
else
{
Console.Write(
"--------------------------------------------------------------------------------------------------------------------------------\n" +
"Display Name\t\t\tDefault Domain\t\t\t\tTenant Type\tTenant Id\n" +
"--------------------------------------------------------------------------------------------------------------------------------\n\n");
foreach(var tenant in tenantList)
{
Console.WriteLine($"{(tenant.DisplayName ?? string.Empty).PadRight(16)}\t\t{(tenant.DefaultDomain ?? string.Empty).PadRight(20)}\t\t{(tenant.TenantType ?? string.Empty).PadRight(10)}\t{(tenant.TenantId ?? string.Empty)}");
}
}
return outputJsonString;
}
}
}

Просмотреть файл

@ -34,11 +34,14 @@ Usage:
dotnet-msidentity [command] [options]
Commands:
--list--aad-apps Lists AAD Applications for a given tenant/username.
--list-service-principals Lists AAD Service Principals.
--register-application Registers/unregisters/updates an AAD/AAD B2C Application in Azure.
- Updates the appsettings.json file.
Internal Commands (These commands have little do with registering AAD/AAD B2C apps but are nice helpers):
--list--aad-apps Lists AAD Applications for a given tenant + username.
--list-service-principals Lists AAD Service Principals for a given tenant + username.
--list-tenants Lists AAD + AAD B2C tenants for a given username.
Options:
--tenant-id <tenant-id> Azure AD or Azure AD B2C tenant in which to create/update the app.
- If specified, the tool will create the application in the specified tenant.

Просмотреть файл

@ -1,5 +1,5 @@
<Project>
<Import Project="..\..\Directory.Build.props" />
<Import Project="..\Directory.Build.props" />
<PropertyGroup>
<DeveloperBuildTestTfms>net5.0</DeveloperBuildTestTfms>

Просмотреть файл

@ -1,5 +1,5 @@
<Project>
<Import Project="..\..\Directory.Build.targets" />
<Import Project="..\Directory.Build.targets" />
<PropertyGroup>
<GeneratedTestProjectFile>$(IntermediateOutputPath)MSBuildProjectStrings.cs</GeneratedTestProjectFile>

Просмотреть файл

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(RepoRoot)src\MsIdentityScaffolding\Microsoft.DotNet.MsIdentity\Microsoft.DotNet.MsIdentity.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,59 @@
using System.Linq;
using System.Reflection;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.DotNet.MsIdentity.DeveloperCredentials;
using Microsoft.DotNet.MsIdentity.MicrosoftIdentityPlatformApplication;
using Moq;
using Xunit;
namespace Microsoft.DotNet.MsIdentity.UnitTests.Tests
{
public class MsAADToolTests
{
string tenantsJson =
"{\"value\":[" +
"{ \"id\":\"/tenants/AAAAAA-bbbbbb-CCCCCC-dddd-EEEEEEEE\",\"tenantId\":\"AAAAAA-bbbbbb-CCCCCC-dddd-EEEEEEEE\",\"countryCode\":\"US\",\"displayName\":\"NET AAD App\",\"domains\":[\"netaadapp.onmicrosoft.com\"],\"tenantCategory\":\"Home\",\"defaultDomain\":\"netaadapp.onmicrosoft.com\",\"tenantType\":\"AAD\"}," +
"{ \"id\":\"/tenants/EEEEEE-dddddd-CCCCCC-bbbb-AAAAAAAA\",\"tenantId\":\"EEEEEE-dddddd-CCCCCC-bbbb-AAAAAAAA\",\"countryCode\":\"US\",\"displayName\":\"NET AAD B2C App\",\"domains\":[\"netaadb2capp.onmicrosoft.com\"],\"tenantCategory\":\"Home\",\"defaultDomain\":\"netaadb2capp.onmicrosoft.com\",\"tenantType\":\"AAD B2C\"}]}";
public static ProvisioningToolOptions ToolOptions
{
get
{
return new ProvisioningToolOptions
{
TenantId = "abcdefg",
Username = "testUser",
Json = true
};
}
}
[Fact]
public async void TestPrintTenantsList()
{
string path = Assembly.GetExecutingAssembly().Location;
MsAADTool jsonTenantTool = new MsAADTool(Commands.LIST_TENANTS_COMMAND, ToolOptions);
Mock<IAzureManagementAuthenticationProvider> azureMngProviderMock = new Mock<IAzureManagementAuthenticationProvider>();
azureMngProviderMock.Setup(_ => _.ListTenantsAsync()).Returns(Task.FromResult(tenantsJson));
jsonTenantTool.AzureManagementAPI = azureMngProviderMock.Object;
string tenantsJsonFormatted = await jsonTenantTool.PrintTenantsList();
if (string.IsNullOrEmpty(tenantsJsonFormatted))
{
Assert.True(false, "Formatting tenants from Azure Management failed");
}
var tenantJsonList = JsonSerializer.Deserialize<TenantInformation[]>(tenantsJsonFormatted);
Assert.True(tenantJsonList.Any());
Assert.True(tenantJsonList.Length == 2);
var aadApp = tenantJsonList.Where(x => x.DisplayName.Equals("NET AAD App")).FirstOrDefault();
var aadB2CApp = tenantJsonList.Where(x => x.DisplayName.Equals("NET AAD B2C App")).FirstOrDefault();
Assert.True(aadApp != null && aadB2CApp != null);
Assert.True(aadApp.TenantType.Equals("AAD"));
Assert.True(!string.IsNullOrEmpty(aadApp.TenantId));
Assert.True(aadB2CApp.TenantType.Equals("AAD B2C"));
Assert.True(!string.IsNullOrEmpty(aadB2CApp.TenantId));
}
}
}

Просмотреть файл

@ -1,8 +1,3 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.DotNet.MsIdentity;
namespace Microsoft.DotNet.MsIdentity.Tool
{
internal static class MsAADToolFactory
@ -13,6 +8,7 @@ namespace Microsoft.DotNet.MsIdentity.Tool
{
case Commands.LIST_AAD_APPS_COMMAND:
case Commands.LIST_SERVICE_PRINCIPALS_COMMAND:
case Commands.LIST_TENANTS_COMMAND:
return new MsAADTool(commandName, provisioningToolOptions);
default:
return new AppProvisioningTool(provisioningToolOptions);

Просмотреть файл

@ -15,14 +15,26 @@ namespace Microsoft.DotNet.MsIdentity.Tool
var rootCommand = MsIdentityCommand();
var listAadAppsCommand = ListAADAppsCommand();
var listServicePrincipalsCommand = ListServicePrincipalsCommand();
var listTenantsCommand = ListTenantsCommand();
var provisionApplicationCommand = ProvisionApplicationCommand();
//hide internal commands.
listAadAppsCommand.IsHidden = true;
listServicePrincipalsCommand.IsHidden = true;
listTenantsCommand.IsHidden = true;
listAadAppsCommand.Handler = CommandHandler.Create<ProvisioningToolOptions>(HandleListApps);
listServicePrincipalsCommand.Handler = CommandHandler.Create<ProvisioningToolOptions>(HandleListServicePrincipals);
listTenantsCommand.Handler = CommandHandler.Create<ProvisioningToolOptions>(HandleListTenants);
provisionApplicationCommand.Handler = CommandHandler.Create<ProvisioningToolOptions>(HandleProvisionApplication);
//add all commands to root command.
rootCommand.AddCommand(listAadAppsCommand);
rootCommand.AddCommand(listServicePrincipalsCommand);
rootCommand.AddCommand(listTenantsCommand);
rootCommand.AddCommand(provisionApplicationCommand);
//if no args are present, show default help.
if (args == null || args.Length == 0)
{
args = new string[] { "-h" };
@ -46,6 +58,17 @@ namespace Microsoft.DotNet.MsIdentity.Tool
return -1;
}
private static async Task<int> HandleListTenants(ProvisioningToolOptions provisioningToolOptions)
{
if (provisioningToolOptions != null)
{
IMsAADTool msAADTool = MsAADToolFactory.CreateTool(Commands.LIST_TENANTS_COMMAND, provisioningToolOptions);
await msAADTool.Run();
return 0;
}
return -1;
}
private static async Task<int> HandleListServicePrincipals(ProvisioningToolOptions provisioningToolOptions)
{
if (provisioningToolOptions != null)
@ -90,6 +113,14 @@ namespace Microsoft.DotNet.MsIdentity.Tool
TenantOption(), UsernameOption(), JsonOption(), ProjectPathOption()
};
private static Command ListTenantsCommand()=>
new Command(
name: Commands.LIST_TENANTS_COMMAND,
description: "Lists AAD and AAD B2C tenants for a given user.")
{
UsernameOption(), JsonOption()
};
private static Command ProvisionApplicationCommand()=>
new Command(
name: Commands.REGISTER_APPLICATIION_COMMAND,
@ -176,10 +207,10 @@ namespace Microsoft.DotNet.MsIdentity.Tool
new Option<string>(
aliases: new[] {"-u", "--username"},
description:"Username to use to connect to the Azure AD or Azure AD B2C tenant." +
"\n\t- It's only needed when you are signed-in in Visual Studio, or Azure CLI with several identities." +
"\n\t- In that case, the username param is used to disambiguate which identity to use to create the app in the tenant.")
{
IsRequired = false
};
"\n- It's only needed when you are signed-in in Visual Studio, or Azure CLI with several identities." +
"\n- In that case, the username param is used to disambiguate which identity to use to create the app in the tenant.")
{
IsRequired = false
};
}
}