Tuesday, June 02, 2015

ADFS : Authorisation code grant

This is continuing the series with Active Directory Federation Services / "AD FS" / ADFS with Windows Server 2016 (currently Technical Preview 2) and OAuth2.

Refer previous blog entry : ADFS : OpenID Connect.

As usual, we need a client. One of Thinktecture's products is Authorization Server.

(Note: AuthorizationServer is not really maintained anymore - read here for details).

I have all the code and I've played around with it previously so it made sense for me to use it. Also, there are some really nice clients which take you through the protocol step-by-step. (in samples/Flows/Clients).

So we are looking at the "Code Flow" sample.

Dominick always puts the constants in the Constants.cs class (part of the bigger project) so you need to change them as appropriate.

public static class AS
{
            public const string OAuth2TokenEndpoint = "https://adfs40.local/adfs/oauth2/token";
            public const string OAuth2AuthorizeEndpoint = "https://adfs40.local/adfs/oauth2/authorize";

            public const string IssuerName = "AS";
            public const string SigningKey = "1fTiS2clmPTUlNcpwYzd5i4AEFJ2DEsd8TcUsllmaKQ=";
}
 
 
Also notice the client_id:

public const string CodeClient = "codeclient";

Config the ADFS client as per:


Note the Client_id matches.

In CallbackController.cs:


public async Task<ActionResult> Postback()
{
            var client = new OAuth2Client(
                new Uri(Constants.AS.OAuth2TokenEndpoint),
                Constants.Clients.CodeClient,
                Constants.Clients.CodeClientSecret,
                OAuth2Client.ClientAuthenticationStyle.PostValues);

            var code = Request.QueryString["code"];

            Dictionary<string, string> dict = new Dictionary<string, string>();
            dict.Add("client_id", Constants.Clients.CodeClient);

            var response = await client.RequestAuthorizationCodeAsync(
                code,
                Constants.Clients.CodeClientRedirectUrl,
                dict);

            return View("Postback", response);
}

I've had to modify the code somewhat. The original code used BasicAuthentication in the ClientAuthenticationStyle. That doesn't work and throws the ADFS error:

MSIS9265: Received invalid Client credentials. Found 'client_secret' query parameter in the request but the Client 'codeclient' is not configured to authenticate using client secret post.

No idea what this means. There is no way via the wizard to configure the secret. Via PowerShell, we see:

PS C:\> Get-AdfsClient -Name "Code Flow Client"

RedirectUri                          : {https://localhost:44303/callback}
Name                                 : Code Flow Client
Description                          :
ClientId                             : codeclient
BuiltIn                              : False
Enabled                              : True
ClientType                           : Public
ADUserPrincipalName                  :
ClientSecret                         :
JWTSigningCertificateRevocationCheck : None
JWTSigningKeys                       : {}
JWKSUri                              :


Notice the ClientSecret as a parameter. The problem is that the Add and Set do not accept this as a paramaeter?

So I changed the Style to PostValues. What this means via The OAuth 2.0 Authorization Framework is that:

client_id
         REQUIRED, if the client is not authenticating with the
         authorization server as described in Section 3.2.1.

we need to add "client_id" as a parameter. Hence, the "additional "Directory dict" code.

No comments: