Using Active Directory Federation Services (ADFS) to provide authentication on local endpoints from a Windows client
ADFS setup
There are two parts to configuring ADFS.
Register a client application using ADFS
ADFS must be able to identify the application requesting user authentication, whether it be a service, a WPF application, a web client or an Office add-in. I went general and added the following client, which we can use for most of our C # requests; we may need to register a new client with a different callback for web clients.
Use one of the many tools to create a GUID for a client ID.
* CLIENT_ID and APP_NAME must be unique. * For the web client, the redirect URI is where the authorization service will redirect your call after user authentication. This should be the endpoint where you can process the token and continue working with your client application. The redirect URI is not really used with rich clients / services / add-ons.
CLIENT_ID = 26E54EC9-7988-4DAE-A527-483A8A78B1C6 APP_NAME = Investplus DESCRIPTION = Invest+ rich client suite REDIRECT_URI = https://server/redirect-adfs.html
Instructions for registering customers
(maybe this is possible in the wizard, but this is what I found on the Internet and it worked for us)
Register the resource you want to access (says the "Hear Party" in ADFS)
I found this link useful, it will walk you through the steps of the wizard to set up the relying party.
Instructions for registering a batch
The administrator in the server command will need to use the ADFS Wizard for adding trust of trusted parties , and in the "Select a data source" section, select "Enter details about the relying party manually."
The values required for this wizard are:
DISPLAY_NAME = "MyInvestApi" (Unique display name for this Relying party) PROFILE = "AD FS Profile" ENABLE_SUPPORT_FOR_WS-FEDERATION_PASSIVE_PROTOCOL = true URL = "https://server/api" (Unique URL for this RP) ADD_ONE_OR_MORE_IDENTIFIERS = eg. "urn:myInvestApi" and "https://server/api" ACCEPT_REMAINING_DEFAULTS
When given the opportunity, Add a claim rule :
SEND_LDAP_ATTRIBUTES_AS_CLAIMS = true ATTRIBUTE_STORE = Active Directory SELECT_USEFUL_ATTRIBUTES = User-Principal-Name; Email; Display-Name
Setting up / coding a client application
Microsoft provides Active Directory Authentication Libraries (ADAL) for a range of platforms and languages from C # to Javascript and from iOS to Cordova to Node.
The discovered API has changed significantly in each major version: I use the latest C # library, currently 3.13.5.
The library makes coding very simple, just a few lines; where i had problems:
- I could not find an explanation of which URL to use for ADFS Secure Token Service (STS)
- I could not find the documentation for the whole process, as I do here (most of the documentation is focused on Azure FS), I struggled to work out how the values provided for ADFS for the client and the mapping of supporters to the values used in the code are displayed.
What is the endpoint / adfs URL to use in code?
Microsoft's best practice is to name the URL of your ADFS / STS server at https://sts.domain.com (some use https://adfs.domain.com and ask your server administrators). However, if you try to remove this from the browser, you will get 404 - Not found and try to get the token in the code, the ADAL library reports:
The browser based authentication dialog failed to complete. Reason: The server has not found anything matching the requested URI (Uniform Resource Identifier).
This is how I found the endpoint:
- ADFS publishes federation metadata at https://sts.domain.com/federationmetadata/2007-06/federationmetadata.xml '
- Extract this file and open it in a text editor.
- When setting up the Relying Party, we specified "Enable WS-Federation Passive Protocol Support" when specifying the resource endpoint, so do an XML search for the
PassiveRequestorEndpoint . - Use the
<Address> from this node - in my case https://sts.domain.com/adfs/ls/ . I do not know if this will always be a value, or if it is indicated when ADFS is configured and therefore potentially different for each site.
What other values to use in the code?
We want our client application to receive the JTON JSON token from ADFS, which we can pass to our secure resource for authentication / authorization purposes.
In the simplest case, the access token can be retrieved in 3 lines of code + configuration, and this will show how to translate what we configured in ADFS to the values needed by ADAL:
var stsEndpoint = "https://sts.domain.com/adfs/ls/"; var relyingPartyIdentifier = "urn:myInvestApi"; // Tenant in Azure AD speak, but this is an on-premise service var authority = stsEndpoint + relyingPartyIdentifier; var restResourceUrl = "https://server/api"; var redirectUri = "https://server/redirect-adfs.html"; const string CLIENT_ID = "26E54EC9-7988-4DAE-A527-483A8A78B1C6"; AuthenticationContext authenticationContext = new AuthenticationContext(authority, false); var asyncRequest = authenticationContext.AcquireTokenAsync(restResourceUrl, CLIENT_ID, redirectUri, new PlatformParameters(PromptBehavior.Auto)); var accessToken = asyncRequest.Result.AccessToken;
useful links