Coder Social home page Coder Social logo

waynemunro / active-directory-dotnetcore-daemon-v2 Goto Github PK

View Code? Open in Web Editor NEW

This project forked from azure-samples/active-directory-dotnetcore-daemon-v2

1.0 2.0 0.0 381 KB

A .NET Core 2.x simple daemon console application calling the graph with its own identity

License: MIT License

PowerShell 63.55% C# 36.45%

active-directory-dotnetcore-daemon-v2's Introduction

topic languages products
sample
csharp
azurepowershell
azure-active-directory
dotnet-core

A .NET Core 2.2 simple daemon console application calling Microsoft Graph with its own identity

Build status

About this sample

Overview

This sample application shows how to use the Azure AD v2.0 endpoint to access the data of Microsoft business customers in a long-running, non-interactive process. It uses the OAuth 2 client credentials grant to acquire an access token, which can be used to call the Microsoft Graph and access organizational data

The app is a .NET Core 2.1 Console application. It gets the list of users in an Azure AD tenant by using Microsoft Authentication Library (MSAL) Preview for .NET to acquire a token.

Scenario

The console application:

  • gets a token from Azure AD in its own name (without a user)
  • and then calls the Microsoft Graph /users endpoint to get the list of user, which it then displays (as Json blob)

Topology

For more information on the concepts used in this sample, be sure to read the v2.0 endpoint client credentials protocol documentation.

Daemon applications can use two forms of secrets to authenticate themselves with Azure AD:

  • application secrets (also named application password). This is what we've seen so far.
  • certificates. This is the object of this paragraph. The first form (application secret) is treated in the next paragraphs. A variation of this sample using a certificate instead of an application password is available at the end of this article in Variation: daemon application using client credentials with certificates

How to run this sample

To run this sample, you'll need:

  • Visual Studio 2017 or just the .NET Core SDK
  • An Internet connection
  • A Windows machine (necessary if you want to run the app on Windows)
  • An OS X machine (necessary if you want to run the app on Mac)
  • A Linux machine (necessary if you want to run the app on Linux)
  • An Azure Active Directory (Azure AD) tenant. For more information on how to get an Azure AD tenant, see How to get an Azure AD tenant
  • A user account in your Azure AD tenant. This sample will not work with a Microsoft account (formerly Windows Live account). Therefore, if you signed in to the Azure portal with a Microsoft account and have never created a user account in your directory before, you need to do that now.

Step 1: Clone or download this repository

From your shell or command line:

git clone https://github.com/Azure-Samples/active-directory-dotnetcore-daemon-v2.git

or download and exact the repository .zip file.

Given that the name of the sample is pretty long, and so are the name of the referenced NuGet packages, you might want to clone it in a folder close to the root of your hard drive, to avoid file size limitations on Windows.

Step 2: Register the sample with your Azure Active Directory tenant

There is one project in this sample. To register it, you can:

If you want to use this automation:

  1. On Windows run PowerShell and navigate to the root of the cloned directory

  2. In PowerShell run:

    Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process -Force
  3. Run the script to create your Azure AD application and configure the code of the sample application accordinly.

    .\AppCreationScripts\Configure.ps1

    Other ways of running the scripts are described in App Creation Scripts

  4. Open the Visual Studio solution and click start

If ou don't want to use this automation, follow the steps below

Choose the Azure AD tenant where you want to create your applications

As a first step you'll need to:

  1. Sign in to the Azure portal using either a work or school account or a personal Microsoft account.
  2. If your account is present in more than one Azure AD tenant, select Directory + Subscription at the top right corner in the menu on top of the page, and switch your portal session to the desired Azure AD tenant.
  3. In the left-hand navigation pane, select the Azure Active Directory service, and then select App registrations (Preview).

