Wednesday, November 15, 2017

ADFS : ADFS 4.0 with SPA

This is for Server 2016 with a single page application.

There is a sample that shows how to do this but you will see many comments along the lines of "I can authenticate but when I call the API I get "Authorization has been denied for this request" ".

This error is typically invoked when either the "audience" or the "issuer" is wrong.

Once you have authenticated, look at the token you received under the "User" tab e.g.

Id_token content
aud:https://localhost:44326/
iss:https://some-adfs/adfs

Ensure these are the values configured for "Audience" and "Issuer" in the "appSettings".

They are case-sensitive!

The sample is a badly hacked Azure AD one and still has references to this all over the place.

It is also confusing because it refers to constructs like "tenant" which mean nothing in the ADFS world.

Also the clientID is a string (as in Azure AD) rather than a GIUD that is automatically generated for you when you create the application.

It needs to be rewritten to make it ADFS centric!

The other problem is that it uses implicit flow and there are contradictory articles that mention that you cannot get extra or custom claims with this flow because it would make the query string too long?

Enjoy!



Monday, November 06, 2017

ADFS : Application Groups

ADFS 4.0 manages OpenID Connect / OAuth connections via the "Application Groups" folder.

There are three kinds:
  • Native application
  • Server application
  • Web API
which leads to the following combinations:
  • Native application accessing web API
  • Server application accessing Web API
Plus the odd one out:
  • Web browser accessing web application
The PowerShell cmdlets split into three separate commands:
  • Get-AdfsNativeClientApplication
  • Get-AdfsServerApplication
  • Get-AdfsWebApiApplication
So although you can create an application with a web API in one pass through the wizard, the separate components need to be accessed via PowerShell.

Examples:

Get-AdfsNativeClientApplication

