Wednesday, November 15, 2017

ADFS : ADFS 4.0 with SPA

This is for Server 2016 with a single page application.

There is a sample that shows how to do this but you will see many comments along the lines of "I can authenticate but when I call the API I get "Authorization has been denied for this request" ".

This error is typically invoked when either the "audience" or the "issuer" is wrong.

Once you have authenticated, look at the token you received under the "User" tab e.g.

Id_token content

Ensure these are the values configured for "Audience" and "Issuer" in the "appSettings".

They are case-sensitive!

The sample is a badly hacked Azure AD one and still has references to this all over the place.

It is also confusing because it refers to constructs like "tenant" which mean nothing in the ADFS world.

Also the clientID is a string (as in Azure AD) rather than a GIUD that is automatically generated for you when you create the application.

It needs to be rewritten to make it ADFS centric!

The other problem is that it uses implicit flow and there are contradictory articles that mention that you cannot get extra or custom claims with this flow because it would make the query string too long?


Monday, November 06, 2017

ADFS : Application Groups

ADFS 4.0 manages OpenID Connect / OAuth connections via the "Application Groups" folder.

There are three kinds:
  • Native application
  • Server application
  • Web API
which leads to the following combinations:
  • Native application accessing web API
  • Server application accessing Web API
Plus the odd one out:
  • Web browser accessing web application
The PowerShell cmdlets split into three separate commands:
  • Get-AdfsNativeClientApplication
  • Get-AdfsServerApplication
  • Get-AdfsWebApiApplication
So although you can create an application with a web API in one pass through the wizard, the separate components need to be accessed via PowerShell.



