Azure Active Directory : Group integration for daemon / server applications (aka Service Principals)

Introduction

Today’s blog post will be how you can leverage the authentication scenario of a Daemon, Service User or Server Application when our application/API is using Azure Active Directory for its authentication flows.

“An example of a daemon application is a batch job, or an operating system service running in the background. This type of application requests an access token by using its application identity and presenting its Application ID, credential (password or certificate), and application ID URI to Azure AD. After successful authentication, the daemon receives an access token from Azure AD, which is then used to call the web API.”

In essence, a “daemon application” will do a “clients credentials grant” whilst using an Azure Active Directory Service Principal. The “application id” of the service principal will serve as the “client_id” and a generated “secret” will service as the “client_secret”.

In addition to this, we want our application to grant permissions (authorization & identification) based on the group memberships of Azure Active Directory. Where this is pretty straightforward for our basic user objects. This requires a bit of attention when wanting to achieve the same for our service principal.

 

Why service principals?

The first question you might ask is… why do I want to use a service principal? The most straightforward answer is that the service principals will not adhere to the same policies you have set for your user. What policies should you be thinking of here? MFA enforcement, password change policies, … and so on. In addition, service principals support multiple secrets (“passwords”), which powers you to do rolling updates. You could even leverage the “Managed Service Identity” to ease up the pain for some deployments.

(Also a bit shoutout to Kristof Rennen for the sparring during this journey…) πŸ˜‰

 

What will we be doing today?

For today I’ll be showing you how you can link both a regular AAD user and an AAD Service Principal to an AAD group. Afterwards, we’ll see how we can get the group claim into the JWT access token we received from our authentication flow.

 

Creating the AAD Group

Let’s start with the most easy part… πŸ˜‰ We’ll be creating our test group for today’s little excersise.

Who doesn’t like super heroes and villains. So let’s add a group for our “little web app” that will identify the “Super Villain Role” in our application.

We won’t be adding users just yet. So let’s just press create, and enjoy the results of our hard work!

 

Adding an AAD user to our AAD group

Meet “My Little Testuser”… This is an extra-ordinary user, as (s)he has ambitions to become a Super Villain!

So let’s add her/him to our newly created group!

Now let’s put this to the test… shall we? We’ll log into the Azure Portal ;

Next up, I’m going to do something funky… Open your favorite web developer tooling. In this case, I’m using Firefox, so I’ll navigate to “Web Developer” and then “Network” ;

This will open the Network inspector view, and I’ll look for an API call where a POST happened. Cool we found one! Now investigate the request headers of this post, and you’ll notice an “Authorization”-header where the content will start with “Bearer ey…”.

This is a JWT token the user got during it’s authentication flow and which it’s using for the authentication towards the Azure services. As I can imagine you aren’t able to read this encrypted token. So a good thing to know is that we have a website where you can decrypt those messages for your pleasure! πŸ˜‰ You can reach this site at : https://jwt.ms/

Let’s enter our token in there… and see how it looks decrypted!

Here you’ll see that there is a “groups”-claim, which has an array of objectids in there. Now let’s take a look at our AAD group again ;

As you would have expected, this object id matches the one of our “villains”-group.

 

Create our service principal (aka Server Application / Daemon Application / Service User / Super Villain of the Future)

Browse to “Application Registrations” in your AAD directory, and press the “New application registration”-button ;

 

Let’s create our little service user…

And now we have a our future villain all ready to go!

Copy the application id… as we’ll need this as our “client_id” later on.

Also browse to “Properties” and copy the “App ID URI”. This isn’t going to make sense now, but we’ll be needing this one later on to set our resource server.

Next up, generate a key (“password”) and copy the value. We’ll be using this later on as our “client_secret”.

 

Gathering an Access Token for our Service Principal

For this, we’ll be using “postman“. This is by far my favorite API testing tool. Though you can use whichever you favor! πŸ˜‰ Now let’s use the set of information we gathered earlier on and construct our request as shown here…

We’ll be given an access token in the format as we saw with our AAD user too. So let’s decrypt this…

The trained eye will notice that the “appid” is matching our service principal’s application id. We could also change the resource server and point to https://graph.microsoft.com/ (instead of our own APIs URI) ;

Then we would see that the access token we got is a bit different. The audience (aud claim) is refering to the graph API. And that one is able to “translate” the appid to the “app_displayname”.

That being said as a bit of trivia and show the difference of the “resource server”-scope.

 

Linking the Service Principal to the Group

If we try to add our service principal as a member to our group, we’ll get the following…

Despite that it’s annoying that we can’t do this via the portal. You can do it via powershell! So let’s do that. First we’ll log into Azure and connect to AAD.

Let’s find the information of our Service Principal and our AAD group.

Let’s see who’s already member of our new Super Villain Role ;

“My Little Testuser” is pretty lonely there… So let’s add our service principal. This can be done vai the “Add-AzureAdGroupMember”-cmdlet. The objectid is refering to the objectid of the group, where the “refobjectid” is the one refering to the object that will need to be added as a member. Once done, let’s check the members again.

And yes, our ServicePrincipal got added to our group! Let’s get another access token.

And decrypt that one…

Hmm, no group info yet…

 

Exposing the group info for our Service Principal

Azure Active Directory has a philosophy that it doesn’t want to expose more than it should… So we’re going to adjust the manifest of our service principal and enable the groups claim.

“Your choices for setting the groupMembershipClaims property are null (the default), All or SecurityGroup. If you choose SecurityGroup you will get group claims in the JWT token for just security groups the user is a member of. If you choose All you will get group claims in the JWT token for security groups and distribution lists the user is a member of.”

Now let’s do this for our little test user… Browse to the “Registered App” and click on “Manifest”.

Locate the “groupMembershipClaims” and you’ll notice that this one is “null”.

Let’s change the value to “All” and press “Save”.

Again, we’ll ask for a new access token ;

And decrypt it…

Hooray! Now we get the groups claim added to our access token. πŸ˜‰

 

Closing Thoughts

Some observations / findings for this post…

  • It is possible to add a Service Principal to an AAD group via Powershell.
  • Service Users, Daemon / Server Applications … and so on should be using a Service Principal.
  • Adding the groups claim to a Service Principal is done by adjusting the groupsMembershipClaims

I quickly referenced the graph API as another “resource server”-scope. Though be aware that you can grant your “API” rights towards the graph API in order to read and/or write user/groups/… objects. When you are working on scale, then this is the API you want to be talking to in order to setup/sync your identification/authorization flows.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.