Friday, July 24, 2015

Misc : Just because something is there doesn't mean you have to use it.

I came across a situation recently that made me smile!

For various reasons, this company uses ADFS and IdentityServer 2.0.

They then had a requirement to secute a Web API.

Web API's require a JWT token and they knew that IdentityServer allows you to convert token types for RP i.e.


So the path is Web API --> IS --> ADFS and then return the SAML token and convert to JWT.

It works fine but if they had taken a step back and asked "What is the correct way to do this" and not been sidetracked by the JWT issue, then they would have found a much better solution which is also supported by IS viz. OAuth2.

As it transpired, they needed to authenticate against AD which IS doesn't do and ADFS 3.0 has limited OAuth functionality but when ADFS vNext on Server 2016 comes out, hopefully they will convert the above and use OAuth2!

Enjoy!

Tuesday, July 21, 2015

ADFS : Problems when restarting

This is with Active Directory Federation Services / ADFS / "AD FS" 2012 R2.

Server sometimes hangs during restart.

What I find is that the server is up but the ADFS wizard will not start. It says that the ADFS service is not running. So restart the ADFS service.

Bad idea! Service just sits there saying "Starting". Can't Stop / Restart etc.

So reset the server. Takes a while to come up.

Before starting the ADFS service, start the Microsoft Key Distribution Service” and then start the ADFS service and then start the ADFS wizard.

Some more possibly useful information here.

All OK.

Enjoy!

Tuesday, June 23, 2015

stackoverflow : Tag badges

Finally got my ADFS 2.0 tag badge:


Nice to get some recognition for all those hours helping and mentoring people.

Goes nicely with my others:

Enjoy!


Tuesday, June 16, 2015

Musings : How to reset a password

I've been involved in discussions with a number of customers recently around this very topic and (without exception) everyone has given me a flowchart that is flawed in some way.

People, this problem has already been solved. Why do you want to re-invent the wheel?

The inestimable Troy Hunt blogged on this a while back - Everything you ever wanted to know about building a secure password reset feature .

There's a flowchart at the end of the post which gives a good overview of the type of system that you should be designing.

I used this flowchart as a discussion point against the various "models" I was presented with and in each case, we discussed what was missing and the risks associated with that.

Ultimately, the customer makes the choice - but it's always worth having the discussion so that they are as informed as possible.

And always write down your recommendations so when things turn to custard and the finger points at you, you have something tangible to fall back on.

BTW - you could use most of this as a "Change Password" guide.

Enjoy!

ADFS : Playing around with Postman

This is for Active Directory Federation Services / "AD FS" / ADFS on Windows Server 2016 (currently Technical Preview 2).

My server is in an Azure VM.

I been playing around with Postman and the new OpenID Connect / OAuth2 features in ADFS.

But could not get it to work.

I contacted the Postman people who were very helpful and they advised me that the issue was that the SSL certificate on my VM is self-signed and hence causes the problem. There's no trust. Other than that, there appears to be no issues.

As this is a test VM and is going to be superseded when TP3 comes along, I don't really see any point in paying for a CA certificate.

But it would be nice to see it working :-)

Enjoy!

Monday, June 15, 2015

SAML : Federating with Azure Active Directory using SAML

This is SAML-P (the protocol) as opposed to SAML (the token).

There are a number of questions around about how you do this with AAD.

The official documentation SAML Protocol Reference is not very helpful but then I came across this:

Set up a trust between Shibboleth and Azure AD

The trick seems to be some "missing" documentation i.e. in:

Set-MsolDomainAuthentication   ,,, -PreferredAuthenticationProtocol SAMLP

Applying Mr. Google to "PreferredAuthenticationProtocol" bought me to:

Office 365 Supports SAML 2     and

Office 365 - Switching the federation protocol to SAML from WS-Federation

Note: Office 365 runs on top of AAD.

No idea why the documentation lacks this key element?

Enjoy!

Wednesday, June 10, 2015

MSDeploy : Registry editing has been disabled by your administrator

Was installing a web site in IIS on Windows Server 2012 R2 and using msdeploy.

Came up with:

Registry editing has been disabled by your administrator

Mr Google etc. and there's pages about using gpedit.msc and navigating to "User Config / Admin Templates / System" and finding the entry "Prevent access to registry editing tools" and making it "Not configured" or "Disabled" etc.

Actually, all you need to do is add:

set MSDeployPath=C:\Program Files\IIS\Microsoft Web Deploy V3\

to the DOS settings!

Obviously, you need to install msdeploy beforehand.

Enjoy!

