Q:

Using AWS Cognito and AD FS as authentication for a web app

We are currently building a web app using a full serverless stack on AWS. So far we have been very successful using AWS Lambda, AWS DynamoDB and Cognito User Pools. This application is intended to be an enterprise application and one of my clients wants to be able to log all users in using their current Active Directory credentials. I have used AD FS in the past on other applications but it has always turned out to be a bit of a hack to get it working.
Now, I want to send the customer instructions on how to configure their AD FS relying party trust to authenticate against my application.
I have read that the best way to do this is to create a Cognito Identity Provider that links to a Cognito User Pool. In the User Pool you should create a SAML provider and upload the metadata.xml from the AD FS server.
I have set up a lab server with AD FS and I can get that working. Now I am not sure what I am doing wrong in terms of the Relying Party Trust setup or the Cognito setup. I have been at this for ages and read just about every blog article I can find. If anyone can help me out or point me in the right direction that would be greatly appreciated.

A:

After much frustration, I can now answer this question so I decided to put together an easy step-by-step answer for beginners with these struggles.
I am only going into the authentication setup and not the authorisation. Authorisation requires IAM roles and some other logic that is architecture specific. I'm happy to discuss that elsewhere.
There are 2 components to this kind of a setup:

An AWS Cognito user pool with a federated identity provider
Windows Server with AD FS installed

Creating the Cognito User Pool domain
In the Cognito User Pool under General Settings, select App clients and add one if there are none (you will need the ID later).
Then go to Domain Name under App Integration and choose a valid domain prefix and save it.
Relying Party Trust in Windows AD FS
You will need to get the company to setup a relying party trust. The steps required are as follows:

Open the AD FS management console
Create a new relying party trust
Select to enter the details manually
Enter a name for the trust that is easily identifiable as your application
Select to use ADFS 2.0
In this example, there is no need for a certificate so just click next
Select the checkbox to enable the SAML 2.0 protocol and enter the URL in this format: https://<domain_prefix>.auth.<region>.amazoncognito.com/saml2/idpresponse (domain prefix is set in the previous step)
The relying party trust identifier needs to be urn:amazon:cognito:sp:<pool-id> where pool-id is the AWS Cognito User Pool id found in the General Settings of the user pool
Permit all users to authenticate (assuming that is your intention)

Now you need to add claims to the relying party trust.

Right-click on the relying party trust and click edit claims
Create a new claim that sends LDAP attributes
Give it a name (I normally use Profile but this is up to you)
Make the attribute store Active Directory
Fill in the table as you need. A requirement is that you have a Name ID being returned (I normally use the User-Principal-Name mapping to Name ID). The rest of the table is as you need. For example, Given-Name can map to FName

Federated Identities in AWS Cognito User pool
So as the application developer, you need to setup the Cognito User pool. Go through the wizard and choose your prefered settings. The federated identities don't necessarily play by the same rules as the user pool itself anyway.
The steps to setup the federated identity are:

In the Cognito user pool select Identity Providers under Federation
Click on SAML
Provide the metadata document endpoint (normally in the form of https://<fqdn>/FederationMetadata/2007-06/FederationMetadata.xml). If you can't then download that file and upload it by clicking "Select File"
Enter a provider name that makes sense to you but make sure not to put any spaces in the name
The identifiers are optional (see below for their use)
Checking enable IdP sign out flow will sign your users out of their federated identity as well as your application on sign out.
Click create provider

Attribute Mapping for Federated Identity

Create the field mappings for the Federated Identity by going to Attribute Mapping under Federation in the user pool.
Select SAML
Click Add SAML Attribute
Make sure Capture is checked, enter the SAML attrbites from above (such as FName) and select the user pool attribute that it maps to.

Setting up the App Client
The last step before testing is to setup the app client that you created earlier.

Go to App Client Settings under App Integration
Enter the settings for the appropriate app client
Select all the appropriate identity providers (specifically the one setup above)
You can set a comma-separated list of callback and logout URLs. The callback URLs should point to somewhere that will use the token after authentication (see testing below).
Select the OAuth 2.0 attributes as required but for testing select everything but Client credentials

Testing
To test, you can try a few different URLs in the form of: -

https://<domain_prefix>.auth.<region>.amazoncognito.com/authorize?idp_identifier=<idp_identifier>&response_type=token&client_id=<app_client_id>&redirect_uri=<app_client_callback_URL> to go directly to the authorize endpoint
https://<domain_prefix>.auth.<region>.amazoncognito.com/login?response_type=token&client_id=<app_client_id>&redirect_uri=<app_client_callback_URL> to go to the AWS hosted login UI

The idp_identifier is the optional field defined when creating the federated identity. This is not required in the URL either.
This one page webapp is a good tool to use to test that things are working and you are getting the desired response.
I hope this helps other people.

