Showing posts with label ADFS. Show all posts
Showing posts with label ADFS. Show all posts

Thursday, December 06, 2018

ADFS : MSIS7042 - The same client browser session has made '6' requests

The full error message is:

Exception details: Microsoft.IdentityServer.Web.InvalidRequestException: MSIS7042: The same client browser session has made '6' requests in the last '7' seconds. Contact your administrator for details.

There are many causes for this; one being the "missing /" on the identifier.

I found one recently where I was running an ASP.NET MVC application inside VS that was authenticated via ADFS. This used the OWIN WS-Fed middleware.

I couldn't authenticate because of this error.

ADFS will only accept https connections so the RP was configured with a:

https://localhost/...

endpoint

But on VS, inside "Properties / Web", I noticed that the URL was:

 http://localhost/...

Setting this to https fixed the problem.

Go figure.

I found a similar solution here.

Enjoy!

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:




 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, 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!

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!

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

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!


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:

?SAMLRequest=fZ...gE%3d&RelayState=620d9067-4bc1-439b-ad21-0d419d3cbd19

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.

Enjoy!

Monday, November 20, 2017

ADFS : ADFS Help

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:

Get-ADFSEvents

and

Write-ADFSEventsSummary

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:

Get-AdfsSystemInformation

OSVersion                 : 10.0.14393.0
OSName                    : Microsoft Windows Server 2016 Datacenter
MachineDomain             : dev.local
IPAddress                 : 100.75.64.15
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,
                            ConfigurationChannelMaxMessageSizeInBytes}
SslBindings               : {System.Collections.Hashtable, 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;
                            MemoryPercentOfTotal=4.49916294642857},
                            @{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;
                            MemoryPercentOfTotal=2.66767229352679}...}
AdHealthAgentInformation  : AdHealthAgentInformation


Get-AdfsServerConfiguration

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

                                            [Issuer]
                                              CN=xxx

                                            [Serial Number]
                                              62...D7

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

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

                                            [Thumbprint]
                                              24...35
                                            ; CertificateType=Service-Communications; IsPrimary=True; StoreName=My;
                                            StoreLocation=LocalMachine;
                                            Thumbprint=24...35},
                                            @{Certificate=[Subject]
                                              CN=ADFS Encryption - xxx

                                            [Issuer]
                                              CN=ADFS Encryption - xxx

                                            [Serial Number]
                                              70...6B

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

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

                                            [Thumbprint]
                                              ED...13
                                            ; CertificateType=Token-Decrypting; IsPrimary=True; StoreName=My;
                                            StoreLocation=CurrentUser;
                                            Thumbprint=ED...13},
                                            @{Certificate=[Subject]
                                              CN=ADFS Signing - xxx

                                            [Issuer]
                                              CN=ADFS Signing - xxx

                                            [Serial Number]
                                              6B...00

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

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

                                            [Thumbprint]
                                              D1...F3
                                            ; CertificateType=Token-Signing; IsPrimary=True; StoreName=My;
                                            StoreLocation=CurrentUser;
                                            Thumbprint=D1...F3},
                                            @{Certificate=[Subject]
                                              CN=ADFS Encryption - xxx

                                            [Issuer]
                                              CN=ADFS Encryption - xxx

                                            [Serial Number]
                                              4C...95

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

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

                                            [Thumbprint]
                                              94...35
                                            ; CertificateType=Token-Decrypting; IsPrimary=False; StoreName=My;
                                            StoreLocation=CurrentUser;
                                            Thumbprint=94...35}...}
ADFSClaimDescription                      : {Microsoft.IdentityServer.Management.Resources.ClaimDescription,
                                            Microsoft.IdentityServer.Management.Resources.ClaimDescription,
                                            Microsoft.IdentityServer.Management.Resources.ClaimDescription,
                                            Microsoft.IdentityServer.Management.Resources.ClaimDescription...}
ADFSEndpoint                              : {Microsoft.IdentityServer.Management.Resources.Endpoint,
                                            Microsoft.IdentityServer.Management.Resources.Endpoint,
                                            Microsoft.IdentityServer.Management.Resources.Endpoint,
                                            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,
                                            Microsoft.IdentityServer.Management.Resources.AdfsClient,
                                            Microsoft.IdentityServer.Management.Resources.AdfsClient,
                                            Microsoft.IdentityServer.Management.Resources.AdfsClient...}