Tuesday, June 09, 2015

ADFS : OpenID Connect and ADAL


This is for Active Directory Federation Services / "AD FS" / ADFS on Windows Server 2016 (currently Technical Preview 2).

My server is in an Azure VM.

It also uses the Active Directory Authentication Library (ADAL).

This is based on AzureADSamples/WebApp-WebAPI-OpenIDConnect-DotNet.

This is for Azure AD and is a web application that requires authentication with AAD and then calls a secure Web API that uses the current JSON token. The Web API is the Graph API that you use to get attributes from AAD.

So let's translate this to ADFS which now supports OpenID Connect. Somewhat annoying that all the samples are for Azure and none for ADFS, ADFS needs to feel the love :-).

<add key="todo:TodoListResourceid" value="https://myPC/TodoListService" />
<add key="todo:TodoListBaseAddress" value="https://myPC" />
<add key="ida:ClientId" value="OpenIDConnect1234" />
<add key="ida:AppKey" value="[Enter app key as obtained from Azure Portal, e.g. dYfh0H8iRU7FIBnPcYIil/Af6SSAwkxVhB0mA8DbzdQ=]" />
<add key="ida:Tenant" value="adfs.local.cloudapp.net" />
<!--<add key="ida:AADInstance" value="https://login.microsoftonline.com/{0}" />-->
<add key="ida:AADInstance" value="https://adfs.local.cloudapp.net/adfs" />
<add key="ida:PostLogoutRedirectUri" value="https://myPC/TodoListWebApp" />

Changes for the application web.config as above.

I changed StartUp.Auth.cs to the simpler:

app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
     new OpenIdConnectAuthenticationOptions
     {
         ClientId = clientId,
         Authority = Authority,
         PostLogoutRedirectUri = postLogoutRedirectUri,
     });

The ADFS client OAuth configuration is:



 OK - so let's run up this puppy.

We get this error:

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.

Looked through the OWIN code and couldn't see anywhere where this is passed.

So I manually added it to the URL at the end in the browser:

 &redirect_uri=https%3A%2F%2FmyPC1%2FTodoListWebApp

Then off to ADFS, authenticate and back we come.

Clearly, still some work to do with ADAL and TP2!

Enjoy!

Thursday, June 04, 2015

ADFS : Protecting Web API with OAuth2

This is for Active Directory Federation Services / "AD FS" / ADFS on Windows Server 2016 (currently Technical Preview 2).

It also uses the Active Directory Authentication Library (ADAL).

Vittorio has a good overview describing Server 2012 behaviour over at Securing a Web API with ADFS on WS2012 R2 Got Even Easier.

How does that look on Server 2016?

The VS solution is pretty much the same. I added a Windows Forms project to the solution which is my native client and the code for that (behind the button) is pretty much the same as  the above post. This calls a web API project in the same solution.

private async void button1_Click(object sender, EventArgs e)
{
            string authority = "https://ADFS_local.cloudapp.net/adfs";
            string resourceURI = "https://myPC/WinServTP2ADALWebApplication/";
            string clientID = "API1234";
            string clientReturnURI = "https://myPC/WinServTP2ADALWebApplication/";

            AuthenticationContext ac = new AuthenticationContext(authority, false);
            AuthenticationResult ar = ac.AcquireToken(resourceURI, clientID, new Uri(clientReturnURI));

            string authHeader = ar.CreateAuthorizationHeader();
            HttpClient client = new HttpClient();
            HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "https://myPC/WinServTP2ADALWebApplication/api/Values");
            request.Headers.TryAddWithoutValidation("Authorization", authHeader);
            HttpResponseMessage response = await client.SendAsync(request);
            string responseString = await response.Content.ReadAsStringAsync();
            MessageBox.Show(responseString);
}

ADFS_local is a Windows Server 2016 server running as an Azure VM.

Over to ADFS.

The OAuth client now has wizard support as opposed to the PowerShell in the post. It looks like:



You do this under "Clients".

We add the RP manually and notice the new OAuth option.


Notice also the extra menu items on the LHS for OAuth.


You can click on the "All Clients" to add more permissions (scopes). At the moment, it is just for "openid". You could also click on "Add" and select a specific client.

I added "email" and "profile".

(BTW, there is a separate "Scope Descriptions" item in the main menu).

Then choose your Access Policy on the next screen - in this case "Permit everyone". Review and you are done.

So looking at our RP, we have an identifier:


and some OAuth permissions - notice the new tab. That's pretty much it.




OK - so now we have the client and the web API RP all configured and ready to go.

Time to run up the client:


