After struggling with this requirement for more than a day, and reading too much information about the OAuth2 protocol, I finally was able to accomplish it, and thought it will save some time to document the process for future use.
So here are the required steps:
Create a new project with Visual Studio 2015
- Create a web application using one of the ASP.NET 5 templates. If you choose the “Web Application” template, set the authentication option to “No Authentication”.
- On the project properties -> Debug, set the “Enable SSL” checkbox and change the “App URL” to use the https protocol with the SSL port.
Configure the ADFS 3.0 server
- On your ADFS server, open the “AD FS Management” console.
- Select the “Relying Party Trusts” node and click “Add Relying Party Trust…”.
- Select “Enter data about the relying party manually” and click “Next”.
- Choose a display name for the trust party. (Usually the same name as your visual studio solution).
- Keep the default selection of “AD FS profile” and keep clicking “Next” until the “Configure Identifies” step.
- On the “Relying Party trust identifier” type your application URL (Ex. https://localhost:44356) and click “ADD”.
- Keep clicking “Next” until you finish the wizard.
- When you click on the “Close” button, the “Edit Claim Rule” wizard will open. There are many options there but a standard configuration will include sending the username, display name and some roles as claims. Click “Add Rule”, leave the default selected template as “Send LDAP Attributes as Claims” and click “Next”. On the “Configure Claim Rule” tab, configure the rule.
- Click Finish and close the wizard.
- Run PowerShell console as administrator and execute the following code. Replace the value of the “relyingParyName” and the “appUri” variables with the relevant values:[sourcecode language=”powershell”]
Import-Module ADFS
$relyingPartyName = “ADFSExample”
$appUri = “https://localhost:44356”$clientId = [guid]::NewGuid()
$redirectUri = “$appUri/oauth2”
Add-AdfsClient -Name $relyingPartyName -ClientId $clientId -RedirectUri $redirectUri
Write-Host “Client Id: $clientId`nClient Uri: $appUri`nCallback Path: /oauth2”
[/sourcecode] - Take a note of the output of the script as you will need it later in the process.
- Export the ADFS’s token-signing certificate by selecting “Service” in the “AD FS Management” -> Certificates. Select the “Token-signing” certificate and click “View Certificate…”. On the Details tab click “Copy to File …”, keep all the defaults and save the file. Copy the result file to the main folder of your application (the same folder that contains the “wwwroot” folder).
Configure the project to use ADFS
- Back in visual studio, extract the 2 attached files (link at the bottom) and include them in your project.
- You will need to add some reference packages to make the code compile. The easiest way to do it is to open the “OAuthAdfsAppBuilderExtensions.cs” file and use the quick action (Ctrl-dot) to add the references. The required packages are:
- “Microsoft.AspNet.Authentication.Cookies”: “1.0.0-rc1-final”
- “Microsoft.AspNet.Authentication.OAuth”: “1.0.0-rc1-final”
- “System.IdentityModel.Tokens.Jwt”: “5.0.0-rc1-211161024”
- Open the Startup.cs file.
- Add the following using statements:[sourcecode language=”csharp”]
using System.IO;
using C60.OAuthAdfs;
using Microsoft.Extensions.PlatformAbstractions;
[/sourcecode] - Locate the “Configure” Method and add another parameter to it: IApplicationEnvironment appEnv. (The DI will inject the value of this parameter automatically when this method is called).
- Add the following code at the beginning of the “Configure” method:[sourcecode language=”csharp”]
var oauthConfig = Configuration.GetSection(“OAuth”);
app.UseOAuthAdfsAuthentication(option =>
{
option.FederationServiceIdentifier = oauthConfig.Get<string>(“Issuer:FederationServiceIdentifier”);
option.AuthorizationEndpoint = oauthConfig.Get<string>(“Issuer:AuthorizationEndpoint”);
option.TokenEndpoint = oauthConfig.Get<string>(“Issuer:TokenEndpoint”);
option.TokenSigningCertificateFile = Path.Combine(appEnv.ApplicationBasePath, oauthConfig.Get<string>(“Issuer:TokenSigningCertificateFile”));
option.ClientUri = oauthConfig.Get<string>(“Client:Uri”);
option.ClientId = oauthConfig.Get<string>(“Client:ClientId”);
option.CallbackPath = oauthConfig.Get<string>(“Client:CallbackPath”);
option.UsernameClaimType = oauthConfig.Get<string>(“ClaimsType:Username”);
option.RoleClaimType = oauthConfig.Get<string>(“ClaimsType:Role”);
});
[/sourcecode]
- Add the following using statements:[sourcecode language=”csharp”]
- Open the “appsettings.json” file and add the “OAuth” section as follows:[sourcecode]
{
“Logging”: {
…
},
“OAuth”: {
“Issuer”: {
“FederationServiceIdentifier”: “http://adfs.dev.local/adfs/services/trust”,
“AuthorizationEndpoint”: “https://adfs.dev.local/adfs/oauth2/authorize”,
“TokenEndpoint”: “https://adfs.dev.local/adfs/oauth2/token”,
“TokenSigningCertificateFile”: “adfs.cer”
},
“Client”: {
“Uri”: “https://localhost:44356”,
“ClientId”: “dcd1c090-b7e0-42a7-af49-a18d6f3f944c”,
“CallbackPath”: “/oauth2”
},
“ClaimsType”: {
“Username”: “winaccountname”,
“Role”: “role”
}
}
}
[/sourcecode]You will need to replace the following configuration values:
- FederationServiceIdentifier – the identifier of the ADFS server. If you don’t know this value you can leave it, and the first time you will execute the application, the token validator will throw an exception with the expected value. (Setting this parameter to the expected value will eliminate the exception).
- AuthorizationEndpoint – The ADFS OAuth endpoint with the “/authorize” suffix.
- TokenEndpoint – The ADFS OAuth endpoint with the “/token” suffix.
- TokenSigningCertificateFile – The name of the certificate file that you export on step 12 of the previous section.
- Client section – Provide the values from the PowerShell output you executed on step 11 of the previous section.
- ClaimsType – Depends on the rule configuration you did on step 8 of the previous section. (if you leave the standard configuration you don’t need to change anything).
- Decorate with the [Authorize] attribute the controllers that required authentication. (you will need to add a using Microsoft.AspNet.Authorization; at the top of the file). Or you can add a policy (using the “AuthorizationPolicyBuilder”) that will be applied globally.
- Execute the application, and browse to a controller that requires authentication. You will be redirected to the ADFS server and after successfully authenticating you will be redirected back to the application.
I know that Windows 2016 is coming and will support OpenId Connect, which is supposed to be simpler to configure, but until then I would love to see Microsoft improving their support of this configuration and hopefully, it will be integrated into the Visual Studio’s “Create New Project” wizard like it was for MVC 5.