Name                       : MyApp  - Native application
Identifier                 : b2...27
ApplicationGroupIdentifier : MyApp
Description                :
Enabled                    : True
RedirectUri                : {https://blah}

Get-AdfsServerApplication

ADUserPrincipalName                  :
ClientSecret                         : ********
JWTSigningCertificateRevocationCheck : None
JWTSigningKeys                       : {}
JWKSUri                              :
Name                                 : My server application
Identifier                           : 8e...44
ApplicationGroupIdentifier           : MyApp
Description                          :
Enabled                              : True
RedirectUri                          : {https://blah}

Get-AdfsWebApiApplication

Name                                 : My Web API
Identifier                           : {https://blah/webapi}
AccessControlPolicyName              : Permit everyone
AccessControlPolicyParameters        :
AdditionalAuthenticationRules        :
AllowedAuthenticationClassReferences : {}
AllowedClientTypes                   : Public, Confidential
ApplicationGroupIdentifier           : MyApp
ApplicationGroupId                   : 12...56
AlwaysRequireAuthentication          : False
ClaimsProviderName                   : {}
DelegationAuthorizationRules         :
Enabled                              : True
ImpersonationAuthorizationRules      :
IssuanceAuthorizationRules           :
IssueOAuthRefreshTokensTo            : AllDevices
IssuanceTransformRules               : @RuleName = "All"
                                       c:[]
                                        => issue(claim = c);
                                      
                                      
NotBeforeSkew                        : 0
Description                          :
PublishedThroughProxy                : False
RefreshTokenProtectionEnabled        : False
RequestMFAFromClaimsProviders        : False
ResultantPolicy                      : RequireFreshAuthentication:False
                                       IssuanceAuthorizationRules:
                                       {
                                         Permit everyone
                                       }
TokenLifetime                        : 0

Plus we have the legacy cmdlets from ADFS 3.0:

Get-AdfsClient

RedirectUri                          : {ms-appx-web://Microsoft.AAD.BrokerPlugin}
Name                                 : Windows Logon Client
Description                          : Client for Microsoft Windows Logon
ClientId                             : 38...93b
BuiltIn                              : True
Enabled                              : True
ClientType                           : Public
ADUserPrincipalName                  :
ClientSecret                         :
JWTSigningCertificateRevocationCheck : None
JWTSigningKeys                       : {}
JWKSUri                              :

Just remember that the clientID is auto-generated when you create one of these entries and the secret key can only be viewed once in the wizard during creation.

Plus there was this question over on the forum around scope:

In an ADFS Application Group, add Client Application/Permitted Scope to Web API with PowerShell

Grant-AdfsApplicationPermission -ClientRoleIdentifier $clientAppIdGuid -ServerRoleIdentifier $relyingPartyIdentifier -ScopeNames $theScopesYouWantAssignedTo

And remember you can get all the commands by:

get-command *adfsclient*

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Cmdlet          Add-AdfsClient                                     1.0.0.0    ADFS
Cmdlet          Disable-AdfsClient                                 1.0.0.0    ADFS
Cmdlet          Enable-AdfsClient                                  1.0.0.0    ADFS
Cmdlet          Get-AdfsClient                                     1.0.0.0    ADFS
Cmdlet          Remove-AdfsClient                                  1.0.0.0    ADFS
Cmdlet          Set-AdfsClient                                     1.0.0.0    ADFS

get-command *adfsnativeclient*

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Cmdlet          Add-AdfsNativeClientApplication                    1.0.0.0    ADFS
Cmdlet          Get-AdfsNativeClientApplication                    1.0.0.0    ADFS
Cmdlet          Remove-AdfsNativeClientApplication                 1.0.0.0    ADFS
Cmdlet          Set-AdfsNativeClientApplication                    1.0.0.0    ADFS

get-command *adfsserver*

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Cmdlet          Add-AdfsServerApplication                          1.0.0.0    ADFS
Cmdlet          Get-AdfsServerApplication                          1.0.0.0    ADFS
Cmdlet          Remove-AdfsServerApplication                       1.0.0.0    ADFS
Cmdlet          Set-AdfsServerApplication                          1.0.0.0    ADFS

get-command *adfswebapi*

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Cmdlet          Add-AdfsWebApiApplication                          1.0.0.0    ADFS
Cmdlet          Get-AdfsWebApiApplication                          1.0.0.0    ADFS
Cmdlet          Remove-AdfsWebApiApplication                       1.0.0.0    ADFS
Cmdlet          Set-AdfsWebApiApplication                          1.0.0.0    ADFS

get-command *adfsapplication*

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Cmdlet          Disable-AdfsApplicationGroup                       1.0.0.0    ADFS
Cmdlet          Enable-AdfsApplicationGroup                        1.0.0.0    ADFS
Cmdlet          Get-AdfsApplicationGroup                           1.0.0.0    ADFS
Cmdlet          Get-AdfsApplicationPermission                      1.0.0.0    ADFS
Cmdlet          Grant-AdfsApplicationPermission                    1.0.0.0    ADFS
Cmdlet          New-AdfsApplicationGroup                           1.0.0.0    ADFS
Cmdlet          Remove-AdfsApplicationGroup                        1.0.0.0    ADFS
Cmdlet          Revoke-AdfsApplicationPermission                   1.0.0.0    ADFS
Cmdlet          Set-AdfsApplicationGroup                           1.0.0.0    ADFS
Cmdlet          Set-AdfsApplicationPermission                      1.0.0.0    ADFS

Enjoy!

Monday, October 30, 2017

Visual Studio : Unable to connect to web server IIS Express

This is with VS 2017.

I was looking at a .NET Core project and wanted to change from http to https.

So under Properties / Debug, I checked the "Enable SSL" checkbox.

This changes the port so I then did a copy / replace of the old port to the new one and changed the URL to https e.g.

http://localhost:5000 became https://localhost:44326

Then I got "Unable to connect to web server IIS Express".

Consulted with Mr. Google.

The solution that worked for me was to:
  • Close the VS project
  • In File Explorer, navigate to the project and delete the entire ".vs" folder
  • Restart the project
  • Run as "Debug"
  • Works
Apparently, it has something to do with the "applicationhost.config" file.

 Enjoy!

Friday, October 27, 2017

Azure : Weird problem with OAuth timing

Came across a head-scratcher recently.

Using OpenID Connect / OAuth against Azure AD, authentication would always fail and then work if you retried two minutes later. Before that, retries would consistently fail.

WTF? What is the significance of two minutes?

Mr. Google to the rescue and came across a similar problem in SAML-P.

The problem here was that the two servers clocks were not synchronised. The token has start / end parameters for the validity of the token and any time outside of these is considered invalid and hence the token is rejected. (You can fix this via the skew parameter),

The OAuth JWT token has similar fields viz.

iat - Issued at
nbf - Not before

Checking the respective server's times, this would indeed the problem :-)

And you guessed it - the server's times were two minutes apart!

Enjoy!

Wednesday, October 18, 2017

IdentityServer : WS-Fed metadata imported into ADFS

I've been looking at Identity server 4 (idsrv4) just to have a play with it.

This runs on .NET Core which I something else I need to get up to speed on.

There is also a WS-Fed plug-in which I got working and tried to hook up to ADFS as an exercise.

The metadata endpoint is:

http://localhost:5000/wsfederation

and when I tried to import this into ADFS, I got the normal:

"Metadata contains some features not supported by ADFS" warning.

Now this could be because the metadata contains a SAML profile that ADFS doesn't support - PAOS being an example.

But 999 out of 1000 times, it's because the endpoints are "http" not "https".

Looking at the metadata, this is indeed the case.

This means that although the entry is added to ADFS, it has no endpoints so it will never work.

You can't just edit the metadata because it's signed and you'll get a signing error when you try and import the updated file.

You can delete the whole "Signature" section in the XML if you want. Do this at your own risk - normal best practice security applies :-).

The other way is to update the metadata when it's generated. There is no metadata file - it's dynamically generated every time.


You can do this in the "Properties".

Select the "Enable SSL" check box. IIS Express generates a new endpoint as above so now you have to replace all the instances of:

http://localhost:5000

with the https endpoint as above.

This also means that you need to change this address in any of the client samples.

The new metadata imports without issues.

Enjoy!

Wednesday, October 11, 2017

ADFS : PowerShell cmdlet - parameter PolicyMetadata

Another question on the forum around the format of PowerShell parameters.

This one was around PolicyMetadata.

Get-AdfsAccessControlPolicy -Name "Demo"

Name           : Demo
Identifier     : Demo
IsBuiltIn      : False
RpUsageCount   : 0
LastUpdateTime : 10/10/2017 7:22:00 PM
Description    :
PolicyMetadata : RequireFreshAuthentication:False
                 IssuanceAuthorizationRules:
                 {
                   Permit everyone
                 }
AssignedTo     : {} 


Now if you copy / paste the metadata into a file and then run:

New-AdfsAccessControlPolicy -Name "DemoOne" -PolicyMetadataFile c:\Filename

you get all kinds of errors.

Looking at the errors e.g. "Root error" made me think that the format wasn't JSON, rather XML.

Which means that it is almost impossible to guess the element names etc.

So Mr. Google to the rescue and a long time later, I came across:

(Get-AdfsAccessControlPolicy -Name "Permit everyone").PolicyMetadata | fl *

which displays:

IsParameterized : False
Serialized      : <PolicyMetadata xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
                  xmlns="http://schemas.datacontract.org/2012/04/ADFS">
                    <RequireFreshAuthentication>false</RequireFreshAuthentication>
                    <IssuanceAuthorizationRules>
                      <Rule>
                        <Conditions>
                          <Condition i:type="AlwaysCondition">
                            <Operator>IsPresent</Operator>
                            <Values />
                          </Condition>
                        </Conditions>
                      </Rule>
                    </IssuanceAuthorizationRules>
                  </PolicyMetadata>
Summary         : RequireFreshAuthentication:False
                  IssuanceAuthorizationRules:
                  {
                    Permit everyone
                  }
ExtensionData   : System.Runtime.Serialization.ExtensionDataObject


Putting that into a file e.g.

<?xml version="1.0" encoding="UTF-8"?>
<PolicyMetadata xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://schemas.datacontract.org/2012/04/ADFS">
    <RequireFreshAuthentication>false</RequireFreshAuthentication>
        <IssuanceAuthorizationRules>
            <Rule>
                <Conditions>
                    <Condition i:type="AlwaysCondition">
                        <Operator>IsPresent</Operator>
                        <Values />
                    </Condition>
                </Conditions>
            </Rule>
        </IssuanceAuthorizationRules>
</PolicyMetadata>


and then running the command works!

I suggest running:

Get-AdfsAccessControlPolicy  

which displays them all and then look at the XML formats to get some hints as to the XML format.

Enjoy!

Saturday, October 07, 2017

ADFS : PowerShell cmdlet - parameter is an array

Over on the forum, there was a question around a parameter in the cmdlet that accepts multiple options as an array i.e.

"-RedirectUriSpecifies an array of redirection URIs for the OAuth 2.0 client to register with AD FS".

The question was around the format of the array since that is not specified.

Looking at another example:

Set-AdfsRelyingPartyTrust -TargetName claimapp -ClaimsProviderName @("Fabrikam","Active Directory")

the array is of the form:

@("Fabrikam","Active Directory")

Enjoy!

Thursday, October 05, 2017

OAuth2 : Displaying JWT tokens

The standard way that I've been looking at and debugging with JWT tokens is via:

https://jwt.io

Now, Microsoft have come to the party with:

https://jwt.ms

It starts off with


Then you copy / paste the ID token and it will display the details.

You can see the standard attributes:


or the same thing as claims rules (if this is a more familiar format for you).



And it gives you a bit of extra context.

Enjoy!

Friday, September 29, 2017

Auth0 : The connection was disabled

I was trying to set up an enterprise connection in Auth0 to my ADFS instance.

When I tried the "Test" button on the enterprise connection, I got:

"description": "the connection was disabled"

WTF?

Eventually I realised that this is because I do not have a client that is configured under "Connections" to use that enterprise connection.

Assigned this to a client and viola! all is well.

That error message needs improvement!

Enjoy!

Monday, September 25, 2017

ADFS : Pre-populating the user on the login screen

This question often comes up and I came across a site that does this.

Note this is with ADFS 4.0 (Server 2016).

The URL is:

GET https://my-adfs.cloudapp.net/adfs/ls/?login_hint=myuser%40dev.local
&wctx=Yue...BfN-A7v
&wtrealm=some_realm
&wa=wsignin1.0
...
etc

The ADFS login screen then looks like:


Enjoy!

Wednesday, September 13, 2017

ADFS : RP default token lifetime

This question keeps coming up.

The default value for TokenLifetime on a RP trust is 0. But what value is 0?

As usual, a heap of garbage via Google.

60 minutes, 300 minutes, 600 minutes, 10 hours ...

Using ADFS 4.0 and looking at a SAML RP, we get:


Conditions        NotBefore="2017-09-12T19:24:01.817Z"
                   NotOnOrAfter="2017-09-12T20:24:01.817Z"


So the correct answer is 1 hour = 60 minutes.

Note: Don't confuse this with the ADFS wide WebSSOLifetime. This is a server wide timeout parameter.

The default value for that = 8 hours = 480 minutes.

Enjoy!

Friday, September 01, 2017

Azure B2C : Adding Azure Active Directory (AAD) via custom policies

As I write these are in preview.

The documentation is here.

The AAD guide is here.

And the obligatory warning:

"Custom policies are designed primarily for identity pros who need to address complex scenarios. For most scenarios, we recommend that you use Azure Active Directory B2C built-in policies. Built-in policies are easier to set up for your configuration. You can use built-in and custom policies in the same Azure Active Directory B2C tenant. To learn more, see the overview of custom policies."

and again:

"Custom policy editing is not for everyone. The learning curve is demanding, the startup time is longer, and future changes to custom policies will require similar expertise to maintain. Built-in policies should be carefully considered first for your scenario before using custom policies."

I don't necessarily agree with this and am somewhat puzzled as to why they push this so hard.

The aim should be to encourage people to have a crack at it and learn something rather than scare them away.

I would spend some time reading through the getting started guide and get an overview of how the XML files work, how to upload them etc.

The big drawback about all of these guides is that they publish snippets of XML and it's always hard to figure out the context i.e. where they go in the document and how they relate to the other sections.

So I decided to publish all five files as gists (suitably redacted!).

I have three add-ons:
  • Facebook - from the default policy 
  • ADFS - added but doesn't work because of the self-signed certificate
  • AAD - which works
Note that this was for a PoC where I was just looking at authentication. I haven't looked at the claims passed etc.

Also I did not have an actual application. I just tested using the "Run Now" button.

My B2C page looks like:


Also note that I added Application Insights which I strongly recommend for debugging (in SignUpOrSigninWithAAD.xml).

Enjoy!