Thursday, April 28, 2016

ADFS : Daemon and Web API on Server 2016 TP4 ADFS 4.0

This follows on from my previous series of posts around taking the Azure AD OpenID Connect / OAuth2 samples and getting them to run on ADFS on TP4.

This uses the active-directory-dotnet-daemon sample that has a Windows console application calling a Web API using its application identity.

This is for Active Directory Federation Services on Server 2016 Technical Preview 4.

Just ignore all the Azure AD comments. There is no Azure in this solution.

In the solution, I've set the Web API to be at localhost:44326.

Just to re-iterate - the ADFS has to be Server 2016 - TP4 and above. This will not work on Server 2012 R2 - ADFS 3.0.

As before, the changes are all in a gist here.

This uses the client credential flow with ADAL i.e.

result = authContext.AcquireToken(todoListResourceId, clientCredential); 

where clientCredential is a combination of the clientID and the secret key. There is no authentication pop up where a user name and password needs to be entered.

The Azure AD sample relies on scope and NameID claims being returned in the JWT token. This is OK in Azure AD where the claims are static and Azure ID knows the ID of the application which is returned as a GUID in the NameID claim. ADFS AFAIK does not have claims rules for this so I hard coded the NameID. Hopefully, this will be resolved as more documentation is forthcoming. (But see ADFS : Server 2016 OAuth JWT is missing scope and NameID).

On to the ADFS configuration:

New Application Group - "Server Application and Web API".

For the Server Application:

You also need to generate a secret key. Copy this key before you leave the page because you can't get back to it. (You can, however, generate a new one).

The Client ID and the secret key need to be copied into the daemon app.config here:

 <add key="ida:ClientId" value="bee24b9a-13ac-45fc-988c-8cce06160c07" />
 <add key="ida:AppKey" value="wp...nE" />

For the Web API:

The custom claim rule for NameID is:

 => issue(Type = "", Value = "abcd");

Now run up the sample and the console application will show something like:

Posting to To Do list at 28/04/2016 9:03:27 p.m.
Successfully posted new To Do item:  Task at time: 28/04/2016 9:03:27 p.m.

Retrieving To Do list at 28/04/2016 9:03:33 p.m.
Task at time: 28/04/2016 9:02:10 p.m.
Task at time: 28/04/2016 9:03:27 p.m.
Task at time: 28/04/2016 9:02:36 p.m.
Total item count:  3

Posting to To Do list at 28/04/2016 9:03:46 p.m.


Thursday, April 21, 2016

Claims : Azman in the new claims-based world

Refer : Windows Authorisation Manager

"AzMan is available for use in the following versions of Windows: Windows Server 2012, Windows 8, Windows Server 2008 R2, Windows 7, Windows Server 2008, Windows Vista, Windows Server 2003, or Windows XP. It is deprecated as of Windows Server 2012 R2 and may be removed in subsequent versions."

"AzMan is a role-based access control (RBAC) framework that provides an administrative tool to manage authorisation policy and a run time that allows applications to perform access checks against that policy. The AzMan administration tool (AzMan.msc) is supplied as a Microsoft Management Console (MMC) snap-in.

Role-based authorisation policy specifies access in terms of user roles that reflect an application's authorisation requirements. Users are assigned to roles based on their job functions and these roles are granted permissions to perform related tasks.

Authorisation policy is managed separately from an application’s code. The application designer defines the set of low-level operations that are considered security sensitive and then defines a set of tasks that map onto those operations. The tasks, but not the operations, are designed to be understandable by administrators and business analysts."

Windows Server 2003 was way before the era of claims-based authentication and no doubt it had a place then.

Imagine a library. There could be two kinds of people; librarians and users. 

Users can browse the catalogue and check in / out books. Librarians can also do those functions plus they can order books. So the list of tasks could be:

Now the steps in ordering a book could be:

So the librarian would first check that there was enough budget, then check that the supplier has stock and then process the order.

There is a hierarchy of Role which has Tasks which has Operations. Each operation has a number.

Now you assign Tasks to Roles and then Operations to Tasks.

Lastly, you then assign users to Roles under "Role Assignments" above.

This is all wrapped up in an Application. As above, in the tree, "Library" is an instance of an application.

