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.