Thursday, December 22, 2016

AAD : The V2.0 endpoints

I've been helping a few people lately with this and I see the same few issues that continually trip people up.

Table to help decide whether to use the v2.0 endpoints or not.

And note that currently the "Resource owner password credentials" grant is not supported.

Have a look at the current restrictions.

The endpoints are different:

https://login.microsoftonline.com/common/oauth2/v2.0/authorize
https://login.microsoftonline.com/common/oauth2/v2.0/token

The scopes are different. They now take the form of a URI e.g.

"scope": "https://outlook.office.com/mail.read https://outlook.office.com/mail.send"

You can use the default scope e.g.

https://graph.microsoft.com/.default

This means that the application uses the pre-defined scope.

You need to use the Application Registration Portal to register the application. Don't use the usual Azure AD Applications screens.

You need to cater for the admin. consent endpoint if you want to grant consent for the application to anyone who can authenticate.

Use the MSAL library rather than the ADAL library.

Enjoy!

Wednesday, December 21, 2016

Swagger : Using Swagger for Implicit Grant on Azure AD

Review my previous post - Swagger : Using Swagger for Implicit Grant on ADFS 4.0.

This builds on that.

Given that I couldn't get it working on ADFS, I thought I would try Azure AD (AAD).

One of the problems with AAD is that the web API calls are protected so if you want to use Swagger, authentication always fails.

I started with the OpenID Connect - web app. with web API sample. Follow the details to configure the web app. and the web API in AAD.

I'm running this on my PC.

This is a standard "adding items to a ToDo list" project.

Then I added swashbuckle etc. as per my post above.

As always, the gist is here.

Note that AAD needs the "resource" parameter, hence the extra line:

additionalQueryStringParams: new Dictionary() { { "resource", "https://azure-tenant.onmicrosoft.com/TodoListService" } }

Also, you do not need the clientSecret for implicit flow. This is because implicit flow is normally used for SPA and the secret key could be easily exposed in the JavaScript.

Looking at the ToDoListController:

if (ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/scope").Value != "user_impersonation")
            {
                throw new HttpResponseException(new HttpResponseMessage { StatusCode = HttpStatusCode.Unauthorized, ReasonPhrase = "The Scope claim does not contain 'user_impersonation' or scope claim not found" });
            }

            if (null != todo && !string.IsNullOrWhiteSpace(todo.Title))
            {
                todoBag.Add(new TodoItem { Title = todo.Title, Owner = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value });
            }

So we need a scope of  "user_impersonation" and we need a NameID claim.

We get the OAuth endpoints from the "View Endpoints" button in AAD. (Using the classic portal).


We need to add Swagger as an Azure AD application - the normal web site flow.

Ensure there is  "Reply URL" for:

  https://my pc/TodoListService/swagger/ui/o2c-html

We have to give this application permission to access the ToDoListService:


So what we are going to do is to use the same web API back-end but use Swagger as the web app.

Since there is a common back end, the ToDo list should reflect across both.

From the project, we add item "1234".


Now we try with Swagger.


and we get the 401.

So we click the red exclamation mark and we see:


Click "Authorize" and then authenticate with AAD.

Problem: we need to explicitly enable implicit flow. You do this via the manifest and then update:

"oauth2AllowImplicitFlow": true,

Now if we break-point at the NameID code and then check which attribute this matches in the token, we''ll see it matches the "sub":

...
"scp": "user_impersonation",
"sub": "nYa...Zow",
...

The OWIN classes must do this mapping internally viz. "sub" --> "NameID".


Now that we have authenticated, let's try again.


and we see that we get back the "1234" that we created with the web app.

Now we add a new item using the POST.

The object requires a "Title" and an "Owner" so we need to build one that looks like:

{
    "Title": "5678",
    "Owner": "nYa...Zow"
}

That returns OK and when we do another GET, we see:

[
  {
    "Title": "5678",
    "Owner": "nYa...Zow"
  },
  {
    "Title": "1234",
    "Owner": "nYa...Zow"
  }
]
 

Now go back to our web app.

so it all lines up.


Enjoy!



Monday, December 12, 2016

Swagger : Using Swagger for Implicit Grant on ADFS 4.0

This is based on this post.

I like Swagger. It maps your REST API and documents them and then allows you to test them from the documentation. Very neat.

You can write the code first and then Swagger reflects the API - much like the default API page in an MVC project or you can use the Swagger UI link to write the contract first and then generate.

Very much along the lines of code first vs. contract first.

(Aside: Once upon a time, I used SOAP and wsdl's and the WSCF (Web Services Contract First) project from thinktecture that does much the same thing. That article is dated from 2006! The more things change ...)

ADFS 4.0 (Server 2016) opens up the OpenID Connect / OAuth stack with full support for all four grant types (refer previous blog entries for a number of examples of this).

So it was a no brainer to try and put the two together.

I used this as a start point and that post gives a good overview of Swagger and how to integrate into a .NET MVC project with NuGet Swashbuckle.

The problem of course is that you need to authenticate the web API and the only OAuth type support in Swagger as I write is the implicit flow.

So following the article, as usual the gist is here.

You will notice that there is a scope called "sampleui". It's simple to add this to the Scopes section in the ADFS wizard.

So we run up the project in VS 2015 and then navigate to:

https://localhost:44326/swagger

(or whatever port your web API project uses).


Notice the highlighted exclamation mark in red.

Click that.


Check the boxes, click "Authorize".

It should take you off to the ADFS login page where you authenticate.


 Notice the exclamation mark is now blue (and if you click it you can Logout).

Now we put a value e.g. 5 in the "id" box and click "Try it out".

And it returns:

{
  "Message": "Authorization has been denied for this request."
}

I've tried everything I can think of  but I can't get this to work.

The JWT returned is:

{
  "aud": "microsoft:identityserver:7b23c943-6782-4d5b-b56c-7ecd59da17f2",
  "iss": "http://my-adfs/adfs/services/trust",
  "iat": 1480889151,
  "exp": 1480892751,
  "apptype": "Public",
  "appid": "7b2...7f2",
  "authmethod": "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport",
  "auth_time": "2016-12-04T22:05:50.803Z",
  "ver": "1.0",
  "scp": "sampleapi user_impersonation"
}

and when I access the API normally from a client in the VS project, I get the JWT:

{
  "aud": "https://localhost:44326/NativeTodoListService1",
  "iss": "http://my-adfs/adfs/services/trust",
  "iat": 1480889366,
  "exp": 1480892966,
  "apptype": "Confidential",
  "appid": "0cc...549",
  "authmethod": "http://schemas.microsoft.com/ws/2008/06/identity/authenticationmethod/password",
  "auth_time": "2016-12-04T22:09:26.486Z",
  "ver": "1.0"
}

I suspect the problem is that the "aud" is wrong. But I can't figure out how to get rid of the "microsoft:identityserver" one?

So close :-(

Any bright ideas?

Enjoy!

Monday, November 28, 2016

Postman : Using Postman for Implicit Grant on ADFS 4.0

This is ADFS 4.0 (Server 2016) and you need the official release.

I tried to get this working on the TPx series but no joy.

I kept getting the error:

"MSIS9358: Received invalid OAuth authorization request. The authorization server does not support the response type 'token' for confidential clients."

However, there is an extra entry in the official release which seems to to the job.


When you select this entry, you first get to configure a "Native Application" that generates a ClientID and you need to provide a "Redirect URI" and then an "Access Policy".

You end up with something like:


and you can configure the web application with claims etc.

The "Native Application" seems a bit weird but refer Customizing Id_Token Claims with OpenId Connect in AD FS 2016.

"Behind the scenes, this template creates a native client and new app type called Web application, which is just a Web API with an Identifier (RPID) that matches the native client's client ID. This means the Web application is simultaneously client and resource, so you can assign issuance transform rules as you would with a Web API."

As always, the gist is here.

You need to run this in a browser, The implicit flow returns an access token straight away. You miss out the intermediate step of getting a code and then using that for an access token. It's normally used for SPA where JavaScript is involved. Hence no security key is required as that would be easy to access.

If you look at the access token with e.g. jwt.io, you see:


Notice the "apptype" is "Public" and this is what is required for this flow. Hence the error about "confidential clients".

Enjoy!

Wednesday, November 23, 2016

ADFS : Metadata on ADFS 4.0

This is on Server 2016.

I've had a number of questions around compatibility e.g. can ADFS 3.0 federate with ADFS 4.0?

The servers are very different e.g. 2016 has containers, full OpenID Connect / OAuth support etc.  but the SAML level on both is still 2.0 so there should be no issues.

As an exercise, I checked the ADFS metadata on both.

Other than the expected differences e.g. federation service name, certificates, ID's etc. there is no difference which bears out the fact that they are compatible.

Enjoy!

Friday, November 11, 2016

Postman : Using Postman for Resource Owner Password Grant on ADFS

This is on Server 2016 TP5 - ADFS 4.0

Couldn't find any examples of this so rolled my own.

As always, the gist is here,

Note that you need the user in the "domain\user" format.

Be careful of this flow  - you are potentially exposing the user name and password.

This is supposed to be for "trusted" clients.

Enjoy!

Postman : OpenID Connect / OAuth errors

This is on ADFS 4.0 on Server 2016 TP5.

Yes, I know the official release is out but I've had other priorities :-)

So some of this may not apply to the official release.

This is based on the Postman collection described here.

While I was trying to get this to work, I encountered a number of errors and quickly established that there is basically zero documentation on any of them.

So I documented as I went along.

There is a authorisation request. This is an https request with a number of parameters and I removed them manually one by one.

Remove client id

MSIS9220: Received invalid OAuth authorization request. The 'client_id' parameter is missing or found empty. The client could not be validated.

Remove "response_type=code"

MSIS7065: There are no registered protocol handlers on path /adfs/oauth2/authorize to process the incoming request.

Remove "redirect_uri=https%3A%2F%2Fmy-pc%2FTodoListWebApp%2F"

MSIS9221: Received invalid OAuth authorization request. The 'redirect_uri' parameter is missing or found empty. Public clients must send the redirect_uri parameter with valid redirect URI in the OAuth authorization request.

This is followed by a REST token request.

This is driven by Postman and one of the nice features of Postman is there is a tick box next to each parameter and if you untick the box, that parameter is not sent.

Remove client_id

MSIS9629: Received invalid Client credentials.'client_secret' was present but 'client_id' parameter is missing or found empty.

Remove code

MSIS9610: The 'code' parameter is not specified. The access token request must contain the 'code' parameter which specifies the previously issued authorization code."

Remove "grant type"

MSIS7065: There are no registered protocol handlers on path /adfs/oauth2/token to process the incoming request.

Remove "client_secret"

MSIS9267: No Client credentials found in the request. Client 'a07...e75' is configured as a confidential client.

Remove "redirect_uri"

MSIS9221: Received invalid OAuth authorization request. The 'redirect_uri' parameter is missing or found empty. Public clients must send the redirect_uri parameter with valid redirect URI in the OAuth authorization request.

MSIS9608: The 'redirect_uri' parameter is not specified. The access token request must contain 'redirect_uri' parameter for public clients

Note there are two slightly different errors here. I noticed this in some other scenarios as well.

The first error is from the ADFS event log i.e. the server side (which is where most of the errors were copied from).

The second is what Postman actually reports i.e. the client side.

I have no idea why they are different?

Enjoy!



Wednesday, November 09, 2016

AAD : Advanced user lifecycle management

Done so much ADFS stuff lately, it's cool to look at Azure AD for a change!

Good overview

So to provision users into Azure AD as per above:

"Azure AD provides automated, advanced user life-cycle management by using dynamic group membership rules and application management capabilities. Here’s more detail:
  • For organisations with on-premises HR, Microsoft Identity Manager establishes user identities in Windows Server Active Directory.
  • For organisations with software as a service (SaaS)–delivered HR, Azure AD currently integrates with Workday.
  • Azure AD Connect syncs users and groups between Windows Server Active Directory and Azure AD.
  • Azure AD provides group-based automated licensing for Office 365 and other Microsoft on line services."
Or you could use the Graph API.

Or manually via the portal.

Or via B2B.

What is really needed as well is a browser-based provisioning service into Azure AD that does not require the use of the Azure portal, admin rights. etc.

Extra brownie points for adding delegated admin. as well :-)

Enjoy!

 

Postman : Authorisation Code Grant on Server 2016 - ADFS 4.0

I previously blogged on ADFS - Web App and Web API on Server 2016 TP4 ADFS 4.0.

This also shows the ADFS configuration

This is using Authorisation Code Grant in a .NET C# program to call the default template API i.e.

/api/values

Then I was asked how to do this with Postman which turned out to be less trivial than I thought.

As always, the Postman gist is here.

There is an authorisation request, a token request and the API request.

The VS project (as above) runs on my PC and has the web site and web service.

Running the authorisation request from a browser redirects to ADFS to authenticate and then returns a code in the query string..

As in "/?code=NjX0...".

We paste the code into the body of the second request (the code parameter) and then send it. This returns an access token, a refresh token and an ID token.

The Postman script automatically posts the access token into the third request (the API call) and this returns:

[
  "value1",
  "value2"
]

as we would expect.

The access token and the id token are encoded and can be decoded with something like jwt.io.

The refresh token is just a long GUID.

This results in:

Access token:

{
  "aud": "https://my-pc/TodoListService/",
  "iss": "http://my-adfs/adfs/services/trust",
  "iat": 1478562128,
  "exp": 1478565728,
  "apptype": "Confidential",
  "appid": "a07...e75",
  "authmethod": "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport",
  "auth_time": "2016-11-07T22:50:31.925Z",
  "ver": "1.0",
  "scp": "openid user_impersonation"
}

ID token:

{
  "aud": "a07...e75",
  "iss": "https://my-adfs/adfs",
  "iat": 1478562128,
  "exp": 1478565728,
  "auth_time": 1478559031,
  "sub": "v2O...nA=",
  "upn": "user1@dev.local",
  "unique_name": "DEV\\user1"

The ADFS wizard allows you to add claims to the web API part.

So I added the usual LDAP rules for email, given name and surname.

After this change, this resulted in a new access token.

{
  "aud": "https://my-pc/TodoListService/",
  "iss": "http://my-adfs/adfs/services/trust",
  "iat": 1478562556,
  "exp": 1478566156,
  "email": "user1@company.com",
  "given_name": "User",
  "family_name": "One",

  "apptype": "Confidential",
  "appid": "a07...e75",
  "authmethod": "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport",
  "auth_time": "2016-11-07T23:49:15.935Z",
  "ver": "1.0",
  "scp": "openid user_impersonation"
}

Enjoy!

Tuesday, November 01, 2016

Visual Studio : VS 2015 Enterprise takes ages to start up

And it gets slower and slower.

Then I found Slow Visual Studio Performance … Solved!.

Essentially "Delete everything in C:\Users\\AppData\Local\Microsoft\WebSiteCache".

As you load up your projects, the first time they will run slower as it rebuilds the cache but it seems to be a good idea to clear this cache out once in a while.

Use at your own risk but wow - what a difference in start-up!

Enjoy!

Tuesday, September 13, 2016

AD : Attempt to compromise security (HRESULT: 0x800704F1)

The full error is:

System.DirectoryServices.AccountManagement.PrincipalOperationException: The system detected a possible attempt to compromise security. Please ensure that you can contact the server that authenticated you. (Exception from HRESULT: 0x800704F1) ---> System.Runtime.InteropServices.COMException: The system detected a possible attempt to compromise security. Please ensure that you can contact the server that authenticated you. (Exception from HRESULT: 0x800704F1)

This is described here:

MS16-101: Description of the security update for Windows authentication methods

Essentially, the updates disable the ability of the Negotiate process to fall back to NTLM when Kerberos authentication fails for password change operation.

I found these useful:

Enabling Secure LDAP on Windows Server 2008/2012 Domain Controllers
Enabling Secure LDAP on Windows Server 2008/2012 Domain Controllers: Configuration

There is a good write-up here:

Solution for Problem in Change Password after Windows Security Update 

TL;DR
  • Enable LDAPS
  • Set "Trusted Hosts"
  • Revert the update
Only the former was an option for me.

And so began a journey into the depths of the Internet - or more specifically the huge amount of garbage, rubbish and misinformation out there :-(

One of the problems was the connection string.

I naively assumed that I simply needed to change:

LDAP://fqdn       to
LDAPS://fqdn

But from what I can see, there is no actual protocol called LDAPS? It's official name is "Secure LDAP" and the connection string you need is:

LDAP://fqdn:636

The "correct" way to enable it is to install an Enterprise Root CA on a Domain Controller.

That wasn't an option (and a massive overkill) so I started wondering about installing a self-signed certificate on the DC.

Disclaimer: Using self-signed certificates or installing certificates as follows may not be the best solution security wise. Use this at your own risk!

The certificate that you need has to follow certain rules e.g.
  • It has to be for "Server Authentication" (OID: 1.3.6.1.5.5.7.3.1)
  • The Subject name must match the Fully Qualified Domain Name (FQDN) of the host machine, such as Subject:CN=server.domain.com
  • (This is also true for the first name in the Subject Alternative Name (SAN))
  • The host machine account needs to have access to the private key
In other words, much the same as an IIS SSL certificate.

Once you have the .pfx file, and using "mmc" with:

Service Account / Local Computer

Select "Active Directory Domain Services".


and import.

You need this certificate in "NTDS\Personal" and  "NTDS\Trusted Root Certification Authorities".

To check this, you need to run "ldp" from the command line.


This should result in:

"Host supports SSL, SSL cipher strength = 256 bits"

If you need to run "ldp" from a non-DC machine, you need Remote Server Administration Tools (RSAT) for Windows Client and Windows Server.

Once "ldp" runs OK, you now have secure LDAP.

Now for the C# .NET side:

Replace the ldapConnection below:

DirectoryEntry ldapConnection = null;

try
{     
      ldapConnection = new DirectoryEntry(LDAP fqdn, user, password);               
}
with:
ldapConnection = new DirectoryEntry(LDAP fqdn, user, password, 
    Password,AuthenticationTypes.SecureSocketsLayer); 
Coming at this from another angle, this code also worked:

Authenticating a user over LDAP in .Net: LdapConnection vs. PrincipalContext

Footnote: I also found that I could leave out the extra parameter:

"Password,AuthenticationTypes.SecureSocketsLayer"

if the user was "domain\user" rather than "user". Go figure!

Enjoy!

Monday, September 12, 2016

OAuth2 : Verifying the ADFS JWT signature

I wrote up this post recently: OAuth2 : Verifying the Azure AD JWT signature.

So how do you do this with ADFS? You need ADFS 4.0 - Server 2016.

This has the following ADFS OAuth information ( ~ metadata) endpoints:



If we go to the "keys" endpoint, we see:

{
  "keys": [
    {
      "kty": "RSA",
      "use": "sig",
      "alg": "RS256",
      "kid": "hHk-...A6k",
      "x5t": "hHk-...A6k",
      "n": "tGy...w9Q",
      "e": "AQAB",
      "x5c": [
        "MIIC7..Log=="
      ]
    }
  ]
}

The information under "x5c" is the certificate that you need.

As  per the linked post, you need to wrap this with "---BEGIN--- ---END---" and copy / paste and you'll see that the signing key is now verified.

Enjoy!



Monday, September 05, 2016

B2C : The Process ID cannot be found for .NET Core exe

The .NET Core B2C sample is here.

I was helping to get it working on another Windows 10 box with VS 2015 when we got the error:

"The Process ID cannot be found for .NET Core exe".

Works fine on my Windows 8.1 box.

If we run .NET Core from the command line and then ran the project, it loaded but then localhost refused the connection.

So Mr. Google to the rescue and the vast majority of the suggestions were along the lines of:

"For me the problem was solved by closing down Visual Studio, deleting project.lock.json
and starting Visual Studio again"

That didn't help and neither did a whole lot of others.

Then I came across a reference along the lines of localhost certificates that aren't trusted for SSL.

And some bells started ringing because I hate IIS Express and don't use it but the Windows 10 machine did not have IIS installed so was running IIS Express by default.

(I always battle with IIS Express and SSL).

And the B2C sample uses https://localhost.

You need to trust the IIS Express self-signed certificate as per this post.

That fixed the problem.

How a trusted certificate issue caused an error message regarding a process ID is another issue entirely :-)

Enjoy!


Friday, September 02, 2016

Postman : Using Postman for Confidential Grant on ADFS

Continuing the series for ADFS 4.0 on Server 2016.

The confidential flow relies on a client_id and a secret_key to authenticate the user.

The gist for the Postman collection is here.

You need to update your ADFS FQDN and the client_id and secret_key.

ADFS returns:

{
  "access_token": "eyJ...ErQ",
  "token_type": "bearer",
  "expires_in": 3600,
  "scope": "openid"
}

You can plug the access token into a JWT viewer.

Enjoy!

Wednesday, August 31, 2016

Misc : Microsoft Open Specifications

Microsoft publishes a list of open specifications that enable inter-operability over here.

These include a number of specifications that describe ADFS and WAP (Web Application Proxy).

These include:
The MS-ADFSPIP document describes the interface between ADFS and WAP.

There are tons of questions on the forum around "Do I have to use WAP as the proxy. Can I use any reverse proxy or a load balancer or F5 or Netscaler etc. ?"

You can as long as the proxy you want to use implements the standards.

Good luck with getting your vendor to confirm that they do and to demonstrate this fact.

In addition, your vendor may also need to comply with the rules around

[MS-OFBA]: Office Forms Based Authentication Protocol

if e.g. the request is 
  • from a Microsoft Office application that relies on the Office Forms Based Authentication (OFBA) Protocol
  • from non-Microsoft-Office clients accessing services that implement the OFBA protocol [MS-OFBA] that rely on ADFS for authentication
It also needs to ensure that the correct claims are set e.g.

http://schemas.microsoft.com/ws/2012/01/insidecorporatenetwork

which is "True" is accessing ADFS directly or "False" if accessing via WAP.

My advice : Just use the WAP - much less stressful - :-).

Enjoy! 

Postman : Azure AD and Implicit Flow

I've been playing around with this and thought it would be worthwhile to document  the journey.

I have a web application in Azure AD and this application calls a web API.

The web application has permission to call the web API.

I want to use the implicit grant.

This is not supported OOTB :

AADSTS70005: response_type 'token' is not supported for the application

You need to update the manifest as per ADAL JS - response_type=“token” is not supported.

After sorting that out, my first call was:

https://login.microsoftonline.com/[tenant id]/oauth2/authorize?client_id=[client id]&response_type=token&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F

This resulted in:

http://localhost/myapp/#error=invalid_resource&error_description=AADSTS50001%3a+Resource+identifier+is+not+provided...

OK - so I need a "resource" parameter - let's make it the same as the response type.

https://login.microsoftonline.com/[tenant id]/oauth2/authorize?client_id=[client id]&response_type=token&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F&resource=http%3A%2F%2Flocalhost%2Fmyapp%2F 

This resulted in:

http://localhost/myapp/#error=invalid_resource&error_description=AADSTS50001%3a+The+application+named+http%3a%2f%2flocalhost%2fmyapp%2f+was+not+found+in+the+tenant+named+[tenant id]/++This+can+happen+if+the+application+has+not+been+installed+by+the+administrator+of+the
+tenant+or+consented+to+by+any+user+in+the+tenant.
++You+might+have+sent+your+authentication+request+to+the+wrong+tenant....

So maybe I need the "APP ID URI" of the web application?

https://login.microsoftonline.com/[tenant id]/oauth2/authorize?client_id=[client id]&response_type=token&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F&resource=https://www.getpostman.com/oauth2/callback

This resulted in:

http://localhost/myapp/#error=invalid_request&error_description=AADSTS90027%3a+The+client+%[client id]%27+and+resource+%27https%3a%2f%2fwww.getpostman.com%2foauth2%2fcallback%27+identify+the+same+application...

Aha - so maybe I need the "APP ID URI" of the web API?

https://login.microsoftonline.com/[tenant id]/oauth2/authorize?client_id=[client id]&response_type=token&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F&resource=https://xxx.onmicrosoft.com/xxxService 

This resulted in:

http://localhost/myapp/#access_token=eyJ...Cpw&token_type=Bearer&expires_in=3599&session_state=6e7...203 

Bingo!

I've obviously over-egged this a bit but you can see how you can work through the issues and figure out what's wrong based on the error messages.

The errors you get back from Azure AD  are an order of magnitude better than they used to be :-)

Note that the implicit grant does not return a refresh token because the browser has no means of keeping it private.

Enjoy!

Friday, August 26, 2016

Misc : Creating self-signed certificates

I normally recommend SelfSSL7 but I was looking at Let's Encrypt which generates free CA SSL certificates.

This is in the context of Windows, specifically IIS SSL or securing ADFS.

To do this you need a client and one of the browser clients on the list was ZeroSSL.

If you click the Tools button, you'll see a "Self-Signed Certificate Generator".


There's a private key and a certificate.

Save the two files somewhere. If you save the certificate as a .cer file, you can double click on it and get the certificate wizard. You'll note that it has no private key which makes it useless for SSL. The certificate is valid for a year.

Now use OpenSSL to run:

openssl pkcs12 -export -out c:\xxx\adfs.pfx -inkey c:\xxx\zerossl.prv -in c:\xxx\zerossl.cer
Loading 'screen' into random state - done
Enter Export Password:
Verifying - Enter Export Password:

You'll need to pick a password.

Now if you double click on the .pfx file, the Import wizard will guide you as to installing it into the certificate store. You'll need to type in the password.

If you look at the "Enhanced Key Usage", you'll see it covers a lot of cases which is cool.


Enjoy!

Postman : Using cURL to send OpenID Connect / OAuth to Azure AD / ADFS

"cURL is a computer software project providing a library and command-line tool for transferring data using various protocols".

I discovered that Postman allows you to generate these commands.

There are Postman collections for Azure AD / ADFS in gists as per Postman : Using Postman to get "Userinfo" on ADFS and the link inside the post.

So if you load the collection into Postman, click on "Generate Code" (top right) and then in the dropdown, select "cURL".

e.g.

curl -k -X POST -H "Content-Type: application/x-
www-form-urlencoded" -H "Cache-Control: no-cache" -H "Postman-Token: 0303470d-5a
3b-bdea-9da3-9ab3e12f66ce" -d "client_id=37f...0b0e&scope=openid&redirect_uri=https://localhost:1234&grant_type=authorization_code&client_secret=Rel...G9&code=Nj...WWg" "https://my adfs/adfs/oauth2/token"


{"access_token":"eyJ...GFQ",

"token_type":"bearer","expires_in":3600,
"resource":"urn:microsoft:userinfo","
refresh_token":"TT9...u21w",
"refresh_token_expires_in":25768,
"scope":"openid","id_token":"eyJ...Ywg"}


If you use self-signed certificates you need to use the "-k" option.

Enjoy!

Thursday, August 25, 2016

Postman : Using Postman to get "Userinfo" on ADFS

This follows on from Postman : Using Postman to get "Userinfo" on Azure AD.

There's a ton of stuff on Azure AD but very little on ADFS.

The gist is here.

Same instructions as the Azure AD article.

In terms of configuring ADFS, have a look at ADFS - Web App and Web API on Server 2016 TP4 ADFS 4.0 . You only need to do the Web App. part.

Enjoy!

Wednesday, August 24, 2016

Postman : Using Postman to get "Userinfo" on Azure AD

I got this idea from v2.0 Protocols - OAuth 2.0 Authorization Code Flow that has "Run in Postman" buttons that load Postman collections.

So I made my own which you can find in this gist.

This uses OpenID Connect / OAuth 2.0.

It has three steps.

The first you have to customise for your clientID etc. and then run in a browser.

Then copy / paste the code from the reply into the second, customise for your clientID etc. and click "Run".

This returns an access token, an ID token and a refresh token.

(You can see what's in them by copy / paste the access / ID token into jwt.io).

The code inside the collection automatically sets up the token for the third step so all you have to do is press "Run".

You will see the full "Userinfo".

There are full instructions in the collection.

Enjoy!

Thursday, August 18, 2016

OAuth2 - Testing OpenID Connect / OAuth 2.0

Utilities to help you develop using OpenID Connect and OAuth 2.0 are always useful so I've listed out the ones I know about.

Postman - Really useful to for API testing. Requires Chrome.

v2.0 Protocols - OAuth 2.0 Authorization Code Flow - Article that has links to Postman collection to try this out step by step. Azure AD centric.

Inspecting the JWT token - from Auth0.

Outlook OAuth Sandbox - for testing Outlook.Office.com API.

OpenID Connect Playground - from Auth0 - for developers to test and work with OpenID Connect calls.

Demo. instance of IdentityServer - has full stack OIDC / OAuth2 support.

Tying the two together - hooking the playground up with IdentityServer.

Enjoy!

Monday, August 15, 2016

OAuth2 : Verifying the Azure AD JWT signature

Was having a look at Azure AD and JWT tokens and was wondering how the signature was calculated?

I use this useful utility from Auth0 to decode the tokens.

So I paste either the access or identity token into the "Encoded" box and set the "Algorithm" drop down to "RS256" (as below in bold). Problem is the signature is invalid. So how do I verify it.?

Looking at a typical token header,

{
  "typ": "JWT",
  "alg": "RS256",
  "kid": "MnC_VZcATfM5pOYiJHMba9goEKY"
}


we see the algorithm and the reference to the public key.

In Azure AD, we can get the OAuth 2.0 details from the discovery endpoint viz.



and that gives us:

"authorization_endpoint": "https://login.microsoftonline.com/common/oauth2/
    authorize",
    "token_endpoint": "https://login.microsoftonline.com/common/oauth2/token",
    "token_endpoint_auth_methods_supported": [
        "client_secret_post",
        "private_key_jwt"
    ],
    "jwks_uri": "https://login.microsoftonline.com/common/discovery/keys",
    "response_modes_supported": [
        "query",
        "fragment",
        "form_post"
    ],
... 

Now if we go to the key endpoint (bold above), we see:

"keys": [
        {
            "kty": "RSA",
            "use": "sig",
            "kid": "MnC_VZcATfM5pOYiJHMba9goEKY",
            "x5t": "MnC_VZcATfM5pOYiJHMba9goEKY",
            "n": "vIqz-4-ER_vNWLON9yv8hIYV737...NOhfXgelixLUQ",
            "e": "AQAB",
            "x5c": [
                "MIIC4jCCAc...H3/bKkLSuDaKLWSqMhozdhXsIIKvJQ=="
            ]
        },
... 

There is  more than one of these sets. You need the one whose "kid" matches the "kid" in the JWT header.

The "x5c" is the public key. Copy the entire string e.g. from "MIIC" to "JQ==" in the above to Notepad.

Now add:

"-----BEGIN CERTIFICATE-----"

at the beginning and add:

"-----END CERTIFICATE-----"

at the end.

You should have something like:

-----BEGIN CERTIFICATE-----
MIIC4jCCAc
...
H3/bKkLSuDaKLWSqMhozdhXsIIKvJQ==
-----END CERTIFICATE-----

Now paste that into the "Verify Signature" box and you'll see the "Signature Verified" message at the bottom in blue.

Enjoy!