Register the client app (daemon-console)

  1. Navigate to the Microsoft identity platform for developers App registrations page.

  2. Select New registration.

    • In the Name section, enter a meaningful application name that will be displayed to users of the app, for example daemon-console.
    • In the Supported account types section, select Accounts in this organizational directory only ({tenant name}).
    • Select Register to create the application.
  3. On the app Overview page, find the Application (client) ID value and record it for later. You'll need it to configure the Visual Studio configuration file for this project.

  4. From the Certificates & secrets page, in the Client secrets section, choose New client secret:

    • Type a key description (of instance app secret),
    • Select a key duration of either In 1 year, In 2 years, or Never Expires.
    • When you press the Add button, the key value will be displayed, copy, and save the value in a safe location.
    • You'll need this key later to configure the project in Visual Studio. This key value will not be displayed again, nor retrievable by any other means, so record it as soon as it is visible from the Azure portal.
  5. In the list of pages for the app, select API permissions

    • Click the Add a permission button and then,
    • Ensure that the Microsoft APIs tab is selected
    • In the Commonly used Microsoft APIs section, click on Microsoft Graph
    • In the Application permissions section, ensure that the right permissions are checked: User.Read.All
    • Select the Add permissions button
  6. At this stage permissions are assigned correctly but the client app does not allow interaction. Therefore no consent can be presented via a UI and accepted to use the service app. Click the Grant/revoke admin consent for {tenant} button, and then select Yes when you are asked if you want to grant consent for the requested permissions for all account in the tenant. You need to be an Azure AD tenant admin to do this.

Step 3: Configure the sample to use your Azure AD tenant

In the steps below, "ClientID" is the same as "Application ID" or "AppId".

Open the solution in Visual Studio to configure the projects

Configure the client project

Note: if you used the setup scripts, the changes below will have been applied for you

  1. Open the daemon-console\appsettings.json file
  2. Find the app key Tenant and replace the existing value with your Azure AD tenant name.
  3. Find the app key ClientId and replace the existing value with the application ID (clientId) of the daemon-console application copied from the Azure portal.
  4. Find the app key ClientSecret and replace the existing value with the key you saved during the creation of the daemon-console app, in the Azure portal.

Step 4: Run the sample

Clean the solution, rebuild the solution, and run it. You might want to go into the solution properties and set both projects as startup projects, with the service project starting first.

Start the application, it will display the users in the tenant.

About the code

The relevant code for this sample is in the Program.cs file, in the RunAsync() method. The steps are:

  1. Create the MSAL confidential client application.

    Important note: even if we are building a console application, it is a daemon, and therefore a confidential client application, as it does not access Web APIs on behalf of a user, but on its own application behalf.

    IConfidentialClientApplication app;
    app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
                                              .WithClientSecret(config.ClientSecret)
                                              .WithAuthority(new Uri(config.Authority))
                                              .Build();
  2. Define the scopes.

    Specific to client credentials, you don't specify, in the code, the individual scopes you want to access. You have statically declared them during the application registration step. Therefore the only possible scope is "resource/.default" (here "https://graph.microsoft.com/.default") which means "the static permissions defined in the application"

    // With client credentials flows the scopes is ALWAYS of the shape "resource/.default", as the 
    // application permissions need to be set statically (in the portal or by PowerShell), and then granted by
    // a tenant administrator
    string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
  3. Acquire the token

    AuthenticationResult result = null;
    try
    {
        result = await app.AcquireTokenForClient(scopes)
                          .ExecuteAsync();
    }
    catch(MsalServiceException ex)
    {
        // AADSTS70011
        // Invalid scope. The scope has to be of the form "https://resourceurl/.default"
        // Mitigation: this is a dev issue. Change the scope to be as expected
    }
  4. Call the API

    In that case calling "https://graph.microsoft.com/v1.0/users" with the access token as a bearer token.

Troubleshooting

Did you forget to provide admin consent? This is needed for daemon apps

If you get an error when calling the API Insufficient privileges to complete the operation., this is because the tenant administrator has not granted permissions to the application. See step 6 of Register the client app (daemon-console) above.

You will typically see, on the output window, something like the following:

Failed to call the Web Api: Forbidden
Content: {
  "error": {
    "code": "Authorization_RequestDenied",
    "message": "Insufficient privileges to complete the operation.",
    "innerError": {
      "request-id": "<a guid>",
      "date": "<date>"
    }
  }
}

Variation: daemon application using client credentials with certificates

Daemon applications can use two forms of secrets to authenticate themselves with Azure AD:

  • application secrets (also named application password). This is what we've seen so far.
  • certificates. This is the object of this paragraph.

Topology

