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

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") ) {


Monday, June 12, 2017

ADFS : Beware copying over claims rules when they contain groups

I copy claims rules over all the time as per my earlier post.

So I did this and it wouldn't work.

Much head scratching and then I realised that  one of the claims rules was a "Send Group Membership as a Claim".

If you look at this type of rule, it looks like:

c:[Type == "", Value == "S-1-5-21-965288371-...-1106", Issuer == "AD AUTHORITY"]
 => issue(Type = "", Value = "Admin", Issuer = c.Issuer, OriginalIssuer = c.OriginalIssuer, ValueType = c.ValueType);

Notice that it has a SID and (of course) this SID is relevant to that instance of AD only.

The same group name in a different AD will have a different SID value.

So, beware, you can't just copy these types of rules over!


Tuesday, June 06, 2017

ADFS : Adding extra text to the HRD screen IDP description

This is for Home Realm Discovery for Server 2012 R2 or 2016 (ADFS 3.0 or 4.0).

Building on from @Pierre's ADFS 2016 – Change the Active Directory claim provider display name in the Home Realm Discovery page.

As per that article, the IDP name is coded in the JavaScript as:

var strADCPName = "Corp Users" ;

What you can do is add a line of text beneath it:

var strADCPName = "Corp Users <br/><small>(Add some text here to suit)</small>" ;

This displays something like:

Because of the HTML there are only a limited amount of characters you can add but it is a neat way to add a better description.

If you are wondering how to change the icon (I just used a random one), refer:

ADFS : You can change anything in the Theme structure


Friday, June 02, 2017

ADFS : OAuth token timeout

This is for Server 2016 - ADFS 4.0.

These are the OpenID Connect / OAuth options that you have.
  • Native application
  • Server application
  • Web API
and combinations of the above.

But nowhere in the wizard can you set the token timeout.

AD FS Scenarios for Developers shows the following PowerShell commands:

Add native client                         Add-AdfsNativeClientApplication
Add server application as client  Add-AdfsServerApplication
Add Web API / resource             Add-AdfsWebApiApplication

Building on this we can do:


Name                       : AppA  - Native application
Identifier                 : b1...28
ApplicationGroupIdentifier : AppA
Description                :
Enabled                    : True
RedirectUri                : {ms-app://s-45...04/} 


ADUserPrincipalName                  :
ClientSecret                         : ********
JWTSigningCertificateRevocationCheck : None
JWTSigningKeys                       : {}
JWKSUri                              :
Name                                 : AppB - Server application
Identifier                           : 8e...44
ApplicationGroupIdentifier           : AppB
Description                          :
Enabled                              : True
RedirectUri                          : {https://localhost:1234/}


Name                                 : AppA  - Web API
Identifier                           : {https://localhost:44666/TodoListService}
AccessControlPolicyName              : Permit everyone
AccessControlPolicyParameters        :
AdditionalAuthenticationRules        :
AllowedAuthenticationClassReferences : {}
AllowedClientTypes                   : Public, Confidential
ApplicationGroupIdentifier           : AppA
ApplicationGroupId                   :
AlwaysRequireAuthentication          : False
ClaimsProviderName                   : {}
DelegationAuthorizationRules         :
Enabled                              : True
ImpersonationAuthorizationRules      :
IssuanceAuthorizationRules           :
IssueOAuthRefreshTokensTo            : AllDevices
IssuanceTransformRules               : @RuleTemplate = "LdapClaims"
                                                        ... Some claims ...

NotBeforeSkew                        : 0
Description                          :
PublishedThroughProxy                : False
RefreshTokenProtectionEnabled        : False
RequestMFAFromClaimsProviders        : False
ResultantPolicy                      : RequireFreshAuthentication:False
                                         Permit everyone
TokenLifetime                        : 480

And here we see a token lifetime!

But note the option only applies to web API.

To set this use:

set-AdfsWebApiApplication -TargetIdentifier "https://localhost:44666/TodoListService" -TokenLi
fetime 480