You then used .COM objects to get the assignments and you ended up with an array of ints; each element was a binary for the operation of that number e.g. if "Check budget" was numbered one, then the first instance in the array would tell you if the user had permission to perform that operation.

Never having used Azman, I may have some details wrong but they are close enough to illustrate the point.

This is all well and good but how to you migrate this to a modern claims-based world using e.g. ADFS.

ADFS authenticates against Active Directory (AD) and AD does not directly support the above structure.

AD does not have a concept of "application" and I'm ignoring that for the moment as my particular requirement was to migrate an Azman based program that only had one application.

AD does allow a hierarchy of roles (called Groups in AD) e.g. A can be memberOf B can be memberOf C.

The problem is that the groups do not display in a hierarchical manner e.g.

The way this is setup in AD is that:

"Librarian" is a memberOf "Order book" is a memberOf "Check budget".

The user is then a memberOf  "Librarian".

In terms of setting up the claims-based application, there are two ways to go:
  • WIF (the older way but still supported)
  • OWIN WS-Fed (the newer way)
For WIF, refer:

How To: Build Claims-Aware ASP.NET MVC Web Application Using WIF

where the STS = ADFS.

For OWIN, there is a Azure AD sample:

Integrating a web app with Azure AD using WS-Federation

and then convert to ADFS by using:

Use the OWIN Security Components in ASP.NET to Implement Web Sign On with ADFS.

On the ADFS side, be sure to add an LDAP rule that maps "Token-Groups - Unqualified Names" to "Role".

Using this and by adding the code in the gist to display the claims, my user that has the Librarian Role displays as:

The code can now use the IsInRole construct.

Refer Working with claims-based identities in multi-tenant applications for other ways to look at the claims.

Hopefully, this provides enough of the plumbing to get you across the line during your Azman migration.


Wednesday, April 20, 2016

Misc : Switching over to https

Now that Blogger supports https, I've enabled https support for this blog.

I can't see any obvious errors.

If you find something, please leave a comment.



Friday, April 15, 2016

ADFS : Adding "Change Password" to the default login page

I used Server 2016 TP4 for this but you can use any version of ADFS from 2012 R2 upwards.

I gave an overview here but this is the actual code sample.

This is based on #AzureAD Mailbag: Self-Service Password Reset.

The PowerShell commands are:

New-ADFSWebTheme -Name ADFSChangePassword -SourceName default