Click the button which calls the API. This is protected as per the configuration and so we get the ADFS logon screen. Authenticate with ADFS and:


We are done!

Enjoy!

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.

Security : Creating self-signed certificates

When you play around a lot with IIS and ADFS and SSL you need certificates and these will normally be self-signed.

You can create them through IIS but that's a pain (they are only valid for a year) and from Server 2012 R2 onwards, ADFS does not run on IIS so you are installing IIS simply for certificate creation?

I used to use the magic SelfSSL7 but that requires .NET 3.5 which isn't there by default on Server 2012 and upwards. (You could always install it as a role / feature).

So now I use "makecert".

Brock has blogged on this: makecert and creating ssl or signing certificates and also
Generating and using a certificate to authorise Azure Automation.

On Windows 8, you'll find makecert inside "Visual Studio Tools" / "Developer Command Prompt for VS2013". Remember to run as Admin.

We see:

C:\>makecert -?

Usage: MakeCert [ basic|extended options] [outputCertificateFile]
Basic Options
 -sk        Subject's key container name; To be created if not present
 -pe                 Mark generated private key as exportable
 -ss          Subject's certificate store name that stores the output
                     certificate
 -sr       Subject's certificate store location.
                        .  Default to 'CurrentUser'
 -#          Serial Number from 1 to 2^31-1.  Default to be unique
 -$       The signing authority of the certificate
                       
 -n        Certificate subject X500 name (eg: CN=Fred Dews)
 -?                  Return a list of basic options
 -!                  Return a list of extended options

C:\>makecert -!

Usage: MakeCert [ basic|extended options] [outputCertificateFile]
Extended Options
 -tbs          Certificate or CRL file to be signed
 -sc           Subject's certificate file
 -sv        Subject's PVK file; To be created if not present
 -ic           Issuer's certificate file
 -ik        Issuer's key container name
 -iv        Issuer's PVK file
 -is          Issuer's certificate store name.
 -ir       Issuer's certificate store location
                        .  Default to 'CurrentUser'
 -in           Issuer's certificate common name.(eg: Fred Dews)
 -a       The signature's digest algorithm.
                        .  Default to 'sha1'
 -ip       Issuer's CryptoAPI provider's name
 -iy           Issuer's CryptoAPI provider's type
 -sp       Subject's CryptoAPI provider's name
 -sy           Subject's CryptoAPI provider's type
 -iky       Issuer key type
                        >.
 -sky       Subject key type
                        >.
 -l            Link to the policy information (such as a URL)
 -cy       Certificate types
                       
 -b      Start of the validity period; default to now.
 -m          The number of months for the cert validity period
 -e      End of validity period; defaults to 2039
 -h          Max height of the tree below this cert
 -len        Generated Key Length (Bits)
                        Default to '2048' for 'RSA' and '512' for 'DSS'
 -r                  Create a self signed certificate
 -nscp               Include Netscape client auth extension
 -crl                Generate a CRL instead of a certificate
 -eku ]>  Comma separated enhanced key usage OIDs
 -?                  Return a list of basic options
 -!                  Return a list of extended options
so Brock's:

makecert -r -pe -n "CN=%1" -b 01/01/2015 -e 01/01/2020 -eku 1.3.6.1.5.5.7.3.1 
-sky exchange -a sha256 -len 2048 -ss my -sr localMachine
-r = Self-signed
-pe =  Mark generated private key as exportable
-n =  Certificate subject X500 name
-b =  Start of the validity period
-e =  End of validity period
-eku = Comma separated enhanced key usage OID
-sky = Subject key type
-a = The signature's digest algorithm
-len = Generated Key Length (Bits)
-ss  = Subject's certificate store name that stores the output certificate
-sr =  Subject's certificate store location

I've never used the -eku option,

As per the other link:

makecert.exe -sky exchange -r -n "CN=your certificate's name" -pe -a sha256 
-len 2048 -ss My "your certificate's name.cer"

Enjoy!

ADFS : Change / update password

I'm a regular contributor to the forum for

And there was this post:

SharePoint 2010 ADFS Password Expired


which contained an interesting snippet about changing your password via an ADFS screen.

This was for Server 2012 R2 and the functionality is enabled via a hotfix - kb/3035025.

It is in Server 2016 (Technical Preview 2) by default.

As per the article - under "Endpoints" - enable the "/adfs/portal/updatepassword/" endpoint under "Other" and reset the ADFS service via Services.

Then navigate to:

https://adfs .../adfs/portal/updatepassword

and you'll see:


Neat!

Enjoy!