PlatformNotSupported Exception when calling AddUse

2019-04-11 09:09发布

问题:

I am trying to write some code that creates a user in Azure AD using the Graph API. I started w/ an example off the net, but right now it fails when adding the user, on the line

await adClient.Users.AddUserAsync(userGraphObj);

In the CreateUser() method below. The error I get is

I am using .NET Core 2.0, debugging on Windows 7. Googling around and I found that they brought serialization back for 2.0, but only for specific types.

I don't really care. How can I add a user to Azure AD in code?


const String appClientID = "2be733f1-88c3-6482-8e2a-5e9631fc3a32";
const String tenant = "brazzers.onmicrosoft.com";
const String authString = "https://login.microsoftonline.com/" + tenant;
const String authClientSecret = "dDdaVGee315s65ewDSWEwfdw7wq5efDNO5C3cvN4RA";
const String resAzureGraphAPI = "https://graph.windows.net";
const String serviceRootURL = resAzureGraphAPI + appClientID;

private ActiveDirectoryClient GetAADClient()
{
    Uri serviceRoot = new Uri(serviceRootURL);
    ActiveDirectoryClient adClient = new ActiveDirectoryClient(
        serviceRoot, async () => await GetAppTokenAsync());
    return adClient;
}

private static async Task<String> GetAppTokenAsync()
{
    AuthenticationContext authenticationContext = new AuthenticationContext(authString, false);
    ClientCredential clientCred = new ClientCredential(appClientID, authClientSecret);
    AuthenticationResult authResult = await authenticationContext.AcquireTokenAsync(resAzureGraphAPI, clientCred);
    return authResult.AccessToken;
}

public async Task<IActionResult> CreateUser()
    {
        var adClient = GetAADClient();

        //Construct The User
        String userEmail = "TestUser@Brazzers.com";
        String mailNickname = userEmail.Split(new char[] { '@' }).FirstOrDefault();

        var userGraphObj = new Microsoft.Azure.ActiveDirectory.GraphClient.User()
        {
            GivenName = "Test",
            Surname = "User",
            Mobile = "13133124044",
            MailNickname = mailNickname,
            DisplayName = "Test User",
            AccountEnabled = true
        };

        await adClient.Users.AddUserAsync(userGraphObj);

        return Ok(tempPassword);

    }

回答1:

Microsoft itself recommends not to use the Azure AD Graph API anymore, in favor of the Microsoft Graph API (cf blog post).

If you don't have a strong requirement to use the Azure AD API, here are the steps to create a user via the latest API.

Disclaimer :

  • I never managed to successfully acquire a token from a desktop application
  • I haven't really understood how the permissions scopes are supposed to be used (here it seems to want a URL, but in the examples it's usually a list of strings, such as User.ReadWrite.All or Directory.ReadWrite.All)

Code to acquire a token:

const String appClientID = "2be733f1-88c3-6482-8e2a-5e9631fc3a32";
const String tenant = "brazzers.onmicrosoft.com";
const String authString = "https://login.microsoftonline.com/" + tenant;
const String authClientSecret = "dDdaVGee315s65ewDSWEwfdw7wq5efDNO5C3cvN4RA";

public static GraphServiceClient GetAuthenticatedClient()
{
    var delegateAuthenticationProvider = new DelegateAuthenticationProvider(
        async (requestMessage) =>
        {
            var accessToken = await GetAppTokenAsync();
            requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", accessToken);
        }
    );

    return new GraphServiceClient(delegateAuthenticationProvider);
}

private static async Task<String> GetAppTokenAsync()
{
    // this doesn't work for desktop apps, 
    // and PublicClientApplication throws a NotImplementedException
    var cca = new ConfidentialClientApplication(
        appClientID,
        authString, 
        "http://www.example.com/", // no redirect
        new ClientCredential(authClientSecret),
        new TokenCache(),
        new TokenCache());

    var authResult = await cca.AcquireTokenForClientAsync(new[] { $"https://graph.microsoft.com/.default" });
    return authResult.AccessToken;
}

Code to create a user (courtesy of the samples):

public async Task<User> CreateUser(GraphServiceClient graphClient)
{
    // This snippet gets the tenant domain from the Organization object to construct the user's email address.
    var organization = await graphClient.Organization.Request().GetAsync();
    var domain = organization.CurrentPage[0].VerifiedDomains.ElementAt(0).Name;

    // Add the user.
    var userEmail = "TestUser@" + domain;
    var mailNickname = userEmail.Split(new char[] { '@' }).FirstOrDefault();

    return await graphClient.Users.Request().AddAsync(new User
    {
        AccountEnabled = true,
        DisplayName = "Test User",
        MailNickname = mailNickname,
        PasswordProfile = new PasswordProfile
        {
            Password = "super_strong_password"
        },
        UserPrincipalName = userEmail
    });
}