Name                    : ADFSChangePassword
IsBuiltinTheme          : False
StyleSheet              : {[, System.Byte[]]}
RTLStyleSheet           : {42, 32, 123, 13...}
OnLoadScript            :
Logo                    : {}
Illustration            : {[, System.Byte[]]}
AdditionalFileResources : {[/adfs/portal/script/onload.js, System.Byte[]], [/adfs/portal/images/idp/localsts.png, System.Byte[]], [/adfs/portal/images/i
                          [/adfs/portal/images/idp/otherorganizations.png, System.Byte[]]}

Export-ADFSWebTheme -Name ADFSChangePassword -DirectoryPath C:\Work

Onload.js will now be in c:\work\script\onload.js

Modify onload.js at this point as below.

Set-AdfsWebTheme -TargetName ADFSChangePassword -AdditionalFileResource @{Uri=’/adfs/portal/script/onload.js';path=”c:\work\script\onload.js”}

Set-AdfsWebConfig -ActiveThemeName ADFSChangePassword

Modify onload.js by adding the following at the end: 

// Add "Change Password" link

var formsAuthArea = document.getElementById("formsAuthenticationArea");

if (formsAuthArea) {

    // Create the hyperlink

    var pwdResetLink = document.createElement('a');

    var linkText = document.createTextNode("Change your password");


    pwdResetLink.title = "Change your password";

    pwdResetLink.href = "https://my-adfs/adfs/portal/updatepassword/";


    // Append to the authArea

    var authArea = document.getElementById("authArea");

Then run the last two PowerShell commands.

The login screen will now look like:

Clicking the link leads to:


ADAL : Use of token cache in Azure multi-tenancy

Very good Patterns and Practices series of posts here on developing an Azure multi-tenant application.

Part of this is the issue around caching the tokens.

The article has this to say:

"It's relatively expensive to get an OAuth access token, because it requires an HTTP request to the token endpoint. Therefore, it's good to cache tokens whenever possible. The Azure AD Authentication Library (ADAL) automatically caches tokens obtained from Azure AD, including refresh tokens.

ADAL provides a default token cache implementation. However, this token cache is intended for native client apps, and is not suitable for web apps:
  • It is a static instance, and not thread safe.
  • It doesn't scale to large numbers of users, because tokens from all users go into the same dictionary.
  • It can't be shared across web servers in a farm.
Instead, you should implement a custom token cache that derives from the ADAL TokenCache class but is suitable for a server environment and provides the desirable level of isolation between tokens for different users."

Just something to keep in mind!


Thursday, April 14, 2016

ADFS : Change the user password

As per ADFS 2012 R2 now supports Password Change (not reset) across all devices, users have had the ability to change their password since 2012 R2.

This is as simple as enabling the endpoint and then restarting the service.

Note that this does not encompass resetting the password.

Note also that you only get these values when the password is due to expire within the next 14 days. (The 14 day value is not currently configurable).

As per the above link:

"All you need to do is to add the following claims rule to the issuance claims when sending tokens to Azure AD/Office 365.

c1:[Type == ““]
=> issue(store = “_PasswordExpiryStore”, types = (““, ““, ““), query = “{0};”, param = c1.Value);

With the above rule we are sending 3 additional claims
  • Password Expiration Time: This is the time when the user’s password will expire
  • Password Expiration Days: This is the number of days remaining prior to the password expiry
  • Password Change URL: This is the URL of the password change URL from ADFS"
That's all well and good with WS-Fed & SAML but what happens with OpenID Connect / OAuth where you don't have the ability to add claims rules?

With Server 2016 TP4, OpenID Connect functionality is enabled but you still can't add claims rules to web applications. You can only add them to web API.

So what happens in TP4 when "Change Password" is enabled and we use OpenID Connect from a web application.

We get two new entries:

Previously, the order was upn / name / c_hash.

Now we have upn / name / pwd_url / pwd_exp / c_hash.

The pwd_url is the URL of the "Change Password" page.

The pwd_exp value is the number of seconds until the password expires (approx. 4 days).

If you want to add this link permanently to the ADFS login page, refer:

I love the SSPR functionality but my users authenticate with AD FS.

Note that this is for the Azure AD SSPR link but there is nothing stopping you changing the wording from "Can't access your account?" to "Change your password" and setting the URL to the ADFS  "Change Password" URL as above.

Code sample for this here.


Wednesday, April 13, 2016

ADFS : Local CP LDAP PowerShell Cmdlets

This is for Active Directory Federation Services on Server 2016 Technical Preview 4.

The previous post was around authenticating using AD LDS with ADFS. You have to use PowerShell. There is currently no support in the wizard.

The available cmdlets are:

get-help Add-AdfsLocalClaimsProviderTrust


    Add-AdfsLocalClaimsProviderTrust -Name -Identifier -LdapServerConnection -UserObjectClass -UserContainer -AnchorClaimLdapAttribute -AnchorClaimType
    [-AcceptanceTransformRules ] [-AcceptanceTransformRulesFile ] [-Enabled ] [-Notes ] [-OrganizationalAccountSuffix ] [-Force] [-Type ] [-PassThru] [-WhatIf] [-Confirm]
    [-LdapAuthenticationMethod {Basic | Kerberos | Negotiate}] [-LdapAttributeToClaimMapping ]  []

get-help  Disable-AdfsLocalClaimsProviderTrust


    Disable-AdfsLocalClaimsProviderTrust -TargetClaimsProviderTrust [-PassThru] [-WhatIf] [-Confirm]  []

    Disable-AdfsLocalClaimsProviderTrust -TargetIdentifier [-PassThru] [-WhatIf] [-Confirm]  []

    Disable-AdfsLocalClaimsProviderTrust -TargetName [-PassThru] [-WhatIf] [-Confirm]  []

get-help  Enable-AdfsLocalClaimsProviderTrust


    Enable-AdfsLocalClaimsProviderTrust -TargetClaimsProviderTrust [-PassThru] [-WhatIf] [-Confirm]  []

    Enable-AdfsLocalClaimsProviderTrust -TargetIdentifier [-PassThru] [-WhatIf] [-Confirm]  []

    Enable-AdfsLocalClaimsProviderTrust -TargetName [-PassThru] [-WhatIf] [-Confirm]  []

get-help Get-AdfsLocalClaimsProviderTrust


    Get-AdfsLocalClaimsProviderTrust [[-Name] ]  []

    Get-AdfsLocalClaimsProviderTrust [-Identifier]   []

get-help Remove-AdfsLocalClaimsProviderTrust


    Remove-AdfsLocalClaimsProviderTrust -TargetClaimsProviderTrust [-PassThru] [-WhatIf] [-Confirm]  []

    Remove-AdfsLocalClaimsProviderTrust -TargetIdentifier [-PassThru] [-WhatIf] [-Confirm]  []

    Remove-AdfsLocalClaimsProviderTrust -TargetName [-PassThru] [-WhatIf] [-Confirm]  []

get-help Set-AdfsLocalClaimsProviderTrust


    Set-AdfsLocalClaimsProviderTrust -TargetClaimsProviderTrust [-AcceptanceTransformRules ] [-AcceptanceTransformRulesFile ] [-Name ] [-Notes ] [-OrganizationalAccountSuffix
    ] [-Force] [-PassThru] [-WhatIf] [-Confirm]  []

    Set-AdfsLocalClaimsProviderTrust -TargetIdentifier [-AcceptanceTransformRules ] [-AcceptanceTransformRulesFile ] [-Name ] [-Notes ] [-OrganizationalAccountSuffix ] [-Force]
    [-PassThru] [-WhatIf] [-Confirm]  []

    Set-AdfsLocalClaimsProviderTrust -TargetName [-AcceptanceTransformRules ] [-AcceptanceTransformRulesFile ] [-Name ] [-Notes ] [-OrganizationalAccountSuffix ] [-Force] [-PassThru]
    [-WhatIf] [-Confirm]  []


ADFS : Authenticating with LDAP

This is for Active Directory Federation Services on Server 2016 Technical Preview 4.

Just to re-iterate - the ADFS has to be Server 2016 - TP4 and above. This will not work on Server 2012 R2 - ADFS 3.0.

I used the following for reference:
To sum up the main points:

"AD FS supports any LDAP v3-compliant directory.

In order for AD FS to authenticate users from an LDAP directory, you must connect this LDAP directory to your AD FS farm by creating a local claims provider trust.

You can support multiple LDAP directories, each with its own configuration, within the same AD FS farm by adding multiple local claims provider trusts. In addition, AD DS forests that are not trusted by the forest that AD FS lives in can also be modelled as local claims provider trusts. You can create local claims provider trusts by using Windows PowerShell.

LDAP directories (local claims provider trusts) can co-exist with AD directories (claims provider trusts) on the same AD FS server, within the same AD FS farm, therefore, a single instance of AD FS is capable of authenticating and authorising access for users that are stored in both AD and non-AD directories.

Only forms-based authentication is supported for authenticating users from LDAP directories.

Certificate-based and Integrated Windows authentication are not supported for authenticating users in LDAP directories.

All passive authorisation protocols that are supported by AD FS, including SAML, WS-Federation, and OAuth are also supported for identities that are stored in LDAP directories.

The WS-Trust active authorisation protocol is also supported for identities that are stored in LDAP directories."


"In ADFS v1.0 and ADFS v1.1 it was possible to use both AD and AD LDS / ADAM as an identity store. One of the very common scenarios is to use the AD identity store for internal users and use the AD LDS / ADAM identity store for external users (e.g. partners, customers, vendors, etc.). 

All the ADFS versions starting with ADFS v2.0 and higher only supported AD as the identity store and nothing else. That could be one of the reasons why some companies remained using ADFS v1.x.

If you would like to support a similar scenario, where you would like to have a separate identity store for externals, you would need to either:
  • Configure a separate AD with its own ADFS infrastructure and configure federation between them
  • Use Azure AD to store those identities and configure federation"
With Server 2016 and ADFS vNext or 4.0 or whatever it is going to be called, the last paragraph is no longer true.

AD LDS is an instance of an LDAP and hence can be supported by ADFS 4.0. This means you can finally retire that instance of ADFS 1.x. Cue massive applause :-)

The previous post detailed how to run up an instance of AD LDS on Server 2016.

This all has to be done with PowerShell. The instance names are as per that previous post.

 $DirectoryCred = Get-Credential

This pops up FBA. I used my domain admin. account.

$vendorDirectory = New-AdfsLdapServerConnection –HostName –Port 50000 –SslMode None –AuthenticationMethod Basic –Credential $DirectoryCred

$GivenName = New-AdfsLdapAttributeToClaimMapping –LdapAttribute givenName –ClaimType “”

$CommonName = New-AdfsLdapAttributeToClaimMapping –LdapAttribute cn –ClaimType “”

$Surname = New-AdfsLdapAttributeToClaimMapping –LdapAttribute sn –ClaimType “”

Add-AdfsLocalClaimsProviderTrust –Name "AD LDS" –Identifier "TP4-1" –Type Ldap -LdapServerConnection $vendorDirectory –UserObjectClass user –UserContainer "CN=ADFS,DC=dev,DC=local" –LdapAuthenticationMethod Basic  –AnchorClaimLda
pAttribute mail –AnchorClaimType "" –LdapAttributeToClaimMapping @($GivenName, $Surname, $CommonName) -AcceptanceTransformRules "@RuleName = `"Issue All Mapped Claims`"`nc:[] => is
sue(claim = c);" –Enabled $true

This will give a warning:

"WARNING: PS0245: Because no organizational account suffixes were specified, this claims provider trust will not be accessible by requests that use the active profile."

If you want this, you need:

Set-AdfsClaimsProviderTrust -TargetName "AD LDS" -OrganizationalAccountSuffix @("dev.local")

Note that the HRD screens will then be slightly different. You can see examples of this in the second article above.

When I setup the local CP trust, I got an error around invalid credentials. I eventually noticed that I had omitted to define $Surname. Once I fixed that, the error went away. That error is very misleading!

Also note that the new CP will not be displayed in the ADFS wizard.

You can, however, see it with:

UserObjectClass             : user
UserContainer               : CN=ADFS,DC=dev,DC=local
AnchorClaimLdapAttribute    : mail
LdapAuthenticationMethod    : Basic
LdapServerConnection        : {}
LdapAttributeToClaimMapping : {Microsoft.IdentityServer.Management.Resources.LdapAttributeToClaimMapping, Microsoft.IdentityServer.Management.Resources.LdapAttributeToClaimMapping,
LocalClaimsProviderType     : Ldap
AnchorClaimType             :
IdentifierType              :
Identities                  : {}
AcceptanceTransformRules    : @RuleName = "Issue All Mapped Claims"
                               => issue(claim = c);

OrganizationalAccountSuffix : {}
Enabled                     : True
IsLocal                     : True
Identifier                  : TP4-1
Name                        : AD LDS
Notes                       :
ProtocolProfile             : WsFed-SAML
To test this I used the OpenID Connect sample referred to in one of my previous posts. Yes, you read that correctly. Not only are we going to authenticate on AD LDS with ADFS, we are going to use the OpenID Connect protocol. Neat!

(This makes sense when you remember that AD LDS is just the Identity repository. The actual protocol layer is handled by ADFS).

When we run up the sample, we see the expected HRD.

 Authenticating with "adamuser1@dev.local" we get the expected JWT claims:

Goodbye ADFS 1.x!


Tuesday, April 12, 2016

Windows Server : Installing AD LDS

This is for Active Directory Lightweight Directory Service on Server 2016 Technical Preview 4.

Note that it is not specific to Server 2016. That's the one I used because this is in preparation for my next post.

AD LDS (aka ADAM) is a Lightweight Directory Service (a poor man's AD!) which is not domain bound and is used mainly for application attributes i.e. you can keep all the application specific stuff. Each application lives in a container. You can have many instances on one server and the schemas of each can be different.

As you may have guessed, TP4 allows ADFS to authenticate against a V3 LDAP of which AD LDS happens to be but one example.

So from Server Manager, Manage / Add Roles.

 Once complete, select the LDS wizard. (Also note ADSI Edit which we will use later).

Select "Unique Instance" Next.

Select a Name. I used "TP4-1". Next.

The default ports should show as 50000 and 50001 for the first instance. You can change them if you wish. Next.

Create a partition and give it a name. I used "CN=ADFS,DC=dev,DC=local". (dev.local is my domain). Next. Next.

I used the Network Service Account. Next.

I used the currently logged on user. Next.

Select the MS-User.LDF LDIF. Next.

Next out.

Now if you look in Services you will see:

Now we use ADSI Edit.

Action / Connect.

Now we need to add a user as below.

Right click on Roles, New Object. Choose "user"


Pick a user name e.g. adamuser1 and then Next out.

Right click on the user and choose "Reset Password". Enter the password twice.

Now double click on the user. (Or right click - Properties). I had:

cn = adamuser1
displayName = Adam User1
givenName = Adam
mail = adamuser1@dev.local
msDS-UserAccountDisabled = FALSE
name =  adamuser1
sn = User1
userPrincipalName = adamuser1@dev.local

and we are done!

From the cmd prompt, you can check:

dsdbutil: list instances

Instance Name:         NTDS
LDAP Port:             389
SSL Port:              636
Install folder:        C:\Windows\NTDS
Database file:         C:\Windows\NTDS\ntds.dit
Log folder:            C:\Windows\NTDS
NTDS Mode    :         Active Directory Domain Controller Mode

Instance Name:         TP4-1
Long Name:             TP4-1
LDAP Port:             50000
SSL Port:              50001
Install folder:        C:\Windows\
Database file:         C:\Program Files\Microsoft ADAM\TP4-1\data\adamntds.dit
Log folder:            C:\Program Files\Microsoft ADAM\TP4-1\data
Service state:         Running


Monday, April 11, 2016

stackoverflow : Finally, the 20,000 rep barrier!

When I started at SO roughly 8 years ago, the highest rep. that gave you extra privileges was 20,000.

so that was always my goal.

However, in writing this, I discovered that they have added a new privilege at 25,000.

It's taken me a while:

but I finally got there.

One of the reasons it's taken so long is that I only answer questions in a very small "obscure" category i.e. around Identity mainly ADFS, SAML and WIF.

I got a big boost from getting a 500 rep. bounty which for a brief instant of time put me into Jon Skeet territory.

i.e. the top 0.01% !!!

(Normally I sit at about 2%).

In  terms of where I sit among the approx 5 million regular SO users (who have rep.):

My badge collection is coming along nicely.

And every now and then I get an extra bonus:

The top non-Microsoft article around MSAL.

OK - that's because it's brand new and there are basically zero articles but hey - I'll take it :-)

So on to 25,000 - only 4,979 to go!


Wednesday, April 06, 2016

AAD : MSAL : Microsoft Authentication Library

This was announced at \\Build in Vittorio's presentation:

Microsoft Identity: State of the Union and Future Direction

and is further described here:

Microsoft Identity at //build/ 2016

"MSAL is a unified library that helps you to develop applications that work with Microsoft Accounts, Azure AD accounts and Azure AD B2C users indifferently – all in a single, streamlined programming model!"

So it targets the "converged model".

It's a "successor" to ADAL with the important proviso that it will not work with ADFS and the original Azure AD.

"ADAL is and remains the main means you have to work with the original Azure AD and with ADFS, which aren’t supported by MSAL. If you need a token for a service that today accepts only tokens from the original Azure AD, such as the Azure ARM API, you’ll want to keep using ADAL."

The NuGet package is here. Note that it is a prerelease.

The other change is that there is a new application portal at:

The article has links to some sample code but I found the web app. one confusing.

I think Integrate Microsoft identity and the Microsoft Graph into a web application using OpenID Connect is a better sample (or another view: Integrate Microsoft identity and the Microsoft Graph into a web application using OpenID Connect).

Running the sample, we see:

So we can choose either the Microsoft account (MSA) (aka LiveID) or the work / school account (aka organisational account).

If we use the work / school account and display the claim, we see:

If we use the MSA account, we see:

so there are some minor differences.

Also of interest is the fact that although WS-Fed was used in the flow we are getting an OAuth JWT not a WS-Fed SAML token.

After we have logged in as both, the login screen looks like:

So both are "signed in" but you can only pick one at any one time.

When I sign in to the work or school account, we see:

&state=OpenIdConnect.AuthenticationProperties%3dxK...Zi HTTP/1.1

which is OAuth (but note the V2 endpoint oauth2/v2.0/authorize)

This is followed by:

& HTTP/1.1

which is WS-Fed

Not sure why both are invoked?

Early days - no doubt more documentation will be forthcoming.