Thursday, November 26, 2015

IdentityServer : Federation with ADFS with Identity Server 3 as the IDP

This follows on from IdentityServer : Identity Server 3 as a WS-Federation IDP with an ASP.NET MVC application so read this first for the Identity Server details.

The use case in this post is an application (RP) that trusts ADFS and ADFS has Identity Server (IS) configured as a CP.

So the authentication chain is:

RP --> ADFS --> IS

ADFS is ADFS ("AD FS") 3.0 and IS is version 3. Everything is via WS-Fed.

On the IS side, we need a new RP:

new RelyingParty
{
      Realm = "http://adfs.domain/adfs/services/trust",
      Enabled = true,
      ReplyUrl = "https://adfs.domain/adfs/ls/",
      TokenType = TokenTypes.Saml2TokenProfile11,
      TokenLifeTime = 1,

       ClaimMappings = new Dictionary
      {
            { "sub", ClaimTypes.NameIdentifier },
            { "name", ClaimTypes.Name },
            { "given_name", ClaimTypes.GivenName },
            { "surname", ClaimTypes.Surname },
            { "email", ClaimTypes.Email }
      }

}


There was a bug (now fixed) with ADFS importing IS metadata (refer Default metadata missing). So you can import the metadata in the normal way or you can do this manually as below.

Identifiers:
















 Endpoints:

















Claims rules:













(where "P/T" is a pass-through rule).

Now we need to import the certificate manually. ADFS won't accept a pfx file.

You can get all the certificates here.

Or you can do this manually:

We need to convert the supplied idserv3test.pfx file to a .cer file.

I normally do this by importing the certificate and then exporting it as a .cer file. You will need the password to import the certificate which is "idsrv3test". (You can find this in "Certificate.cs").

(To export: in "mmc" , right-click on the certificate / All Tasks / Export / do not export the private key - choose "Base-64 encoded X509").

You could also do this with OpenSSL.

Then import this .cer certificate in the "Certificates" tab of the ADFS wizard.

OK - so run the RP - redirect to ADFS - choose IS in the Home Realm Discovery screen (assuming you have a number of CP) - redirect to IS - use the credentials "alice / alice".

ADFS throws an error. 

"An error occurred during an attempt to build the certificate chain for the claims provider trust 'https://localhost:44333/core' certificate identified by thumbprint '6B7ACC520305BFDB4F7252DAEB2177CC091FAAE1'. Possible causes are that the certificate has been revoked, the certificate chain could not be verified as specified by the claims provider trust's signing certificate revocation settings or certificate is not within its validity period.

You can use Windows PowerShell commands for AD FS to configure the revocation settings for the claims provider trust's signing certificate.
Claims provider trust's signing certificate revocation settings: CheckChainExcludeRoot
The following errors occurred while building the certificate chain: 
A certificate chain could not be built to a trusted root authority."

Not sure why this is? I've discussed this with a number of people but no real resolution. It may be a problem with my test setup?

I don't have this problem with the certificates I mint. I certainly don't want to change the revocation policies via PowerShell. So I made my own certificate, added it to the project and repeated the above. (And take note of C# : GetManifestResourceStream returns null on pfx file).

So now clear out the cookies (or use InPrivate mode), connect from the RP again and you will get the claims as per the IS setup as expected.

Enjoy!

C# : GetManifestResourceStream returns null on pfx file

I'm playing around with IdentityServer 3 and had some issues with the supplied certificate, So I made my own but the code to load it using GetManifestResourceStream returned null.

The certificate was OK - I could import it, inspect it etc.

WTF? - chat with Mr. Google and turns out you need to right-click on the pfx file in the project / Properties and set "Build Action" to "Embedded Resource".

Enjoy!

Wednesday, November 25, 2015

ADFS : OAuth 2.0 support

This post refers to ADFS ("AD FS") v3.0 on Server 2012 R2. Below that (2.1 and below), there is no OAuth 2.0 support.

It was inspired by OAuth2 SSO implementation using ADFS in MVC4 with Owin Oauth middleware.

Now this question was answered by @vibronet who is of course the much-fabled Vittorio of Cloud Identity fame.

"ADFS 2012 R2 only supports public clients. Web sites are confidential clients, hence you cannot perform an OAuth2 authorization grant with ADFS 2012 R2."

But there are references all over the Internet stating that ADFS v3.0 does support "authorization code grant" ?

So I queried this - refer to the article for the response!

After reading the OAuth 2.0 spec. again, ( RFC6749) there are two kinds of clients (Section 2.1)  viz:

"confidential
    Clients capable of maintaining the confidentiality of their credentials (e.g., client implemented on a secure server with restricted access to the client credentials), or capable of secure client authentication using other means.

public
    Clients incapable of maintaining the confidentiality of their credentials (e.g., clients executing on the device used by the resource owner, such as an installed native application or a web browser-based application), and incapable of secure client authentication via any other means"

and it then goes on to discussing the client profiles:
  • A web application is a confidential client running on a web server. 
  • A user-agent-based application is a public client in which the client code is downloaded from a web server and executes within a user-agent (e.g., web browser) on the device used by the resource owner. 
  • A native application is a public client installed and executed on the device used by the resource owner. 
 Now as per this post OAuth 2.0 support in ADFS on Windows Server 2012 R2, we see:

Supported authorization grants

Authorization grant typeADFS (Windows Server 2012 R2)
Authorization code grantSupported
Implicit grantNot supported
Resource Owner Password Credentials grantNot supported
Client Credentials grantNot supported

Supported client types

Client typeADFS (Windows Server 2012 R2)
Public clientSupported
Confidential clientNot supported

we note that "authorization code grant" is only supported for public clients which do not include web applications.

Which explains @vibronet's answer and also explains why the only code samples I've ever seen for this are for Web API not web application.

(If you read to the bottom of the post, you'll see that Microsoft extended the OAuth2 spec.!).

Also to call out @vibronet's statement "OAuth2 is not a sign on protocol". Yes - and it doesn't do SSO either. That's where OpenID Connect comes in.And OpenID Connect is not supported in this release either.

In terms of a summary of the grant types, I found "A guide to OAuth grants" useful.

If you want a full implementation plus OpenID Connect you'll find this in ADFS 4.0 - Server 2016 which brings the support up to par with Azure AD.

Enjoy!

Misc : Certification for blogs

There's more and more stuff on the Internet - which includes more and more blogs - and the advice and information in a pile of them is rubbish.

It takes ages to sift through all the information discarding all the chaff until you find a few grains of wheat!

stackoverflow addressed this problem with questions. People who know what they are talking about get marked up and you can gauge the quality of the answer from the reputation of the answerer.

We need something like that for blogs.

So there would be some way of getting your blog "certified" e.g. the author has a stackoverflow rep. of more than 10,000 or whatever. Then you get a "badge" that you can display. And you can use this in a Google or Bing filter i.e. show me information from certified blogs only.

We can but dream!

Enjoy!

IdentityServer : Post up on the Identity Server Resource page

Good to see my post :

IdentityServer : Identity Server 3 as a WS-Federation IDP with an ASP.NET MVC application 

is now up on the Identity Server documentation page:

Resources

under:

Getting started with WS-Federation in IdentityServer

It's always a good feeling to "pay back".

Enjoy!

Friday, November 20, 2015

Thursday, November 19, 2015

ADFS : RelayState with IDPInitiated

I've been playing around with this lately so thought I would get all the references in one place.

Firstly. an overview : AD FS 2.0 RelayState.

Now I'm using ADFS ("AD FS") 3.0 so no need to install the hot-fix.

However, the feature is turned off by default so you need to turn it on as in Enabling RelayState In ADFS Versions.

And then you need the AD FS 2.0 RelayState Generator.

My use case is really simple:

SP --> ADFS (with a number of SAML SP).

I want to avoid selecting which SP. (And thus achieve the same objective as when I use the "whr" parameter with WS-Fed).

(Now as the first link alludes to, you could achieve this by using the loginToRp parameter instead).

So using the generator tool:













The actual URL is:

https://domain.local/adfs/ls/idpinitiatedsignon.aspx?RelayState=RPID%3Durn%253Acustomer%253Aserviceprovider1
%26RelayState%3Dhttps%253A%252F%252Fwebsite%252FServiceProvider%252FDefault.aspx

which for ease of reading is:

https://domain.local/adfs/ls/idpinitiatedsignon.aspx?RelayState=RPID=urn:customer:serviceprovider1&RelayState=https://website/ServiceProvider/Default.aspx

when URL Decoded.

Note: Don't be confused by the fact that RelayState serves two completely separate purposes. For IdPInitiated, the RelayState specifies the landing page at the SP. For SPInitiated it's a way for the SP to maintain state information between sending the AuthnRequest and receiving the SAML response. RelayState may be sent along with the AuthnRequest and the IDP must return this RelayState along with the SAML response.

Enjoy!

Wednesday, November 18, 2015

ADFS : SAML all the way through

I recently set up some ADFS 3.0 ("AD FS") servers as follows:

SP --> SAML --> ADFS A --> xxxx --> ADFS B --> Authenticate

The middle ADFS A is just passing everything through. SAML is the SAML 2.0 protocol.

What protocol is "xxx"?

I had thought that all ADFS to ADFS traffic was WS-Fed but to my surprise it turned out to be SAML. Which caused an error because I had configured the ADFS trust with SHA 256 rather than SHA 1.

So you see the AuthnRequest getting passed all the way up and the Response passed all the way down.

However, when I logged out, it didn't work.

Chatting to Mr. Google, I discovered that the SAML logout doesn't work if the token doesn't have a NameID claim.

So for ADFS B, you need a Transform rule to transform e..g. email to NameID.

And for ADFS A, you need a pass-through rule for NameID. Don't forget you need pass-through rules for all the claims from ADFS B on ADFS A.

Enjoy!

ADFS : MSIS7527

The full description is "MSIS7527: The metadata does not contain the roles descriptors needed for the entity to be configured as a relying party trust".

I was trying to set up a RP trust with some metadata to another STS when I got this.

Examination of the metadata showed that there was no SPSSODescriptor in the metadata.

This contains things like whether the assertions should be signed, the location of the SingleLogoutService, the location of the AssertionConsumerService, the NameIDFormat etc.

Ended up having to configure the RP manually which is a PIA because then you have to get the signing certificate etc. etc. which is exactly the pain that the metadata is supposed to solve.

I imagine you would get a similar error if the metadata didn't contain the IDPSSODescriptor.

Update:

Pondering on this, I realised that these two descriptors are only for SAML 2.0 federation. This particular STS only supports WS-Federation.

The metadata was missing the

RoleDescriptor xsi:type="fed:ApplicationServiceType" 

element.

This tells ADFS that WS-Federation is supported. Since this was missing, ADFS fell back to SAML but then couldn't find either of the two Descriptors hence the error.

Enjoy!

Wednesday, November 11, 2015

IdentityServer : Identity Server 3 as a WS-Federation IDP with an ASP.NET MVC application

Expanding on my previous post ...

BTW : idsrv3 documentation is here.

Run up the "Self-Host with WS-Federation"  from the samples.

It runs on "https://localhost:44333/core".

Now create a new MVC project in VS. I used VS 2013 with "ASP.NET Web Application" and .NET 4.5.

On the next page, ensure "MVC" is checked and click "Change Authentication".

Select the options as per:


 The metadata address is:

https://localhost:44333/core/wsfed/metadata

Now run the project, click the "About" or "Contact" tabs and you will be redirected to identityserver3 and you'll see a login screen.

As per my previous post, use alice/alice.(You can see these in the "Users.cs" file in the self-host project).

Then you'll get an error stating that the RP is invalid.

That's because you need to add the RP to the self-host project.

You do this in "RelyingParties.cs".

new RelyingParty
{
    Realm = "https://localhost:44307/",
    Enabled = true,
    ReplyUrl = "https://localhost:44307/",
    TokenType = TokenTypes.Saml11TokenProfile11,
    TokenLifeTime = 1,

    ClaimMappings = new Dictionary
    {
        { "sub", ClaimTypes.NameIdentifier },
        { "name", ClaimTypes.Name },
        { "given_name", ClaimTypes.GivenName },
        { "surname", ClaimTypes.Surname },
        { "email", ClaimTypes.Email }
   }

}

The 44307 endpoint is what was generated for the MVC project.

In "Users.cs" in the self-host project, change:

new InMemoryUser{Subject = "alice", Username = "alice", Password = "alice",
 Claims = new Claim[]
 {
     new Claim(Constants.ClaimTypes.GivenName, "Alice"),
     new Claim(Constants.ClaimTypes.FamilyName, "Smith"),
     new Claim(Constants.ClaimTypes.Name, "Alice Smith"),
     new Claim(Constants.ClaimTypes.Email, "AliceSmith@email.com"),
 }
},

In the MVC project, change "Contacts.cshtml" to:

@{
    ViewBag.Title = "Contact";
}
@model IEnumerable
    @foreach (var claim in Model)
    {
        @claim.Type
        @claim.Value
    }
In the HomeController.cs in the MVC project, change:

public ActionResult Contact()
{
      return View((User as ClaimsPrincipal).Claims);
}

Then run up the project, authenticate, click the "Contacts" tab and viola:



Enjoy!

Monday, November 09, 2015

IdentityServer : IdentityServer 3

There's not a lot of documentation on this.

If you come from a background of IdentityServer 2 which is  a normal ASP.NET MVC web site with web.config and heaps of admin. screens, you are in for a bit of a culture shock (as I was).

First off, idsrv3 has no Admin. screens. Yup - everything is done in code.

It's based on the OWIN concept of plug-ins.

The easiest way to get started is to go to the Samples directory i.e. IdentityServer3 Samples

Then build the "Self-Host with WS-Federation" sample in VS. I used VS 2013.

You'll notice that idsrv3 is concentrated on OpenID Connect and OAuth. WS-Fed and SAML are very much add-ons.

Then  right click the project - Debug.

You'll see this in the Command prompt.

[WRN] (IdentityServer3.Core.Configuration.IdentityServerServiceFactory)
 AuthorizationCodeStore not configured - falling back to InMemory
[WRN] (IdentityServer3.Core.Configuration.IdentityServerServiceFactory)
 TokenHandleStore not configured - falling back to InMemory
[WRN] (IdentityServer3.Core.Configuration.IdentityServerServiceFactory)
 ConsentStore not configured - falling back to InMemory
[WRN] (IdentityServer3.Core.Configuration.IdentityServerServiceFactory)
 RefreshTokenStore not configured - falling back to InMemory

Server listening at https://localhost:44333/core. Press enter to stop
The "self-host" means no IIS. It has a "built-in" web server. This is part of OWIN where the idea was to abstract away from the ASP.NET reliance on IIS.

Also, you have to plug-in your own identity store. If you don't (as in this example) it falls back to InMemory.

So now if you navigate to https://localhost:44333/core, you'll get the Welcome screen.

If you click the "discovery document" link, you'll see the OpenID Connect "metadata" in JSON format. This is part of the OpenID Connect standard.

If you click the "application permissions" link. you get a LogIn screen.

Now if you had a look through the actual idsrv3 project, you'd see that there are two canned users viz alice and bob with the password being alice / bob respectively. And there are some canned claims.

So what about WS-Fed?

The metadata address is: https://localhost:44333/core/wsfed/metadata.

Going to https://localhost:44333/core/wsfed gives:

{
  • "Message": "Invalid WS-Federation request"
}
much as going to "adfs/ls" in ADFS would.

Enjoy!

Thursday, November 05, 2015

SAML : Please do not roll your own

I've answered two questions on the forums today concerning SAML 2.0 protocol stacks that people are trying to roll on their own.

Not surprisingly, they are stuck and I can pretty much guarantee that there are security holes in their solutions that you could drive a Soviet May Day parade through!

SAML is hard, security is hard, writing security software is even harder,

Please use a library e.g. SAML : SAML connectivity / toolkit

Enjoy!

Wednesday, November 04, 2015

HTTP : HTTP 418

This amused me :-)

Hyper Text Coffee Pot Control Protocol

In particular:

418 I'm a teapot - The HTCPCP server is a Teapot - "short and stout"

If you don't get the reference, it's from the children's song:

"I'm a little teapot short and stout.
Here is my handle.
Here is my spout.
When I get all steamed up,
Hear me shout!
Just tip me over
And pour me out

I'm a clever teapot, yes it's true.
Here's an example of what I can do.
I can turn my handle to a spout.
Just tip me over and pour me out"

Enjoy!

Tuesday, November 03, 2015

ADFS : whr for AD

You can use whr to tell ADFS what CP to use which saves ADFS from asking the user via HRD.

So if you had some kind of IDP upstream whose ID was "urn:idp:auth", then setting the whr to that value tells ADFS to find the IDP with that ID and redirect to it seamlessly.

That's fine when you have another CP but what if you want to force ADFS to choose the local AD?

What's AD's ID?

After consulting with Mr. Google, the answer is the address of the ADFS service i.e.

http://server.domain/adfs/services/trust

Enjoy!