ADFSGlobalAuthenticationPolicy            : Microsoft.IdentityServer.Management.Resources.AdfsGlobalAuthenticationPolic
                                            y
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
                   Auditing'
Output           : {StsAuditConfig, MachineAuditPolicy}
ExceptionMessage :

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

Output           : {NtlmOnlySupportedClientAtProxy}
ExceptionMessage :


More examples here.

Enjoy!

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
aud:https://localhost:44326/
iss:https://some-adfs/adfs

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.

Enjoy!

Monday, November 06, 2017

ADFS : Application Groups

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

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

Examples:

Get-AdfsNativeClientApplication

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

Get-AdfsServerApplication

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

Get-AdfsWebApiApplication

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

Plus we have the legacy cmdlets from ADFS 3.0:

Get-AdfsClient

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

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

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

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

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

And remember you can get all the commands by:

get-command *adfsclient*

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

get-command *adfsnativeclient*

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

get-command *adfsserver*

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

get-command *adfswebapi*

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

get-command *adfsapplication*

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

Enjoy!

Wednesday, October 18, 2017

IdentityServer : WS-Fed metadata imported into ADFS

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

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

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

The metadata endpoint is:

http://localhost:5000/wsfederation

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

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

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

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

Looking at the metadata, this is indeed the case.

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

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

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

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


You can do this in the "Properties".

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

http://localhost:5000

with the https endpoint as above.

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

The new metadata imports without issues.

Enjoy!

Wednesday, October 11, 2017

ADFS : PowerShell cmdlet - parameter PolicyMetadata

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

This one was around PolicyMetadata.

Get-AdfsAccessControlPolicy -Name "Demo"

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


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

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

you get all kinds of errors.

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

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

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

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

which displays:

IsParameterized : False
Serialized      : <PolicyMetadata xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
                  xmlns="http://schemas.datacontract.org/2012/04/ADFS">
                    <RequireFreshAuthentication>false</RequireFreshAuthentication>
                    <IssuanceAuthorizationRules>
                      <Rule>
                        <Conditions>
                          <Condition i:type="AlwaysCondition">
                            <Operator>IsPresent</Operator>
                            <Values />
                          </Condition>
                        </Conditions>
                      </Rule>
                    </IssuanceAuthorizationRules>
                  </PolicyMetadata>
Summary         : RequireFreshAuthentication:False
                  IssuanceAuthorizationRules:
                  {
                    Permit everyone
                  }
ExtensionData   : System.Runtime.Serialization.ExtensionDataObject


Putting that into a file e.g.

<?xml version="1.0" encoding="UTF-8"?>
<PolicyMetadata xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://schemas.datacontract.org/2012/04/ADFS">
    <RequireFreshAuthentication>false</RequireFreshAuthentication>
        <IssuanceAuthorizationRules>
            <Rule>
                <Conditions>
                    <Condition i:type="AlwaysCondition">
                        <Operator>IsPresent</Operator>
                        <Values />
                    </Condition>
                </Conditions>
            </Rule>
        </IssuanceAuthorizationRules>
</PolicyMetadata>


and then running the command works!

I suggest running:

Get-AdfsAccessControlPolicy  

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

Enjoy!

Saturday, October 07, 2017

ADFS : PowerShell cmdlet - parameter is an array

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

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

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

Looking at another example:

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

the array is of the form:

@("Fabrikam","Active Directory")

Enjoy!

Monday, September 25, 2017

ADFS : Pre-populating the user on the login screen

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

Note this is with ADFS 4.0 (Server 2016).

The URL is:

GET https://my-adfs.cloudapp.net/adfs/ls/?login_hint=myuser%40dev.local
&wctx=Yue...BfN-A7v
&wtrealm=some_realm
&wa=wsignin1.0
...
etc

The ADFS login screen then looks like:


Enjoy!

Wednesday, September 13, 2017

ADFS : RP default token lifetime

This question keeps coming up.

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

As usual, a heap of garbage via Google.

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

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


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


So the correct answer is 1 hour = 60 minutes.

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

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

Enjoy!

Wednesday, August 30, 2017

Azure B2C : Custom policies with ADFS

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

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

So ADFS 4.0 was a good candidate for OIDC.

As per my SO question:

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

I have set up all the custom policies.

I am using OpenID Connect as the protocol.

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

The error I get in Application Insights is: 

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

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

Turns out:

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

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

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

Enjoy!