Auth0 have a neat playground where you can play around with the Lock settings.
Lock is the Auth0 login component.
I was trying to get some extra fields added when the user wants to self-register and we want to capture some extra information.
There are examples but they don't have context i.e. they show you what attribute to set but you don't get to see the full picture.
As usual, the gist is here.
This is the basic screen - notice I've added some of the Asian social providers like Baidu. This isn't part of the js - it's part of the application configuration.
Here is the signup screen. Clicking "United States" shows the drop-down. Also notice the checkbox at the bottom.
Shortening the text shows the error message that is part of the validation.
Enjoy!
Ideas and thoughts about Microsoft Identity, C# development, cabbages and kings and random flotsam on the incoming tide
Wednesday, June 20, 2018
Wednesday, May 16, 2018
ADFS : Cookies, tokens and timeouts
This is for Server 2016 (ADFS 4.0).
I've been helping a customer get to the bottom of token timeouts, sessions timeouts etc.
The two best links I've found are:
AD FS Single Sign-On Settings
Active Directory Federation Services (#ADFS) Single Sign On (SSO) and token lifetime settings
and a few lines in:
AD FS Frequently Asked Questions (FAQ)
that are:
"How long are ADFS tokens valid?
Often this question means ‘how long do users get single sign on (SSO) without having to enter new credentials, and how can I as an admin control that?’ This behavior, and the configuration settings that control it, are described in the article here.
The default lifetimes of the various cookies and tokens are listed below (as well as the parameters that govern the lifetimes):
Registered Devices
PRT and SSO cookies: 90 days maximum, governed by PSSOLifeTimeMins. (Provided device is used at least every 14 days, which is controlled by DeviceUsageWindow)
Refresh token: calculated based on the above to provide consistent behavior
access_token: 1 hour by default, based on the relying party
id_token: same as access token
Un-registered Devices
SSO cookies: 8 hours by default, governed by SSOLifetimeMins. When Keep Me Signed in (KMSI) is enabled, default is 24 hours and configurable via KMSILifetimeMins.
Refresh token: 8 hours by default. 24 hours with KMSI enabled
access_token: 1 hour by default, based on the relying party
id_token: same as access token"
And here we see the first problem - there is a major distinction between registered and unregistered (aka non registered) devices and most of the documentation is for the former.
A registered device is a device that has been provisioned via EMS / Intune. You could add domain-joined here. This allows a user to BYOD and still have access to a company's intranet.
So if you have a customer with a B2C type of scenario where their users have a wide range of devices and never need to access the company intranet, you start to see some problems.
The first issue is that of persistent cookies.
Set-AdfsProperties –EnablePersistentSso
These are not enabled for unregistered devices. You can turn them on with the KMSI (Keep Me Signed In) option.
Set-AdfsProperties -EnableKmsi $true
What you now see in a PC browser is:
The defaults have changed from 8 hours to 24 as above.
However, on some mobile devices, the onload.js has a:
style="display:none"
which means that it does not display and you are back to square one.
This may be because there is a:
"&prompt=login"
in the query string,
So assuming KMSI is on, you have:
access token = id-token = 1 hour
SSO cookie = refresh token = 24 hours
To change the default:
Set-AdfsProperties – KmsiLifetimeMins int32
and if KMSI is off:
access token = id-token = 1 hour
SSO cookie = refresh token = 8 hours
To change the default:
Set-AdfsProperties –SsoLifetime int32
Also note that there is a KMSI "user component" (which adds the box) and a KMSI "ADFS feature" (that changes the timeout values).
You don't want the refresh token to time out because that would force the user to re-authenticate.
So you can use the "authorize" endpoint to get a brand new set of tokens. Because the SSO cookie has not yet expired, ADFS will simply mint a new set without any login requirement.
The tokens are "brand new" e.g the id-token will be valid for another hour.
By a "new set", I mean an access token, a refresh token and an id-token.
You get the same behaviour if you call the refresh endpoint.
However, I noticed that although the value of the refresh token is different, it has the same
"refresh_token_expires_in": 72186
value (adjusted by the time it took to do the refresh itself).
So the new refresh token inherits the old "time to timeout".
Enjoy!
I've been helping a customer get to the bottom of token timeouts, sessions timeouts etc.
The two best links I've found are:
AD FS Single Sign-On Settings
Active Directory Federation Services (#ADFS) Single Sign On (SSO) and token lifetime settings
and a few lines in:
AD FS Frequently Asked Questions (FAQ)
that are:
"How long are ADFS tokens valid?
Often this question means ‘how long do users get single sign on (SSO) without having to enter new credentials, and how can I as an admin control that?’ This behavior, and the configuration settings that control it, are described in the article here.
The default lifetimes of the various cookies and tokens are listed below (as well as the parameters that govern the lifetimes):
Registered Devices
PRT and SSO cookies: 90 days maximum, governed by PSSOLifeTimeMins. (Provided device is used at least every 14 days, which is controlled by DeviceUsageWindow)
Refresh token: calculated based on the above to provide consistent behavior
access_token: 1 hour by default, based on the relying party
id_token: same as access token
Un-registered Devices
SSO cookies: 8 hours by default, governed by SSOLifetimeMins. When Keep Me Signed in (KMSI) is enabled, default is 24 hours and configurable via KMSILifetimeMins.
Refresh token: 8 hours by default. 24 hours with KMSI enabled
access_token: 1 hour by default, based on the relying party
id_token: same as access token"
And here we see the first problem - there is a major distinction between registered and unregistered (aka non registered) devices and most of the documentation is for the former.
A registered device is a device that has been provisioned via EMS / Intune. You could add domain-joined here. This allows a user to BYOD and still have access to a company's intranet.
So if you have a customer with a B2C type of scenario where their users have a wide range of devices and never need to access the company intranet, you start to see some problems.
The first issue is that of persistent cookies.
Set-AdfsProperties –EnablePersistentSso
These are not enabled for unregistered devices. You can turn them on with the KMSI (Keep Me Signed In) option.
Set-AdfsProperties -EnableKmsi $true
What you now see in a PC browser is:
and indeed the cookies are now persistent if you tick the box.The defaults have changed from 8 hours to 24 as above.
However, on some mobile devices, the onload.js has a:
style="display:none"
which means that it does not display and you are back to square one.
This may be because there is a:
"&prompt=login"
in the query string,
So assuming KMSI is on, you have:
access token = id-token = 1 hour
SSO cookie = refresh token = 24 hours
To change the default:
Set-AdfsProperties – KmsiLifetimeMins int32
and if KMSI is off:
access token = id-token = 1 hour
SSO cookie = refresh token = 8 hours
To change the default:
Set-AdfsProperties –SsoLifetime int32
Also note that there is a KMSI "user component" (which adds the box) and a KMSI "ADFS feature" (that changes the timeout values).
You don't want the refresh token to time out because that would force the user to re-authenticate.
So you can use the "authorize" endpoint to get a brand new set of tokens. Because the SSO cookie has not yet expired, ADFS will simply mint a new set without any login requirement.
The tokens are "brand new" e.g the id-token will be valid for another hour.
By a "new set", I mean an access token, a refresh token and an id-token.
You get the same behaviour if you call the refresh endpoint.
However, I noticed that although the value of the refresh token is different, it has the same
"refresh_token_expires_in": 72186
value (adjusted by the time it took to do the refresh itself).
So the new refresh token inherits the old "time to timeout".
Enjoy!
Tuesday, April 24, 2018
Stackoverflow : How to treat newbies
Joel Spolsky is writing a series of articles on the evolution of stackoverflow.
Part of this is the treatment of newbies; in particular the arrogant treatment of people who genuinely need an answer but don't know how to ask the question.
Jon Skeet wrote an excellent post on how to ask a question.
The problem arises when they don't know enough to do that.
e.g. "My boss tells me that I need to convert my ASP.NET Membership application to SAML 2.0. I've googled SAML for a whole day and am hopelessly confused".
Now, the standard response on stackoverflow is to close this - too broad - not focused - not a programming question.
All of which is true and this question could also go on serverfault.
But that doesn't help the newbie.
My approach is to say something like:
"OK - you need a SAML stack on the client side. Here's a list of SAML clients, Find one that fits your requirements (language, cost etc.) and read the documentation and samples".
Then I ask what IDP they plan to use?
And depending on that, I may have some more suggestions or links to a good post.
The outcome is that the newbie has something concrete to go on.
(I leave the admin. to other people).
In fact, that's how this blog originally started.
I was answering the same question again and again and so I answered the question in the blog and then posted the link. Major time saving.
The other point is that I can't do their job for them. All I can do is point them in the right direction.
The comments section in stackoverflow is for further questions.
Enjoy!
Part of this is the treatment of newbies; in particular the arrogant treatment of people who genuinely need an answer but don't know how to ask the question.
Jon Skeet wrote an excellent post on how to ask a question.
The problem arises when they don't know enough to do that.
e.g. "My boss tells me that I need to convert my ASP.NET Membership application to SAML 2.0. I've googled SAML for a whole day and am hopelessly confused".
Now, the standard response on stackoverflow is to close this - too broad - not focused - not a programming question.
All of which is true and this question could also go on serverfault.
But that doesn't help the newbie.
My approach is to say something like:
"OK - you need a SAML stack on the client side. Here's a list of SAML clients, Find one that fits your requirements (language, cost etc.) and read the documentation and samples".
Then I ask what IDP they plan to use?
And depending on that, I may have some more suggestions or links to a good post.
The outcome is that the newbie has something concrete to go on.
(I leave the admin. to other people).
In fact, that's how this blog originally started.
I was answering the same question again and again and so I answered the question in the blog and then posted the link. Major time saving.
The other point is that I can't do their job for them. All I can do is point them in the right direction.
The comments section in stackoverflow is for further questions.
Enjoy!
Thursday, March 29, 2018
Certificates : Removing a certificate store folder
I created the wrong folder using makecert and you can't remove it using "mmc".
Then I found this post.
void Main()
{
int CERT_SYSTEM_STORE_LOCATION_SHIFT = 16;
uint CERT_SYSTEM_STORE_CURRENT_USER_ID = 1;
uint CERT_SYSTEM_STORE_LOCAL_MACHINE_ID = 2;
uint CERT_STORE_DELETE_FLAG = 0x10;
uint CERT_SYSTEM_STORE_CURRENT_USER = CERT_SYSTEM_STORE_CURRENT_USER_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT;
uint CERT_SYSTEM_STORE_LOCAL_MACHINE = CERT_SYSTEM_STORE_LOCAL_MACHINE_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT;
CertUnregisterSystemStore("makecert", CERT_STORE_DELETE_FLAG | CERT_SYSTEM_STORE_CURRENT_USER);
}
[DllImport("crypt32.dll", CharSet = CharSet.Unicode)]
public static extern bool CertUnregisterSystemStore(string systemStore, uint flags);
Also need to add:
using System.Runtime.InteropServices;
and run in LINQPad as a "C# program".
Works for "Current User" but doesn't seem to work for "Local Computer".
Enjoy!
Then I found this post.
void Main()
{
int CERT_SYSTEM_STORE_LOCATION_SHIFT = 16;
uint CERT_SYSTEM_STORE_CURRENT_USER_ID = 1;
uint CERT_SYSTEM_STORE_LOCAL_MACHINE_ID = 2;
uint CERT_STORE_DELETE_FLAG = 0x10;
uint CERT_SYSTEM_STORE_CURRENT_USER = CERT_SYSTEM_STORE_CURRENT_USER_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT;
uint CERT_SYSTEM_STORE_LOCAL_MACHINE = CERT_SYSTEM_STORE_LOCAL_MACHINE_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT;
CertUnregisterSystemStore("makecert", CERT_STORE_DELETE_FLAG | CERT_SYSTEM_STORE_CURRENT_USER);
}
[DllImport("crypt32.dll", CharSet = CharSet.Unicode)]
public static extern bool CertUnregisterSystemStore(string systemStore, uint flags);
Also need to add:
using System.Runtime.InteropServices;
and run in LINQPad as a "C# program".
Works for "Current User" but doesn't seem to work for "Local Computer".
Enjoy!
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
CONNECTED(000005DC)
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
i:/CN=my-adfs
-----BEGIN CERTIFICATE-----
MIIExD...vLMng0
-----END CERTIFICATE-----
---
Server certificate
subject=/CN=my-adfs
issuer=/CN=my-adfs
---
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
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES256-GCM-SHA384
Session-ID: 29140000...E4D79A337F1F0BBC9
Session-ID-ctx:
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)
---
read:errno=10054
Copy / paste this section:
-----BEGIN CERTIFICATE-----
MIIExD...vLMng0
-----END CERTIFICATE-----
into a file called e.g. adfs.cer
Then:
openssl x509 -in c:\xxx\adfs.cer -fingerprint -noout
SHA1 Fingerprint=24:F8:...:9A:21:2B:35
Enjoy!
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
CONNECTED(000005DC)
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
i:/CN=my-adfs
-----BEGIN CERTIFICATE-----
MIIExD...vLMng0
-----END CERTIFICATE-----
---
Server certificate
subject=/CN=my-adfs
issuer=/CN=my-adfs
---
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
SSL-Session:
Protocol : TLSv1.2
Cipher : ECDHE-RSA-AES256-GCM-SHA384
Session-ID: 29140000...E4D79A337F1F0BBC9
Session-ID-ctx:
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)
---
read:errno=10054
Copy / paste this section:
-----BEGIN CERTIFICATE-----
MIIExD...vLMng0
-----END CERTIFICATE-----
into a file called e.g. adfs.cer
Then:
openssl x509 -in c:\xxx\adfs.cer -fingerprint -noout
SHA1 Fingerprint=24:F8:...:9A:21:2B:35
Enjoy!
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:
[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String("base64encodedtext"))
so something like:
PS C:\> [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64Strin
g("PHNhbWxwO2...c2FtbHA6UmVzcG9uc2U+"))
Neat!
Enjoy!
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:
[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String("base64encodedtext"))
so something like:
PS C:\> [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64Strin
g("PHNhbWxwO2...c2FtbHA6UmVzcG9uc2U+"))
<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
is:names:tc:SAML:2.0:protocol">...</Assertion></samlp:Response>
Neat!
Enjoy!
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
/sAMAccountname"
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.
Enjoy!
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
/sAMAccountname"
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.
Enjoy!
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
Name : RP Name
IssueOAuthRefreshTokensTo : AllDevices
AlwaysRequireAuthentication : False
TokenLifetime : 960
Enjoy!
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
Name : RP Name
IssueOAuthRefreshTokensTo : AllDevices
AlwaysRequireAuthentication : False
TokenLifetime : 960
Enjoy!
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".
Enjoy!
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".
Enjoy!
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!
Enjoy!
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!
Enjoy!
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:\\
Then:
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
Enjoy!
Turns out you can with PowerShell.
Instead of \cd to a drive, you go to the certificate store with:
cd CERT:\\
Then:
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
Enjoy!
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.
Onwards.
Enjoy!
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.
Onwards.
Enjoy!
Subscribe to:
Posts (Atom)