Name                       : MyApp  - Native application
Identifier                 : b2...27
ApplicationGroupIdentifier : MyApp
Description                :
Enabled                    : True
RedirectUri                : {https://blah}


ADUserPrincipalName                  :
ClientSecret                         : ********
JWTSigningCertificateRevocationCheck : None
JWTSigningKeys                       : {}
JWKSUri                              :
Name                                 : My server application
Identifier                           : 8e...44
ApplicationGroupIdentifier           : MyApp
Description                          :
Enabled                              : True
RedirectUri                          : {https://blah}


Name                                 : My Web API
Identifier                           : {https://blah/webapi}
AccessControlPolicyName              : Permit everyone
AccessControlPolicyParameters        :
AdditionalAuthenticationRules        :
AllowedAuthenticationClassReferences : {}
AllowedClientTypes                   : Public, Confidential
ApplicationGroupIdentifier           : MyApp
ApplicationGroupId                   : 12...56
AlwaysRequireAuthentication          : False
ClaimsProviderName                   : {}
DelegationAuthorizationRules         :
Enabled                              : True
ImpersonationAuthorizationRules      :
IssuanceAuthorizationRules           :
IssueOAuthRefreshTokensTo            : AllDevices
IssuanceTransformRules               : @RuleName = "All"
                                        => issue(claim = c);
NotBeforeSkew                        : 0
Description                          :
PublishedThroughProxy                : False
RefreshTokenProtectionEnabled        : False
RequestMFAFromClaimsProviders        : False
ResultantPolicy                      : RequireFreshAuthentication:False
                                         Permit everyone
TokenLifetime                        : 0

Plus we have the legacy cmdlets from ADFS 3.0:


RedirectUri                          : {ms-appx-web://Microsoft.AAD.BrokerPlugin}
Name                                 : Windows Logon Client
Description                          : Client for Microsoft Windows Logon
ClientId                             : 38...93b
BuiltIn                              : True
Enabled                              : True
ClientType                           : Public
ADUserPrincipalName                  :
ClientSecret                         :
JWTSigningCertificateRevocationCheck : None
JWTSigningKeys                       : {}
JWKSUri                              :

Just remember that the clientID is auto-generated when you create one of these entries and the secret key can only be viewed once in the wizard during creation.

Plus there was this question over on the forum around scope:

In an ADFS Application Group, add Client Application/Permitted Scope to Web API with PowerShell

Grant-AdfsApplicationPermission -ClientRoleIdentifier $clientAppIdGuid -ServerRoleIdentifier $relyingPartyIdentifier -ScopeNames $theScopesYouWantAssignedTo

And remember you can get all the commands by:

get-command *adfsclient*

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Cmdlet          Add-AdfsClient                               ADFS
Cmdlet          Disable-AdfsClient                           ADFS
Cmdlet          Enable-AdfsClient                            ADFS
Cmdlet          Get-AdfsClient                               ADFS
Cmdlet          Remove-AdfsClient                            ADFS
Cmdlet          Set-AdfsClient                               ADFS

get-command *adfsnativeclient*

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Cmdlet          Add-AdfsNativeClientApplication              ADFS
Cmdlet          Get-AdfsNativeClientApplication              ADFS
Cmdlet          Remove-AdfsNativeClientApplication           ADFS
Cmdlet          Set-AdfsNativeClientApplication              ADFS

get-command *adfsserver*

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Cmdlet          Add-AdfsServerApplication                    ADFS
Cmdlet          Get-AdfsServerApplication                    ADFS
Cmdlet          Remove-AdfsServerApplication                 ADFS
Cmdlet          Set-AdfsServerApplication                    ADFS

get-command *adfswebapi*

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Cmdlet          Add-AdfsWebApiApplication                    ADFS
Cmdlet          Get-AdfsWebApiApplication                    ADFS
Cmdlet          Remove-AdfsWebApiApplication                 ADFS
Cmdlet          Set-AdfsWebApiApplication                    ADFS

get-command *adfsapplication*

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Cmdlet          Disable-AdfsApplicationGroup                 ADFS
Cmdlet          Enable-AdfsApplicationGroup                  ADFS
Cmdlet          Get-AdfsApplicationGroup                     ADFS
Cmdlet          Get-AdfsApplicationPermission                ADFS
Cmdlet          Grant-AdfsApplicationPermission              ADFS
Cmdlet          New-AdfsApplicationGroup                     ADFS
Cmdlet          Remove-AdfsApplicationGroup                  ADFS
Cmdlet          Revoke-AdfsApplicationPermission             ADFS
Cmdlet          Set-AdfsApplicationGroup                     ADFS
Cmdlet          Set-AdfsApplicationPermission                ADFS


Monday, October 30, 2017

Visual Studio : Unable to connect to web server IIS Express

This is with VS 2017.

I was looking at a .NET Core project and wanted to change from http to https.

So under Properties / Debug, I checked the "Enable SSL" checkbox.

This changes the port so I then did a copy / replace of the old port to the new one and changed the URL to https e.g.

http://localhost:5000 became https://localhost:44326

Then I got "Unable to connect to web server IIS Express".

Consulted with Mr. Google.

The solution that worked for me was to:
  • Close the VS project
  • In File Explorer, navigate to the project and delete the entire ".vs" folder
  • Restart the project
  • Run as "Debug"
  • Works
Apparently, it has something to do with the "applicationhost.config" file.


Friday, October 27, 2017

Azure : Weird problem with OAuth timing

Came across a head-scratcher recently.

Using OpenID Connect / OAuth against Azure AD, authentication would always fail and then work if you retried two minutes later. Before that, retries would consistently fail.

WTF? What is the significance of two minutes?

Mr. Google to the rescue and came across a similar problem in SAML-P.

The problem here was that the two servers clocks were not synchronised. The token has start / end parameters for the validity of the token and any time outside of these is considered invalid and hence the token is rejected. (You can fix this via the skew parameter),

The OAuth JWT token has similar fields viz.

iat - Issued at
nbf - Not before

Checking the respective server's times, this would indeed the problem :-)

And you guessed it - the server's times were two minutes apart!


Wednesday, October 18, 2017

IdentityServer : WS-Fed metadata imported into ADFS

I've been looking at Identity server 4 (idsrv4) just to have a play with it.

This runs on .NET Core which I something else I need to get up to speed on.

There is also a WS-Fed plug-in which I got working and tried to hook up to ADFS as an exercise.

The metadata endpoint is:


and when I tried to import this into ADFS, I got the normal:

"Metadata contains some features not supported by ADFS" warning.

Now this could be because the metadata contains a SAML profile that ADFS doesn't support - PAOS being an example.

But 999 out of 1000 times, it's because the endpoints are "http" not "https".

Looking at the metadata, this is indeed the case.

This means that although the entry is added to ADFS, it has no endpoints so it will never work.

You can't just edit the metadata because it's signed and you'll get a signing error when you try and import the updated file.

You can delete the whole "Signature" section in the XML if you want. Do this at your own risk - normal best practice security applies :-).

The other way is to update the metadata when it's generated. There is no metadata file - it's dynamically generated every time.

You can do this in the "Properties".

Select the "Enable SSL" check box. IIS Express generates a new endpoint as above so now you have to replace all the instances of:


with the https endpoint as above.

This also means that you need to change this address in any of the client samples.

The new metadata imports without issues.


Wednesday, October 11, 2017

ADFS : PowerShell cmdlet - parameter PolicyMetadata

Another question on the forum around the format of PowerShell parameters.

This one was around PolicyMetadata.

Get-AdfsAccessControlPolicy -Name "Demo"

Name           : Demo
Identifier     : Demo
IsBuiltIn      : False
RpUsageCount   : 0
LastUpdateTime : 10/10/2017 7:22:00 PM
Description    :
PolicyMetadata : RequireFreshAuthentication:False
                   Permit everyone
AssignedTo     : {} 

Now if you copy / paste the metadata into a file and then run:

New-AdfsAccessControlPolicy -Name "DemoOne" -PolicyMetadataFile c:\Filename

you get all kinds of errors.

Looking at the errors e.g. "Root error" made me think that the format wasn't JSON, rather XML.

Which means that it is almost impossible to guess the element names etc.

So Mr. Google to the rescue and a long time later, I came across:

(Get-AdfsAccessControlPolicy -Name "Permit everyone").PolicyMetadata | fl *

which displays:

IsParameterized : False
Serialized      : <PolicyMetadata xmlns:i=""
                          <Condition i:type="AlwaysCondition">
                            <Values />
Summary         : RequireFreshAuthentication:False
                    Permit everyone
ExtensionData   : System.Runtime.Serialization.ExtensionDataObject

Putting that into a file e.g.

<?xml version="1.0" encoding="UTF-8"?>
<PolicyMetadata xmlns:i=""
                    <Condition i:type="AlwaysCondition">
                        <Values />

and then running the command works!

I suggest running:


which displays them all and then look at the XML formats to get some hints as to the XML format.


Saturday, October 07, 2017

ADFS : PowerShell cmdlet - parameter is an array

Over on the forum, there was a question around a parameter in the cmdlet that accepts multiple options as an array i.e.

"-RedirectUriSpecifies an array of redirection URIs for the OAuth 2.0 client to register with AD FS".

The question was around the format of the array since that is not specified.

Looking at another example:

Set-AdfsRelyingPartyTrust -TargetName claimapp -ClaimsProviderName @("Fabrikam","Active Directory")

the array is of the form:

@("Fabrikam","Active Directory")


Thursday, October 05, 2017

OAuth2 : Displaying JWT tokens

The standard way that I've been looking at and debugging with JWT tokens is via:

Now, Microsoft have come to the party with:

It starts off with

Then you copy / paste the ID token and it will display the details.

You can see the standard attributes:

or the same thing as claims rules (if this is a more familiar format for you).

And it gives you a bit of extra context.


Friday, September 29, 2017

Auth0 : The connection was disabled

I was trying to set up an enterprise connection in Auth0 to my ADFS instance.

When I tried the "Test" button on the enterprise connection, I got:

"description": "the connection was disabled"


Eventually I realised that this is because I do not have a client that is configured under "Connections" to use that enterprise connection.

Assigned this to a client and viola! all is well.

That error message needs improvement!


Monday, September 25, 2017

ADFS : Pre-populating the user on the login screen

This question often comes up and I came across a site that does this.

Note this is with ADFS 4.0 (Server 2016).

The URL is:


The ADFS login screen then looks like:


Wednesday, September 13, 2017

ADFS : RP default token lifetime

This question keeps coming up.

The default value for TokenLifetime on a RP trust is 0. But what value is 0?

As usual, a heap of garbage via Google.

60 minutes, 300 minutes, 600 minutes, 10 hours ...

Using ADFS 4.0 and looking at a SAML RP, we get:

Conditions        NotBefore="2017-09-12T19:24:01.817Z"

So the correct answer is 1 hour = 60 minutes.

Note: Don't confuse this with the ADFS wide WebSSOLifetime. This is a server wide timeout parameter.

The default value for that = 8 hours = 480 minutes.


Friday, September 01, 2017

Azure B2C : Adding Azure Active Directory (AAD) via custom policies

As I write these are in preview.

The documentation is here.

The AAD guide is here.

And the obligatory warning:

"Custom policies are designed primarily for identity pros who need to address complex scenarios. For most scenarios, we recommend that you use Azure Active Directory B2C built-in policies. Built-in policies are easier to set up for your configuration. You can use built-in and custom policies in the same Azure Active Directory B2C tenant. To learn more, see the overview of custom policies."

and again:

"Custom policy editing is not for everyone. The learning curve is demanding, the startup time is longer, and future changes to custom policies will require similar expertise to maintain. Built-in policies should be carefully considered first for your scenario before using custom policies."

I don't necessarily agree with this and am somewhat puzzled as to why they push this so hard.

The aim should be to encourage people to have a crack at it and learn something rather than scare them away.

I would spend some time reading through the getting started guide and get an overview of how the XML files work, how to upload them etc.

The big drawback about all of these guides is that they publish snippets of XML and it's always hard to figure out the context i.e. where they go in the document and how they relate to the other sections.

So I decided to publish all five files as gists (suitably redacted!).

I have three add-ons:
  • Facebook - from the default policy 
  • ADFS - added but doesn't work because of the self-signed certificate
  • AAD - which works
Note that this was for a PoC where I was just looking at authentication. I haven't looked at the claims passed etc.

Also I did not have an actual application. I just tested using the "Run Now" button.

My B2C page looks like:

Also note that I added Application Insights which I strongly recommend for debugging (in SignUpOrSigninWithAAD.xml).


Azure B2C : Using B2C as an Identity router

B2C has been touted as the successor to ACS but I've always struggled to understand this.

With the advent of custom policies, this is now doable.

Essentially, forget about using B2C as it's supposed to be used i.e. external customer registration and self service password reset.

Just use it as a hub / identity router.

You can configure a policy e.g. sign up / sign in to handle any number of IDP as long as they support OpenID Connect or SAML 2.0. Each of these is configured via XML in the custom policies. Each has a login button on the landing page.

You could almost think of B2C as acting as a pseudo Home Realm Discovery page.

B2C can be branded so it could have the same look and feel as the rest of the corporate pages.

e.g. this is my PoC page.

It allows you to sign up with Facebook, ADFS or Azure AD.

Downstream B2C only allows OpenID Connect so the path would be e.g.

Application --> OIDC --> B2C --> OIDC  --> Facebook
                                                  --> SAML --> ADFS
                                                  --> OIDC  --> AAD

Or if you wanted lots of social providers, you could go OIDC to something like Auth0 and then use their large array of social providers.

So it's pretty much ACS++!

WS-Fed support is on the way.


Thursday, August 31, 2017

Azure B2C : Tracking errors

I've posted before on how crucial Application Insights is to troubleshooting B2C custom policies.

Once you had got it setup, you need to wait about 5 minutes and then run something like:


This displays all the data. You can sort by clicking on the "timestamp column".

 Expand the "message" section.

Expand the "FatalException" section.

and you'll see the error.

If you want to filter the errors, try something like:

| where severityLevel > 0 and message contains "Exception"


Wednesday, August 30, 2017

Azure B2C : Custom policies with ADFS

Azure AD B2C has custom policies in preview that enable you to add extra IDP / social to B2C via an "Identity Framework" that is a collection of XML files that document standards, orchestrations, user journeys etc.

Using this you can add providers that use either SAML or OpenID Connect.

So ADFS 4.0 was a good candidate for OIDC.

As per my SO question:

"I have ADFS 4.0 on an Azure VM and am trying to add ADFS as a provider to my Azure AD B2C tenant.

I have set up all the custom policies.

I am using OpenID Connect as the protocol.

My ADFS SSL certificate is self-signed and I have certificate rollover for the encryption and signing certificates.

The error I get in Application Insights is: 

Exception {"Kind":"Handled","HResult":"80131501",
"Message":"The remote certificate is invalid according to the validation procedure.","Data":{}} Kind Handled HResult 80131501 
Message The remote certificate is invalid according to the validation procedure.

I battled for hours trying to get this to work before asking the question.

Turns out:

"Your ADFS needs to have a valid SSL cert signed by the standard Certificate Authorities in order for Azure AD B2C to communicate with it".

So no self-signed. As this was a proof on concept, I'm not intending to go out and buy a certificate. This is further complicated by the fact that you can't buy a certificate for!

Tip - to debug the custom policies you need Application Insights. Without that, your chances of solving the issues are effectively zero.


Tuesday, August 29, 2017

ADFS : Issue with updating the SSL certificate

Using ADFS 4.0 and updating the SSL certificate.

This is on an Azure VM and I was accessing it remotely.

Ran the normal commands:

Set-AdfsCertificate -CertificateType Service-Communications -Thumbprint thumbprint

Set-AdfsSslCertificate -Thumbprint thumbprint

Error :

Set-AdfsSslCertificate -Thumbprint 24f...b35

Set-AdfsSslCertificate : PS0319: Validation task 'Test-_InternalAdfsSslCertificate' on AD FS server 'localhost' failed with error 'Connecting to remote server localhost failed with the following error message : The client cannot connect to the destination specified in the request. Verify that the service on the destination is running and is accepting requests. Consult the logs and documentation for the WS-Management service running on the destination, most commonly IIS or WinRM. If the destination is the WinRM service, run the following command on the destination to analyze and configure the WinRM service: "winrm quickconfig".

As per the message, running:

winrm qc

and then re-running the command fixed the problem.


Monday, August 21, 2017


SLO = Single log out.

The way this is supposed to work is described in the SAML specification.

For one customer, they had 6 RP and one of then didn't do SLO properly and didn't return a logout response.

This stopped all the others getting called, clearing cookies etc. so it was a "half a logout" solution.

Eventually, I simply removed the SLO endpoint for the RP via the ADFS wizard.

Everything then worked correctly.

The RP with issues was still logged in and if you knew the URL you could still continue but at least the bigger picture worked.

I should point out that this RP was the only one that did not use an industry standard SAML stack and had instead tried to roll their own. You may draw your own conclusions :-)


Friday, August 04, 2017

Identity : Breached passwords

Troy Hunt has an interesting feature over on Introducing 306 million freely downloadable pwned passwords.

All the passwords that have been in a breach are searchable.

If there is a hit, it's either out there or someone else make the same password selection as you did (decreasing security).

But there's also a section on how to utilise this for Identity Management.

When you ask the user to select a password, check it against this list and reject if there is a hit.

Azure AD uses a similar approach where they reject all "common" passwords.


Friday, July 28, 2017

ASP.NET : Misused header name. Make sure request headers are used

The full error is:

Misused header name. Make sure request headers are used with HttpRequestMessage, response headers with HttpResponseMessage, and content headers with HttpContent objects.

This is when I use HttpClient with .NET 4.5 and try something like:

client.DefaultRequestHeaders.Add("Contact-Type", ...);

And so began a long and painful journey to figure out to to fix this because the external web API wouldn't work without "Content-Type" as a header.

There is so much garbage out there :-(

After some research, Content-Type is part of Content - the name pretty much implies that - so use HttpContent.

using (var client = new HttpClient())
  // Adding contentType to client as header gives "Misused header name. Make   sure request headers are used 
with HttpRequestMessage, response headers with HttpResponseMessage, and content headers with HttpContent 
  // objects."

  client.DefaultRequestHeaders.Add("Authorization", "Bearer abc...123");

  HttpResponseMessage response;
  // Construct an HttpContent from the data
  HttpContent hc = new StringContent(data);
  hc.Headers.ContentType = new MediaTypeHeaderValue("application/json");
  response = client.PostAsync(baseAddress, hc).Result;

  var result = response.Content.ReadAsStringAsync().Result;


Wednesday, July 19, 2017

Git : Publish causes problems

Git in VS 2015 is driving me insane!

When I publish the applications, I get a whole lot of build files etc. in the Git changes folder.

This is despite these files being in the .gitignore.

Undoing the changes does nothing. The changes still sit in the folder.

Then I figured out that:

git reset --hard

gets rid of everything.

Always check with:

git status 

before and after and always ensure you are on the correct branch.


Tuesday, July 18, 2017

Git : Using Beyond Compare with the Bash shell

This post shows how to set up Git Bash.

There is a diff in Git but it's the Unix style showing one side and then the other in text and it's hard to understand. I like visual indicators in a GUI which is where BC comes in.

So first we need to tell Bash where BC is:

$ PATH=$PATH:/c/'Program Files/Beyond Compare 4'

Test this by typing:


and you should get the BC GUI coming up.

Tell Git to use BC for diff.

$ git config --global diff.tool bc

Now compare a file on two branches.

$ git difftool branch1  branch1 -- somepath/Index.cshtml

Viewing (1/1): 'somepath/Index.cshtml'
Launch 'bc' [Y/n]? y

BC will now launch showing the text wizard differences for Index.cshtml between the two branches.

So much cleaner and more readable.

The Bash prompt will stay open until you close BC.


Monday, July 17, 2017

VS : Cannot pull because there are uncommitted changes

Using VS 2015.

The full error is:

"Cannot pull because there are uncommitted changes. Commit or undo your changes before pulling again. See the Output window for details."

So annoying. This happens a lot when trying to pull.

Install Git Bash.

In Windows Explorer, navigate to the directory where your project is and right click.

$ git status
On branch somebranch


Check you are on the right branch. You will get messages about the difference with master.


 $ git pull

Back to VS. Now you get a message about files being updated outside of VS.

Just "Reload all".

Job done!


Thursday, July 13, 2017

ADFS : A SQL operation in the ADFS configuration database failed

The full error is:

A SQL operation in the AD FS configuration database with connection string Data Source=np:\\.\pipe\microsoft##wid\tsql\query;Initial Catalog=AdfsConfigurationV3;Integrated Security=True failed.

Event ID: 352.

This was on Server 2016 with WID after I had done a Windows update.

The normal Google collection of mostly useless information when I searched.

The ADFS service was stopped. Restarting it just gave errors.

Then I came across a post where the user had restarted the "Windows Internal Database" service first.

I tried that - took a while - and then got an error message.

But when I looked at the status of the service it was running.

Restarting the ADFS service then worked - Hallelujah!

And the next thing I did was backup the database with the AD FS Rapid Restore Tool :-)


ADFS : Pop-ups on the HRD / login and change password screens

This was inspired by a post over on the forum.

This is for Server 2012 R2 and 2016.

Full customisation wrap here.

The code you add to onload.js would be something like:

if ( document.getElementById("hrdArea") ) {
        window.alert("Some message");

This would only pop-up on the HRD screen.

This is a JavaScript Alert.

A Confirm would let the user enter "OK" or "Cancel". (What would the point be?).

A Prompt would let the user enter a value but you wouldn't be able to use it other than maybe further customising the screen.

Note: Use at own risk.


Tuesday, July 11, 2017

ADFS : Adding default password rules to the Change and Update Password pages

Continuing the series on customising the ADFS HRD, login and password pages.

This is for Server 2012 R2 and 2016.

There's a full wrap here.

I see continual problems when users have to pick a new password because they are not sure of the actual validation rules detailed in the AD group password policy.

So it would be useful to give them some guidelines.

The change to onload.js is:

if ( document.getElementById("updatePasswordArea") ) {
    if ( document.getElementById("introduction") ) {
        document.getElementById("introduction").innerHTML = "<br/><b>Default Password Rules</b><br/><br/><ul><li>At least 12 characters</li><li>At least one capital & one lower case letter and at least one number (0-9) and / or symbol (e.g. !, $, #, %, @)</li></ul><br/><br/>"

This gives:


Monday, July 10, 2017

ADFS : Removing the copyright notice - the easy way

This is for Server 2012 R2 / 2016.

I've done a series of articles on customising the login, HRD and change password screens here.

The official article for removing the copyright notice is here.

This involves updating the .css file etc.

Following the procedure in my posts, there is an easier way.

Just update the onload.js.

if ( document.getElementById("copyright") ) {
    document.getElementById("copyright").innerHTML = "";


Thursday, June 29, 2017

AD : LDAP connections work remotely but not locally

I have a web API on a server which talks to a DC (via LDAP) on an Azure VM and I have been connecting to it remotely no problem.

Remotely, I connect to The DC shows as in ADUC.

Then I deployed a copy of the web API locally on the VM and the web API started throwing LDAP errors and telling me that there was an invalid user name / password when trying the LDAP connection. The  aforementioned user name / password work perfectly remotely.


So using "LDP" locally, we see:

and then we bind:

This gives:

0 = ldap_set_option(ld, LDAP_OPT_ENCRYPT, 1)
res = ldap_bind_s(ld, NULL, &NtAuthIdentity, NEGOTIATE (1158)); // v.3
    {NtAuthIdentity: User='xxxldap'; Pwd=unavailable; domain = 'dev.local'}
Error 49: ldap_bind_s() failed: Invalid Credentials.
Server error: 8009030C: LdapErr: DSID-0C090516, comment: AcceptSecurityContext error, data 52e, v3839
Error 0x8009030C The logon attempt failed

Now I can try any combination I like. I can leave out the domain name, just use "dev", ... Nothing works.

This works remotely i.e. use "" as the LDAP address and login as dev/userxxx.

So what if I try the "dev.local" address?

The connect works. Now for the Bind.

This works! But only if I leave the domain blank.

This gives:

0 = ldap_set_option(ld, LDAP_OPT_ENCRYPT, 1)
res = ldap_bind_s(ld, NULL, &NtAuthIdentity, NEGOTIATE (1158)); // v.3
    {NtAuthIdentity: User='xxxldap'; Pwd=; domain = ''}
Authenticated as: 'DEV\xxxLDAP'.

I'm not a DC / LDAP guru so can't explain this but hopefully this will help someone stuck on the same issue.


Thursday, June 22, 2017

ADFS : Moving the "Active Directory" IDP entry to the top of the list

This is for ADFS 4.0 (Server 2016).

This post shows how to rename the "Active Directory" IDP and at the bottom of the post is a comment around "move Active Directory to Top" and some script.

This script assumes a set number of IDP and looking at the script, it seems to move the names but not the URL i.e. if you had two IDP viz. IDP A and "Active Directory", it would swop the names around but clicking "Active Directory" would in fact navigate to IDP A.

Also, there are other considerations as mentioned by @Jorge in a reply:

"The list of IdPs in general is dynamic as you may add or remove an IdP. The code should take that into account.

In addition, per RP trust you can also specify a list of IdP that are allowed to use that RP trust and that list is a subset of the overall list of IdPs. Again, the code should take that into account.

It should not matter how long the IdP list is.

Is it possible to make this dynamic where the logic is something like:

* if more than 1 IdP is listed and the AD IdP is included, then move that IdP to the top."

I needed to move this entry to the top.

I would not have got this to work without having the ability to debug.

This is the script I came up with:

// This script moves the "Active Directory" entry (the local IDP) to the top of the list.

// Per RP trust you can specify a list of IdP that are allowed to use that RP trust and that list is a subset 
// of the overall list of IdPs. This list may not have an "Active Directory" entry.

// If there is only one entry, no point in re-ordering!

// The logic is:

// If more than one IDP is listed and the "Active Directory" IDP is included, then move that IdP to the top.


var idp = document.getElementsByClassName("idp");

var totElements = idp.length;

var listAllSpanForIdp = document.getElementsByClassName("idpDescription float");

var adElementPresent = false;

var inc;

for (inc = 0; inc < listAllSpanForIdp.length; inc++) {
  if (listAllSpanForIdp[inc].innerText == "Active Directory") {
    adElementPresent = true;

if ((totElements > 1) && (adElementPresent)) {
  var lastElement = totElements - 1;

  idp[lastElement].parentNode.insertBefore(idp[lastElement], idp[0]);

I move the elements around in the DOM as per this.

idp[lastElement].parentNode.insertBefore(idp[lastElement], idp[0]);

This inserts one node before the other.

You get the parent of the node. You then call the insertBefore method on the parent and you pass it the idp[lastElement] node (the "Active Directory" IDP  one) and tell it you want it inserted before idp[0] (the first one). This then swops their order.

This seems to work across all the requirements.


Wednesday, June 21, 2017

ADFS : Debugging onload.js when customising the Login, Update Password and Home Realm Discovery (HRD) screens

This is for ADFS 3.0 / 4.0 (Server 2012 R2 and 2016).

I've done a number of posts around the customisation but the hard part is that I could not debug the JavaScript in onload.js.

Then I came across JSFiddle.

This allows you to input your HTML, your css and your JavaScript and then run the script and see the result.

The screen is divided into four segments:

Top left = HTML
Bottom left = JavaScript
Top right = css
Bottom right = Result

I'm playing around with the order of the HRD IDP so this post concentrates on that functionality.

(The full post around the order is here).

In a browser, navigate to the HRD screen and then view the source.

Copy the entire:

form id="hrd" method="post" autocomplete="off" ...

section into the HTML.

Obviously, what HTML you select depends on what you are trying to achieve.

Then write your JavaScript in the JavaScript window.

Then click "Run".

The results will show in the Results section.

Perfect - so now I can play around and see the result. This is far easier than going through the whole theme / upload etc. procedure.

What would be the cherry on top is if I could step through and debug it. And like Bob the Builder - "Yes you can!".

 Run JSFiddle in Chrome.

You can add:

console.log (idp.length);

commands if you want.

To hook into the debugger, add this command at the point that you want to invoke it.


In Chrome, hit "F12" - the developer window.

Now hit "Run" in JSFiddle.

The debugger will be activated:

 Now you can step through using the commands top right and view Local etc.

 Any console output you are looking for is under the "Console" tab.

This is SO much easier.


ADFS : Adding extra text and links to the Login and Update Password screens

This is for ADFS 3.0 / 4.0. (Server 2012 R2 / 2016).

There are PowerShell commands to change text but there is nothing to add text, links etc.

We use the js inject mechanism described here.

Assume we want extra links on both the login and Update Password screens but we only want the text on the Update Password page.

And we want the text in blue.

The trick is to find an element on the Update Password HTML that is not on the login page.

"cancelButton" fits the bill.

// Add link and text

if ( document.getElementById("footerPlaceholder") ) {
   if ( document.getElementById("cancelButton") ) {    
     var str = "<p>Some extra text - lots of words - blah blah blah<p>";
     var result = str.fontcolor("blue");    
   } else {
     var result = "";
   document.getElementById("footerPlaceholder").innerHTML = result + "<br/><p>Help? <A href='https://company/help'>Get help</A></p><br/><p>Repost an Issue? <A href='https://company/issues'>Report an Issue</A></p>";

The screens are then:

Note that the "Cancel" button in the "Update Password" screen has been removed as per this.


ADFS : Remove the "Cancel" button from the Update Password screen

This is for ADFS 3.0 / 4.0 (Server 2012 R2 / 2016).

I don't actually get the "Cancel" button on this screen. It doesn't seem to do anything and just confuses people.

So why not remove it?

This is just another change to onload.js. (See this for how to make a new theme etc.).

// Remove Cancel button for "Update Password" screen

if ( document.getElementById("cancelButton") ) {
   document.getElementById("cancelButton").outerHTML = "";

Notice the user of "outerHTML" to remove the whole element.


Tuesday, June 20, 2017

ADFS : Continuing the Login and Home Realm Discovery (HRD) and Change Password customisation adventure

I've posted a number of times on this topic and during my research came across a number of useful articles so I thought I would wrap them all up as a reference.

This is for Server 2012 / Server 2016 - (ADFS 3.0 and 4.0).

I found that most articles I came across simply regurgitate the information in the official articles. I just wonder what the point is?

The official Microsoft reference is:

AD FS user sign-in customisation

Add sign-in page description

 Home Realm Discovery Customisation

Update Password

Some code to allow the ADFS Cancel button on the Update Password page (Expired Password) to redirect back to the original page.

ADFS 3.0 Cancel Button Redirection and Password Change Link


Just remove the button:

ADFS : Remove the "Cancel" button from the Update Password screen

Handling Expired Passwords in AD FS 2012 R2

What's interesting about this article is that the custom js is in a separate file, it's added via the additional file resources and then "injected" i.e.

Set-AdfsGlobalWebContent –SignInPageDescriptionText "&lt;script type=""text/javascript"" src=""/adfs/portal/script/custom.js"">&lt;/script>"

Most examples for text strings simply replace the text with other text but as this shows, you can replace the text with JavaScript. You could use this technique for the other screens as well.

You can add text and links:

ADFS : Adding extra text and links to the Login and Update Password screens

Adding some help text around password requirements:

ADFS : Adding default password rules to the Change and Update Password pages

Login page

Adding buttons instead of links:

Customize the ADFS authentication page with buttons!

Using sAMAccountName to login rather than User Principal Name (UPN) or using DOMAIN\username.

Using SAMAccountName to Login to ADFS in Windows Server 2012R2/2016


Accept SAM-account name as a login format on the ADFS form-based password update page

Don't like the screen - just redo it!

How to “TOTALLY” customize your Home Realm Discovery Page in Windows Server 2012 R2 ADFS

Hiding others customers when using Office 365.

Customizing the AD FS 3.0 Sign-in Page Logo

You can add text and links:

ADFS : Adding extra text and links to the Login and Update Password screens

Hiding some of the RP in the IDPInitiated scenario:

How to Hide a Relying Party from AD FS 3.0

Forcing a button click automatically on logout:

How do I customize the ADFS 3.0 logout page to force sign out?

Don't like the copyright notice?

ADFS : Removing the copyright notice - the easy way 

Slightly different technique to add a link:

Adding A Link To The SSPR Page In The ADFS FBA Page


Changing the "Active Directory" name in ADFS 4.0 to something more appropriate.

ADFS 2016 – Change the Active Directory claim provider display name in the Home Realm Discovery page

At the bottom of that article, there is some JavaScript to show how to move this entry (the local AD) to the top. Unfortunately, it is hard-coded for a certain number of IDP and needs to be more dynamic.

This is a more dynamic solution.

ADFS : Moving the "Active Directory" IDP entry to the top of the list

Another example here.

If you use the -OrganizationalAccountSuffix to associate a RP with an IDP, you get something like:

If you want to skip this, have a read of:

Customize the Home Realm Discovery page to ask for UPN right away

-OrganizationalAccountSuffix is out-of-the-box for ADFS 4.0.

To do this in ADFS 3.0:

Customizing the AD FS sign-in pages per relying party trust

If you want to change the thumbnail images:

Customizing the IDP images in the Home Realm Discovery page

You can add extra text to the pages:

ADFS : Adding messages to the ADFS login / HRD screens

If you are wondering about how to get the small text inside the "button", refer:

ADFS : Adding extra text to the HRD screen IDP description


The standard commands to change the default theme are in the official links at the top.

Note that you can change any collateral in the theme.

ADFS : You can change anything in the Theme structure


"Unless you have saved all the PowerShell cmdLet you typed to create your custom theme in your pre-production environment, it is quite challenging to recreate the exact same webtheme on your production servers. It is easy to export a configuration with the Export-WebTheme cmdLet. But it does not give you the ability to re-import what you just exported. I wrote the following script to help with that:"

How to export an ADFS custom web theme and import it to another serverrt-an-adfs-custom-webtheme-and-import-it-to-another-server/

And you can debug the onload.js. Bargain!

ADFS : Debugging onload.js when customising the Login, Update Password and Home Realm Discovery (HRD) screens

Want pop-ups with that?

ADFS : Pop-ups on the HRD / login and change password screens 

I'll keep adding to this page as new examples come to light.


Friday, June 16, 2017

ADFS : Adding messages to the ADFS login / HRD screens

This is for Server 2012 R2 / Server 2016.

There are a number of posts out there around this, mainly around changing the text of an element in onload.js e.g.

element.innerHTML = "Some text"

where that element already has a text element and you are simply overwriting it.

What I didn't realise is that you can do this with any element, even those that don't currently have text.

I needed to add some text to the HRD screen. The only text there is the copyright message at the bottom.

<div id="footerPlaceholder"></div>
<div id="footer">
<div id="footerLinks" class="floatReverse">
<div><span id="copyright">© 2016 Microsoft</span></div>

There's an element there called "footerPlaceholder". It has no text.


if ( document.getElementById("footerPlaceholder") ) {
   document.getElementById("footerPlaceholder").innerHTML = "<p>
If you need help, please look at <A href='https://company/help'>

gives us:

This then flows into the login page:

If you don't want that, you need to filter by:

//Check if we are in the HRD page
if ( document.getElementById("hrdArea") ) {