To use certificates instead of an application secret you will need to do little changes to what you have done so far:

  • (optionnally) generate a certificate and export it, if you don't have one already
  • register the certificate with your application in the application registration portal
  • enable the sample code to use certificates instead of app secret.

(Optional) use the automation script

If you want to use the automation script:

  1. On Windows run PowerShell and navigate to the root of the cloned directory

  2. In PowerShell run:

    Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process -Force
  3. Run the script to create your Azure AD application and configure the code of the sample application accordinly.

    .\AppCreationScripts-WtihCert\Configure.ps1

    Other ways of running the scripts are described in App Creation Scripts

  4. Open the Visual Studio solution

  5. Right click on the daemon-console project in VisualStudio and choose Properties. Then, in the Build tab, add a Conditional compilation symbol set to VariationWithCertificateCredentials. This is to enable conditional compilation for your project to use the certificate rather than the app secret.

  6. Save and select start

If ou don't want to use this automation, follow the following steps:

(Optional) Create a self-signed certificate

To complete this step, you will use the New-SelfSignedCertificate Powershell command. You can find more information about the New-SelfSignedCertificat command here.

  1. Open PowerShell and run New-SelfSignedCertificate with the following parameters to create a self-signed certificate in the user certificate store on your computer:

    $cert=New-SelfSignedCertificate -Subject "CN=DaemonConsoleCert" -CertStoreLocation "Cert:\CurrentUser\My"  -KeyExportPolicy Exportable -KeySpec Signature
  2. Export this certificate using the "Manage User Certificate" MMC snap-in accessible from the Windows Control Panel. You can also add other options to generate the certificate in a different store such as the Computer or service store (See How to: View Certificates with the MMC Snap-in).

Alternatively you can use an existing certificate if you have one (just be sure to record its name for the next steps)

Add the certificate for the daemon-console application in Azure AD

In the application registration blade for your application, in the Certificates & secrets page, in the Certificates section:

  1. Click on Upload certificate and, in click the browse button on the right to select the certificate you just exported (or your existing certificate)
  2. Click Add

Configure the Visual Studio project

To change the visual studio project to enable certificates you need to:

  1. Open the daemon-console\appsettings.json file
  2. Find the app key CertificateName and replace the existing value with the name of your certificate (if you generated your own certificate from the instructions above, this should be CN=DaemonConsoleCert).
  3. Right click on the daemon-console project in VisualStudio and choose Properties. Then, in the Build tab, add a Conditional compilation symbol set to VariationWithCertificateCredentials. This is to enable conditional compilation for your project to use the certificate rather than the app secret.

Build and run

Build and run your project. You have the same output, but this time, your application is authenticated with Azure AD with the certificate instead of the application secret.

About the alternate code

The code change is the following: the ClientCredentials instance passed to the constructor of the ConfidentialClientApplication is now built from a ClientAssertionCertificate instance (built from the certificate) instead of from the application password

X509Certificate2 certificate = ReadCertificate(config.CertificateName);
app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
                .WithCertificate(certificate)
                .WithAuthority(new Uri(config.Authority))
                .Build();

The rest of the application is the same. The sample also has a method to retrive the certificate from the Windows certificate store (This part was not tested on linux)

Community Help and Support

Use Stack Overflow to get support from the community. Ask your questions on Stack Overflow first and browse existing issues to see if someone has asked your question before. Make sure that your questions or comments are tagged with [msal dotnet].

If you find a bug in the sample, please raise the issue on GitHub Issues.

If you find a bug in msal.Net, please raise the issue on MSAL.NET GitHub Issues.

To provide a recommendation, visit the following User Voice page.

Contributing

If you'd like to contribute to this sample, see CONTRIBUTING.MD.

This project has adopted the Microsoft Open Source Code of Conduct. For more information, see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.

More information

For more information, see MSAL.NET's conceptual documentation:

For more information about the underlying protocol:

For a more complex multi-tenant Web app daemon application, see active-directory-dotnet-daemon-v2

active-directory-dotnetcore-daemon-v2's People

Contributors

andretms avatar henrik-me avatar jennyf19 avatar jmprieur avatar matt40k avatar microsoftopensource avatar msftgits avatar

Stargazers

 avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.