Tuesday, March 20, 2018

Certificates : Getting the thumbprint via OpenSSL

I've been looking at AWS Cognito and keep coming across interesting snippets of how to do things.

Let's say you wanted the ADFS thumbprint for the SSL certificate.

You could do this via mmc or via the ADFS wizard or via the IIS binding.

You could also do:

openssl s_client -showcerts -connect my-adfs:443

Note: You just use the top-level ADFS URL - don't add /adfs/ls etc.

This displays:

Loading 'screen' into random state - done
depth=0 CN = my-adfs
verify error:num=18:self signed certificate
verify return:1
depth=0 CN = my-adfs
verify return:1
Certificate chain
 0 s:/CN=my-adfs
Server certificate
No client certificate CA names sent
SSL handshake has read 1964 bytes and written 447 bytes
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 4096 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES256-GCM-SHA384
    Session-ID: 29140000...E4D79A337F1F0BBC9

    Master-Key: 91E8...DE30CD
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1521150875
    Timeout   : 300 (sec)
    Verify return code: 18 (self signed certificate)

Copy / paste this section:


into a file called e.g. adfs.cer


openssl x509 -in c:\xxx\adfs.cer -fingerprint -noout

SHA1 Fingerprint=24:F8:...:9A:21:2B:35 


Tuesday, March 13, 2018

SAML : Decoding the SAML response

I've blogged before about this and I normally use the SAML Tracer running under Firefox.

Someone asked me about AWS Cognito and while I was having a look at this and doing some troubleshooting, I came across a page that also showed you how you can do this with PowerShell.

Basically, in your trace find the "SAML Response".

Then copy / paste it into:


so something like:

PS C:\> [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64Strin

<samlp:Response ID="_f560b...9cf8c7d" Version="2.0" IssueIn
stant="2018-03-13T02:13:05.625Z" Destination="https://signin.aws.amazon.com/saml
" Consent="urn:oasis:names:tc:SAML:2.0:consent:unspecified" xmlns:samlp="urn:oas



Wednesday, February 14, 2018

ADFS : MSIS9642: The request cannot be completed

This is for Server 2016 (ADFS 4.0).

The full error is:

MSIS9642: The request cannot be completed because an id token is required but the server was unable to construct an id token for the current user.

You only get this error if you are using OpenID Connect with ADAL configured via Application Groups.

Our setup is:

User --> application --> external ADFS A --> internal ADFS B via HRD

We had used this model no problem with OWIN OIDC applications authenticating on both the internal and external ADFS.

However, on the applications that used ADAL, external authentication worked fine but trying the internal one threw the above error.

ADFS A is set up as a CP to ADFS B.

There's a good write-up here.

"The root cause of MSIS9642 is that the new OpenID Connect Application Group features in ADFS 2016 need to issue an access token to your application. This token must include the users identity. In order to issue the token the subsystem must understand which claim in the inbound claims is used to uniquely identify the user.

A new property called AnchorClaimType has been added to the Claim Provider Trust model."

Note that this property is not available on a RP trust.

The PowerShell needs to be run on the CP server i.e. ADFS A.

(Get-AdfsClaimsProviderTrust -Name "CP name").anchorclaimtype

This will be blank the first time. You can use any attribute that makes sense to uniquely identify the user. Typically, this would be sAMAccountName or UPN.

In our case, we had a custom claim so the command was:

Set-AdfsClaimsProviderTrust -TargetName "CP Trust" -AnchorClaimType "http://company/claims

and you can check this is correct by running the above Get-AdfsClaimsProviderTrust command again.

Remember that you need to pass-through this claim in the CP claims rules and the RP claims rules.


Monday, February 12, 2018

ADFS : Postman : Getting refresh token on Server 2016 - ADFS 4.0

Using Postman for the Authorisation Code Grant on Server 2016 (ADFS 4.0) is documented here.

Then someone asked me how to extend this to get a new access token using the refresh token.

Recall that the second part of the code grant is to send a code to the /token endpoint that returns an access token, a refresh token and an ID token.

To get a new access token, we use the same /token endpoint with the parameters above and the same refresh token that we received as described above.

This returns an access token and an ID token. It does not return another refresh token?

So back to the OAuth spec (RFC 6749) section:

6. Refreshing an Access Token

"If valid and authorized, the authorization server issues an access token as described in Section 5.1. If the request failed verification or is invalid, the authorization server returns an error response as described in Section 5.2.

The authorization server MAY issue a new refresh token, in which case the client MUST discard the old refresh token and replace it with the new refresh token.

The authorization server MAY revoke the old refresh token after issuing a new refresh token to the client. If a new refresh token is issued, the refresh token scope MUST be identical to that of the refresh token included by the client in the request."

So that is correct.

Note that you can use this refresh token over and over again until it expires and each time you will get a new access token.

There's a good write-up here around configuring the refresh token timeouts etc.

It revolves around the PowerShell command:

Get-AdfsRelyingPartyTrust |fl Name, IssueOAuthRefreshTokensTo, AlwaysRequireAuthentication, TokenLifetime

Name                        : RP Name
IssueOAuthRefreshTokensTo   : AllDevices
AlwaysRequireAuthentication : False
TokenLifetime               : 960


Friday, January 26, 2018

ADFS : The strange case of the wrong SAML signature

A customer was working fine and then within a short space of time Dev, QA and Production all stopped working for a Java SAML SaaS product with the error:

Microsoft.IdentityModel.Protocols.XmlSignature.SignatureVerificationFailedException: MSIS0038: SAML Message has wrong signature. Issuer: 'xxx'.

Back in the day, there was a bug in ADFS that produced this error but it was misleading - it had nothing to do with certificates. But I could find no reference to a new bug.

Coincidentally, the ADFS certificates rolled around the same time.

That's where we put our effort and nothing helped. We turned rollover off and on, we used the "urgent" construct to force new certificates etc.

Nothing doing :-(

In desperation, I asked the supplier to send us the contents of the key store.

Then I noticed that the thumbprint of their signing certificate didn't match the one in ADFS,

This certificate expires in 2026. Why on earth did in change?

So I did some digging. Turns out this was the "new kid on the block" syndrome. The guru who normally did this had left and they gave the job to a newbie.

He looked at the document he was given but did not realise that this was "as-built" not "deployment".

So every time he built a new build, he changed the signing certificate. He didn't supply it to ADFS.

That's why the error progressively rolled. The company wanted a fix and as the deployment rolled through the various environments, it broke.

Sometimes, you have to look outside of the square.

Again, best practice and supplying metadata would have helped.

To quote Sherlock Holmes:

"When you have eliminated the impossible, whatever remains, however improbable, must be the truth".


Tuesday, January 23, 2018

Visual Studio : Unable to start debugging on the web server. A debugger is already attached.

Came across this error when we had more than one person working on a VS project which is hosted on a VM.

The setup script for a new user gives each person their own web site.

Because there is only one version of IIS, when multiple people try and debug their version, you get the error:

Unable to start debugging on the web server. A debugger is already attached.

The solution turned out to be simple. The debugger attaches to a process which is itself attached to an application pool.

Give each user an application pool i.e. make a new one in IIS Manager.

Attach each person's web site to their application pool in IIS Manager.

Just make sure that the pool is configured the same way as the original e.g. same .NET framework and managed pipeline.

Problem solved!


Friday, January 12, 2018

Certificates : Finding a thumbprint and using PowerShell

I always use mmc as the wizard to manage certificates but I needed to do some certificate work and I wondered if there was a way of automating it.

Turns out you can with PowerShell.

Instead of \cd to a drive, you go to the certificate store with:

cd CERT:\\


PS Cert:\> dir

Location   : CurrentUser
StoreNames : {ACRS, SmartCardRoot, Root, Trust...}

Location   : LocalMachine
StoreNames : {TrustedPublisher, ClientAuthIssuer, Remote Desktop, Root...}

Then we can do things like:

dir .\\CurrentUser\My

dir .\\LocalMachine\My

which gives a list:

PSParentPath: Microsoft.PowerShell.Security\Certificate::LocalMachine\My

Thumbprint                          Subject
----------                                -------

If we want to see the structure, we can do:

PS Cert:\currentuser> get-childitem

which gives:

Name : ACRS

Name : SmartCardRoot

Name : Root

Name : Trust

Name : AuthRoot

Name : CA

Name : UserDS

Name : Disallowed

Name : My

Name : TrustedPeople

Name : TrustedPublisher

Name : ClientAuthIssuer

If we want to find a certificate with a particular thumbprint, we can use:

Get-ChildItem -Path 'thumbprint' -recurs

which gives:

PS Cert:\> Get-ChildItem -Path 'CD...72' -recurse

PSParentPath: Microsoft.PowerShell.Security\Certificate::CurrentUser\Root

Thumbprint                                Subject
----------                                -------
CD...72  CN=Microsoft Root Certificate Authority, DC=microsoft, DC=com

PSParentPath: Microsoft.PowerShell.Security\Certificate::LocalMachine\Root

Thumbprint                                Subject
----------                                -------
CD...72  CN=Microsoft Root Certificate Authority, DC=microsoft, DC=com

or we can get a list:

Get-ChildItem -Path 'thumbprint' -recurse | Format-List -Property *

which gives:

PSPath                   : Microsoft.PowerShell.Security\Certificate::CurrentUser\Root\CD...72
PSParentPath             : Microsoft.PowerShell.Security\Certificate::CurrentUser\Root
PSChildName              : CD...72
PSDrive                  : Cert
PSProvider               : Microsoft.PowerShell.Security\Certificate
PSIsContainer            : False
EnhancedKeyUsageList     : {}
DnsNameList              : {Microsoft Root Certificate Authority}
SendAsTrustedIssuer      : False
EnrollmentPolicyEndPoint : Microsoft.CertificateServices.Commands.EnrollmentEndPointProperty
EnrollmentServerEndPoint : Microsoft.CertificateServices.Commands.EnrollmentEndPointProperty
PolicyId                 :
Archived                 : False
Extensions               : {System.Security.Cryptography.Oid, System.Security.Cryptography.Oid,
                           System.Security.Cryptography.Oid, System.Security.Cryptography.Oid}
FriendlyName             : Microsoft Root Certificate Authority
IssuerName               : System.Security.Cryptography.X509Certificates.X500DistinguishedName
NotAfter                 : 10/05/2031 11:28:13 AM
NotBefore                : 10/05/2011 11:19:22 AM
HasPrivateKey            : False
PrivateKey               :
PublicKey                : System.Security.Cryptography.X509Certificates.PublicKey
RawData                  : {48, ... 153}
SerialNumber             : 79...65
SubjectName              : System.Security.Cryptography.X509Certificates.X500DistinguishedName
SignatureAlgorithm       : System.Security.Cryptography.Oid
Thumbprint               : CD...72
Version                  : 3
Handle                   : 25...92
Issuer                   : CN=Microsoft Root Certificate Authority, DC=microsoft, DC=com

Subject                  : CN=Microsoft Root Certificate Authority, DC=microsoft, DC=com


Monday, January 08, 2018

stackoverflow : Privileges

Stackoverflow has levels of privilege. As your reputation goes up, you get to be able to do more.

The top level is 25,000 that I just achieved.

My current ranking is 4242 out of the 8 million odd that have used stackoverflow.

So I need a new goal :-).

I decided that my next goal is to answer 1,000 questions.

Coincidentally, my stats show that I clocked up 750,000 page views as well.



Friday, December 08, 2017

ADFS : InvalidContextException: MSIS7001

The full error message is:

Microsoft.IdentityServer.Web.CookieManagers.InvalidContextException: MSIS7001: The passive protocol context was not found or not valid. If the context was stored in cookies, the cookies that were presented by the client were not valid. Ensure that the client browser is configured to accept cookies from this website and retry this request.

I've often wondered what this means?

Then I had a issue which I could repeat and with the help of @Pierre, I sorted it out.

My path was:

Application --> ADFS --> SAML --> Another IDP -->  Another IDP

The request was:


This results in:

Set-Cookie: MSISContext620d9067-4bc1-439b-ad21-0d419d3cbd19=UlB...cw==; path=/adfs; HttpOnly; Secure

Notice that the RelayState is added to the name of the cookie.

Somewhere upstream, the RelayState changed.

When the response comes back to ADFS, ADFS checks for a cookie with the new RelayState name that doesn't exist.

Hence the error.


Wednesday, November 22, 2017

Fiddler : Some tips

Doing some Fiddler traces recently and these tips helped me.

Modern browsers are far stricter about security and using Fiddler sometimes blocks a process that works fine without.

These settings help:

Also, sometimes you can't get round an issue.

What you can do is use IE's Developer Tools (F12).

Network tab - "Export captured traffic".

Then import the saved file into Fiddler.

If you use Chrome, you can save the trace as a .har file.

You can "Import Sessions" on Fiddler and then select  "HTTPArchive".


Monday, November 20, 2017


This tool has been extended with more scripts and tooling.

For the log tools:

"AdfsEventsModule Overview

This module provides tools for gathering related ADFS events from the security, admin, and debug logs, across multiple servers. This tool also allows the user to reconstruct the HTTP request/response headers from the logs.

Cmdlets in AdfsEventsModule

This module exposes two cmdlets:




The detailed parameters for each are provided below.

The Get-ADFSEvents cmdlet is used to aggregate events by correlation ID, while the Write-ADFSEventsSummary cmdlet is used to generate a PowerShell Table of only the most relevant logging information from the events that are piped in."

For the Diagnostics,  this downloads a PowerShell module that you need to import:

import-module -name .\ADFSDiagnostics.psm1 -verbose
VERBOSE: Loading module from path 'C:\junk\ADFSDiagnostics.psm1'.
VERBOSE: Importing function 'Get-AdfsServerConfiguration'.
VERBOSE: Importing function 'Get-AdfsServerTrace'.
VERBOSE: Importing function 'Get-AdfsSystemInformation'.
VERBOSE: Importing function 'Get-AdfsVersionEx'.
VERBOSE: Importing function 'Receive-AdfsServerTrace'.
VERBOSE: Importing function 'Set-ADFSDiagTestMode'.
VERBOSE: Importing function 'Start-AdfsServerTrace'.
VERBOSE: Importing function 'Test-AdfsServerHealth'.
VERBOSE: Importing function 'Test-AdfsServerHealthSingleCheck'.
VERBOSE: Importing function 'Test-AdfsServerToken'.

Some examples:


OSVersion                 : 10.0.14393.0
OSName                    : Microsoft Windows Server 2016 Datacenter
MachineDomain             : dev.local
IPAddress                 :
TimeZone                  : Coordinated Universal Time
LastRebootTime            : 10/24/2017 6:49:22 PM
MachineType               : Virtual Machine
NumberOfLogicalProcessors : 1
MaxClockSpeed             : 2394
PhsicalMemory             : 1792
Hosts                     : {}
Hotfixes                  : {KB4023834, KB3199986, KB4013418, KB4035631...}
AdfsWmiProperties         : {ConfigurationDatabaseConnectionString, ConfigurationServiceAddress,
SslBindings               : {System.Collections.Hashtable, System.Collections.Hashtable, System.Collections.Hashtable,
AdfssrvServiceAccount     : DEV\xxx
AdfsVersion               : 3.0
Role                      : STS
Top10ProcessesByMemory    : {@{Name=Microsoft.Sirona.OMS.Security.BaselineAssessment; MemoryInMB=80.625;
                            @{Name=Microsoft.Identity.AadConnect.Health.AadSync.Host; MemoryInMB=76.25390625;
                            MemoryPercentOfTotal=4.25524030412946}, @{Name=miiserver; MemoryInMB=57.1640625;
                            MemoryPercentOfTotal=3.18995884486607}, @{Name=MsMpEng; MemoryInMB=47.8046875;
AdHealthAgentInformation  : AdHealthAgentInformation


ADFSSyncProperties                        : Microsoft.IdentityServer.Management.Resources.SyncPropertiesBase
ADFSAttributeStore                        : {Microsoft.IdentityServer.Management.Resources.AttributeStore,
ADFSCertificate                           : {@{Certificate=[Subject]


                                            [Serial Number]

                                            [Not Before]
                                              8/21/2017 12:00:00 PM

                                            [Not After]
                                              8/28/2027 12:00:00 PM

                                            ; CertificateType=Service-Communications; IsPrimary=True; StoreName=My;
                                              CN=ADFS Encryption - xxx

                                              CN=ADFS Encryption - xxx

                                            [Serial Number]

                                            [Not Before]
                                              11/2/2017 8:31:02 PM

                                            [Not After]
                                              11/2/2018 8:31:02 PM

                                            ; CertificateType=Token-Decrypting; IsPrimary=True; StoreName=My;
                                              CN=ADFS Signing - xxx

                                              CN=ADFS Signing - xxx

                                            [Serial Number]

                                            [Not Before]
                                              11/2/2017 8:31:14 PM

                                            [Not After]
                                              11/2/2018 8:31:14 PM

                                            ; CertificateType=Token-Signing; IsPrimary=True; StoreName=My;
                                              CN=ADFS Encryption - xxx

                                              CN=ADFS Encryption - xxx

                                            [Serial Number]

                                            [Not Before]
                                              11/22/2016 7:34:42 PM

                                            [Not After]
                                              11/22/2017 7:34:42 PM

                                            ; CertificateType=Token-Decrypting; IsPrimary=False; StoreName=My;
ADFSClaimDescription                      : {Microsoft.IdentityServer.Management.Resources.ClaimDescription,
ADFSEndpoint                              : {Microsoft.IdentityServer.Management.Resources.Endpoint,
ADFSProperties                            : Microsoft.IdentityServer.Management.Resources.ServiceProperties
ADFSRelyingPartyTrustCount                : 4
ADFSClaimsProviderTrustCount              : 6
ADFSConfigurationDatabaseConnectionString : Data Source=np:\\.\pipe\microsoft##wid\tsql\query;Initial
                                            Catalog=AdfsConfigurationV3;Integrated Security=True
AdfssrvServiceAccount                     : DEV\xxx
AdfsVersion                               : 3.0
AadTrustStatus                            : Not Configured
ADFSAdditionalAuthenticationRule          :
ADFSClient                                : {Microsoft.IdentityServer.Management.Resources.AdfsClient,
ADFSGlobalAuthenticationPolicy            : Microsoft.IdentityServer.Management.Resources.AdfsGlobalAuthenticationPolic
ADFSDeviceRegistration                    : Microsoft.IdentityServer.Management.Resources.DeviceRegistrationServiceObject

Test-AdfsServerHealth | ft Name,Result  -AutoSize

Name                                                         Result
----                                                         ------
IsAdfsRunning                                                  Pass
IsWidRunning                                                   Pass
PingFederationMetadata                                         Pass
CheckAdfsSslBindings                                           Pass
Test-Certificate-Token-Decrypting-Primary-NotFoundInStore    NotRun
Test-Certificate-Token-Decrypting-Primary-IsSelfSigned       NotRun
Test-Certificate-Token-Decrypting-Primary-PrivateKeyAbsent   NotRun
Test-Certificate-Token-Decrypting-Primary-Expired              Pass
Test-Certificate-Token-Decrypting-Primary-Revoked              Pass
Test-Certificate-Token-Decrypting-Primary-AboutToExpire      NotRun
Test-Certificate-Token-Signing-Primary-NotFoundInStore       NotRun
Test-Certificate-Token-Signing-Primary-IsSelfSigned          NotRun
Test-Certificate-Token-Signing-Primary-PrivateKeyAbsent      NotRun
Test-Certificate-Token-Signing-Primary-Expired                 Pass
Test-Certificate-Token-Signing-Primary-Revoked                 Pass
Test-Certificate-Token-Signing-Primary-AboutToExpire         NotRun
Test-Certificate-SSL-Primary-NotFoundInStore                   Pass
Test-Certificate-SSL-Primary-IsSelfSigned                      Fail
Test-Certificate-SSL-Primary-PrivateKeyAbsent                  Pass
Test-Certificate-SSL-Primary-Expired                           Pass
Test-Certificate-SSL-Primary-Revoked                           Pass
Test-Certificate-SSL-Primary-AboutToExpire                     Pass
Test-Certificate-Token-Decrypting-Secondary-NotFoundInStore  NotRun
Test-Certificate-Token-Decrypting-Secondary-IsSelfSigned     NotRun
Test-Certificate-Token-Decrypting-Secondary-PrivateKeyAbsent NotRun
Test-Certificate-Token-Decrypting-Secondary-Expired            Pass
Test-Certificate-Token-Decrypting-Secondary-Revoked            Pass
Test-Certificate-Token-Decrypting-Secondary-AboutToExpire    NotRun
Test-Certificate-Token-Signing-Secondary-NotFoundInStore     NotRun
Test-Certificate-Token-Signing-Secondary-IsSelfSigned        NotRun
Test-Certificate-Token-Signing-Secondary-PrivateKeyAbsent    NotRun
Test-Certificate-Token-Signing-Secondary-Expired               Pass
Test-Certificate-Token-Signing-Secondary-Revoked               Pass
Test-Certificate-Token-Signing-Secondary-AboutToExpire       NotRun
CheckFarmDNSHostResolution                                     Pass
CheckDuplicateSPN                                              Pass
TestServiceAccountProperties                                   Pass
TestAppPoolIDMatchesServiceID                                NotRun
TestComputerNameEqFarmName                                     Pass
TestSSLUsingADFSPort                                         NotRun
TestSSLCertSubjectContainsADFSFarmName                         Pass
TestAdfsAuditPolicyEnabled                                     Fail
TestAdfsRequestToken                                           Pass
CheckOffice365Endpoints                                        Pass
TestADFSO365RelyingParty                                     NotRun
TestNtlmOnlySupportedClientAtProxyEnabled                      Fail

Test-AdfsServerHealth | where {$_.Result -eq "Fail"} | fl

Name             : Test-Certificate-SSL-Primary-IsSelfSigned
Result           : Fail
Detail           : SSL certificate with thumbprint 24...35 is self-signed.
Output           : {Thumbprint}
ExceptionMessage :

Name             : TestAdfsAuditPolicyEnabled
Result           : Fail
Detail           : Audits are not configured for Usage data collection : Expected 'Success and Failure', Actual='No
Output           : {StsAuditConfig, MachineAuditPolicy}
ExceptionMessage :

Name             : TestNtlmOnlySupportedClientAtProxyEnabled
Result           : Fail
Detail           : NtlmOnlySupportedClientAtProxy is disabled; extranet users can experience authentication failure.

Output           : {NtlmOnlySupportedClientAtProxy}
ExceptionMessage :

More examples here.


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?

My understanding is that to get the custom claims, you need to do a POST whereas adal.js does a GET. This requires the claims to be in the URL which is not secure and may make the URL too long.

This is a restriction of adal.js; not a restriction of the protocol.

This post suggests that you can fix the problem by proxying the GET to a POST.

Also of interest is that using the identityserver oidc-client-js stack instead of adal.js does not have have this problem. But then you lose the goodness of ADAL.

Claims rules are a huge part of the advantage of ADFS. It's a pity that they can't be used in this scenario.