Nick's .NET Travels

Continually looking for the yellow brick road so I can catch me a wizard....

Why String Interpolation is a BAD thing

So I’ll set the scene – I was reviewing some code and refactoring it. First thing to do was to go through and take a look at the Resharper comments as they do a good job at tightening up sloppy code. In this instance I came across code that looked a bit like this:

var url = “http://someservice.com/”;
url += queryParameters;
DoSomething(url);

Of course, this can easily be refactored using string interpolation to

var url = $“http://someservice.com/{queryParameters}”;
DoSomething(url);

Which looks so much cleaner. Unfortunately this has actually just made my code even worse – I still have this horrible nasty string literal, now with embedded code. Argh, who does this stuff. Next step, factor the string out into a constants, or ideally configuration file.

private const string ServiceUrlTemplate = “http://someservice.com/{0}”;

and then:

var url = string.Format(Constants.ServiceUrlTemplate,queryParameters);
DoSomething(url);

I’m sure there are a ton of other ways to make this nicer and perhaps more readable but having a string literal with interpolation is not one of them.

Additional Note: If you’re not using Resharper or another equivalent tool, you’re not working effectively. Start using a refactoring tool today and don’t ignore the warnings. Spend time everyday reviewing and improving the code you write

Call out to the ADAL team! – Authenticate Using External Browser

In my post, Authorizing Access to Resources using Azure Active Directory, I talk about authenticating using the built in browser on the device, rather than authenticating via a webview, which is all too common. Unfortunately despite being fully supported by Azure Active Directory, the team responsible for ADAL haven’t, as far as I can tell, provided support for using an external browser to authenticate.

I was super impressed when I just downloaded the Facebook app on Windows, that it supports “Log in with Browser”.

image

In my opinion, this not only represents a more secure form of authentication (since I can validate the website I’m signing into), it is also a better experience, since I’m already logged into Facebook in the browser anyhow.

I definitely encourage developers to consider using the external browser, rather than supporting SDKs and libraries that us the in-app browser.

UseWindowsAzureActiveDirectoryBearerAuthentication v’s UseJwtBearerAuthentication for Authorization with Azure Active Directory for an ASP.NET Web API

In my previous post, Securing a Web API using Azure Active Directory and OWIN, I covered how to authorize requests against Azure Active Directory using the UseWindowsAzureActiveDirectoryBearerAuthentication extension method in the OWN startup class. This extension method has been designed specifically for Azure Active Directory but if you think about it, the Authorization token is just a JWT token, so in theory you could take a much more generic approach to authorizing access by validating the JWT. This can be done using the UseJwtBearerAuthentication extension method.

There are a couple of steps to using the UseJwtBearerAuthentication extension method. Firstly, in order to validate the signature of the JWT, we’re going to need the public certificate that matches the key identifier contained in the JWT. In my post on Verifying Azure Active Directory JWT Tokens I cover how to examine the JWT using https://jwt.io in order to retrieve the kid, retrieve the openid configuration, locate the jwks uri, retrieve the keys and save out the key as a certificate. In the post I used the certificate (ie wrapping the raw key in ---BEGIN---, ---END--- markers) to validate the JWT; in this case I’ve copied the contents into a text file which I’ve named azure.cer and added it to the root of my web project (making sure the build action is set to Content so it is deployed with the website).

The next thing to do is to remove the UseWindowsAzureActiveDirectoryBearerAuthentication extension method, replacing it with the following code.

var fileName = HostingEnvironment.MapPath("~/") + "azure.cer";
var cert = new X509Certificate2(fileName);
app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
{
    AllowedAudiences = new[] {ConfigurationManager.AppSettings["ida:Audience"]},
    IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
    {
        new X509CertificateSecurityTokenProvider(ConfigurationManager.AppSettings["ida:IssuerName"], cert)
    }
});

This code uses the azure.cer certificate file combined with the Audience and IssuerName which I’ve added to the web.config.

<add key="ida:Audience" value="a07aa09e-21b9-4e86-b269-a18903b5fe54" />
<add key="ida:IssuerName" value="https://sts.windows.net/55cc17b5-7d2a-418e-86a6-277c54462485/" />

The Audience is the application id (aka client id) of the Azure application registration. The IssuerName needs to match to what appears in the JWT. Opening one of the tokens in https://jwt.io it’s the ISS value that you want to use as the IssuerName.
image

Now you can run the project and see that again the requests are validated to ensure they’re correctly signed.

Securing a Web API using Azure Active Directory and OWIN

In this post we’re going to look at how to use Azure Active Directory to secure a web api built using ASP.NET (full framework – we’ll come back to .NET Core in a future post). To get started I’m going to create a very vanilla web project using Visual Studio 2017. At this point VS2017 is still in RC and so you’ll get slightly different behaviour than what you’ll get using the Visual Studio 2015 templates. In actual fact the VS2015 templates seem to provide more in the way of out of the box support for OWIN. I ran into issues recently when I hadn’t realised what VS2015 was adding for me behind the scenes, so in this post I’ll endeavour not to assume anything or skip any steps along the way.

image

After creating the project, the first thing I always to is to run it and make sure the project has been correctly created from the template. In the case of a web application, I also take note of the startup url, in this case http://localhost:39063/. However, at this point I also realised that I should do the rest of this post following some semblance of best practice and do everything over SSL. Luckily, recent enhancements to IIS Express makes it simple to configure and support SSL with minimal fuss. In fact, all you need to do is select the web project node and press F4 (note, going to Properties in the shortcut menu brings up the main project properties pane, which is not what you’re after) to bring up the Properties window. At the bottom of the list of properties is the SSL Enabled and SSL URL, which is https://localhost:44331/. Take note of this url as we’ll need it in a minute.

image

To setup the Web API in order to authorize requests, I’m going to create a new application registration in Azure Active Directory. This time I need to select Web app / API from the Application Type dropdown. I’ll give it a Name (that will be shown in the Azure portal and when signing into use this resource) and I’ll enter the SSL address as the Sign-on URL. This URL will also be listed as one of the redirect URIs used during the sign in process. During debugging you can opt to do this over HTTP but I would discourage this as it’s no longer required.

image

After creating the application, take note of the Application Id of the newly created application. This is often referred to as the client id and will be used when authenticating a user for access to the web api.

Application Id (aka Client Id): a07aa09e-21b9-4e86-b269-a18903b5fe54

We’re done for the moment with Azure Active Directory, let’s turn to the web application we recently created. The authorization process for in-bound requests involves extracting the Authorization header and processing the bearer token to determine if the calling party should have access to the services. In order to do this for tokens issues by Azure AD I’ll add references to both the Microsoft.Own.Security.ActiveDirectory and Microsoft.Own.Host.SystemWeb packages.

image

Note: Adding these references takes a while! Make sure they’re completely finished before attempting to continue.

Depending on the project template, you may, or may not, already have a Startup.cs file in your project. If you don’t, add a new item based on the OWIN Startup class template

image

The code for this class should be kept relatively simple:

[assembly: OwinStartup(typeof(SampleWebApp.Startup))]
namespace SampleWebApp
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            ConfigureAuth(app);
        }
    }
}

Additionally, you’ll want to add another partial class file Startup.Auth.cs in the App_Start folder.

namespace SampleWebApp
{
    public partial class Startup
    {
        public void ConfigureAuth(IAppBuilder app)
        {
        }
    }
}

And now we get to adding the middleware that will be used to process the authorization header

public void ConfigureAuth(IAppBuilder app)
{
    app.UseWindowsAzureActiveDirectoryBearerAuthentication(
        new WindowsAzureActiveDirectoryBearerAuthenticationOptions
        {
             Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
             TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
             {
                 ValidAudience = ConfigurationManager.AppSettings["ida:Audience"]
             }
        });
}

This uses the configuration manager to extract the Tenant and Audience settings from the web.config (and subsequently the Azure portal settings when you publish to the cloud):

<add key="ida:Audience" value="a07aa09e-21b9-4e86-b269-a18903b5fe54" />
<add key="ida:Tenant" value="nicksdemodir.onmicrosoft.com" />

The tenant is the Id, or in this case, the domain of the tenant where the application is registered. The Audience is the application Id of the application registered in Azure AD.

Warning: If you run the application now and get an error relating to a missing type, you may have to revert the Microsoft.Owin.Security.ActiveDirectory to the most recent v4 package. At the time of writing this post there seems to be an incompatibility between v5 and Owin.

Reference to type 'TokenValidationParameters' claims it is defined in 'System.IdentityModel.Tokens.Jwt', but it could not be found

Ok, we’re ready to try making requests. I’m going to use Fiddler but you can use any other tool that’s able to generate and send HTTP requests. The first attempt will be a GET request to https://localhost:44331/api/values which is one of the default controllers that was created from the project template. Depending on what your project template included, the valuescontroller may, or may not, have the Authorize attribute applied to it. If, like me, you didn’t have the Authorize attribute applied to the valuecontroller, you should get a valid response back to your HTTP request. In this case, you’re going to want to add security to the valuecontroller by adding the Authorize attributes:

[Authorize]
public class ValuesController : ApiController
{

Now, try making the request again – you should now get a 401 Unauthorized error. The body of the response should say:

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

Clearly this is the case since we didn’t send the Authorization header. This time, let’s add an Authorization header, with the word “Bearer” and a token consisting of random text:

Authorization: Bearer abcdefg

This should generate the same response. However, let’s start to look into this further. To get more diagnostic information, add the following to the web.config file for the project

<system.diagnostics>
  <switches>
    <add name="Microsoft.Owin" value="Verbose" />
  </switches>
</system.diagnostics>

Now when you make the request you should see more diagnostic information in the Output window in Visual Studio:

Microsoft.Owin.Security.OAuth.OAuthBearerAuthenticationMiddleware Error: 0 : Authentication failed
System.ArgumentException: IDX10708: 'System.IdentityModel.Tokens.JwtSecurityTokenHandler' cannot read this string: 'abcdefg’.
The string needs to be in compact JSON format, which is of the form: '<Base64UrlEncodedHeader>.<Base64UrlEncodedPayload>.<OPTIONAL, Base64UrlEncodedSignature>'.

As we should have predicted, the token we passed in isn’t a value Jwt – it’s not even valid JSON. Let’s fix this by generating an actual access token for this Web API. In a previous post I walked through manually the process of authenticating, retrieving an authorization code and then exchanging it for an access token. I’ll do the same here.

First I’m going to launch an authorization url in the browser and sign in using credentials from the nicksdemodir.onmicrosoft.com tenant:

https://login.microsoftonline.com/nicksdemodir.onmicrosoft.com/oauth2/authorize?client_id=a07aa09e-21b9-4e86-b269-a18903b5fe54&response_type=code&redirect_uri=https://localhost:44331/

The authorization url is made up of various components:

nicksdemodir.onmicrosoft.com – This is the domain name of the tenant where the web application is registered with Azure AD. You can also use the tenant Id (guid format)

a07aa09e-21b9-4e86-b269-a18903b5fe54 – This is the application id of the application registration in Azure AD

code – This indicates that the response should be an authorization code

https://localhost:44331/  - This is the uri that the browser will be redirected back to, passing with it the code in the query string.

Make sure you have the web application running, otherwise the redirect uri won’t resolve at it may be hard to extract the code from the query string (depending on the browser). After signing in, you’ll be redirected back to your web application with a URL similar to (the code has been shortened for brevity):

https://localhost:44331/?code=zvrs_zz0…….05B_ggAA&session_state=ef2986b8-75bd-484a-b9b9-68f0e46ab569

The next thing to do is to prepare a POST request in your http tool of choice with the following:

URL: https://login.microsoftonline.com/nicksdemodir.onmicrosoft.com/oauth2/token

Body: grant_type=authorization_code&client_id=a07aa09e-21b9-4e86-b269-a18903b5fe54&client_secret=c06kP0Q9ENGpZGbiZTqB1QQaZUWNe190mCittRMr&redirect_uri=https://localhost:44331/&code=zvrs_zz0…….05B_ggAA&resource=a07aa09e-21b9-4e86-b269-a18903b5fe54

The Body parameters are broken down as:

a07aa09e-21b9-4e86-b269-a18903b5fe54 – This is the application id of the application registration in Azure AD. It’s required as both the client_id and the resource, since we’re using the access token to access the web application itself.

c06kP0Q9ENGpZGbiZTqB1QQaZUWNe190mCittRMr – This is a private key (aka client secret) issued by the Azure AD application to ensure the security of token requests. I’ll come back to this in a second and show how to create one for your application.

https://localhost:44331/ – The redirect uri for the application – required here to verify the calling party as it has to align with what’s in Azure AD

zvrs_zz0…….05B_ggAA – This is the authorization code returned in the previous step

To generate the client secret in Azure AD simply click on the Keys tab within the details of the application registration. You can then create a new key by entering a description. The description is only seen by you, so give it a name that’s meaningful to you. Note that once you save the new key, you will only be shown the value of the key once. Once you leave the page, the value of the key will never been shown again.

image

The key created in the Azure AD should be used as the client secret when doing the authorization code to access token exchange.

The response to this POST should return JSON which includes and access token value. Add the access token to the authorization header:

Authorization: Bearer G1ZsPGjPF6qJO8Sd5HctnKqNk_8KDc-………Lpy9P8sDWdECziihaPWyseug9hgD119keoZuh4B

This should give you a 200 response with data. And there you have it – you’ve successfully secured your web api so that it requires the user to be authenticated using Azure Active Directory.

Making your Azure Active Directory application Multi-tenanted

So far in my previous posts I’ve discussed signing into an application using Azure Active Directory (Azure AD) using a basic application registration in Azure AD. Last post we added some additional permissions that required administrator consent. However, up until now, only users in the same directory (aka tenant) that the application is registered in, can sign in. In the case of the sample application I’ve been working with, the application is registered to the nicksdemodir.onmicrosoft.com tenant, so only users belonging to that tenant can sign in eg admin@nicksdemodir.onmicrosoft.com. If I attempt to sign in with an account from a different tenant, I run into a few issues, and depending on what type of account I sign in with, the error that is displayed varies.

I’ll start by signing in with a regular user account that belongs to a different tenant (in this case btro365dev.onmicrosoft.com). When I attempt to sign in with this account, everything seems to go well – I’m prompted to sign in; I successfully sign in; I’m returned to the application where the code is exchanged for an access token. However, when I attempt to use this access token I get a rather cryptic error about an “Unsupported token” eg:

{"odata.error":{"code":"Request_BadRequest","message":{"lang":"en","value":"Unsupported token. Unable to initialize the authorization context."},"requestId":"86481ea2-79bd-461b-93ad-4f649286617a","date":"2017-01-25T21:28:14"}}

This is actually less cryptic than it seems – essentially it’s saying that I’m attempting to present a token that the API can’t process. If you were to open the access token in https://jwt.io, you’d see that the token has been issued by the nicksdemodir.onmicrosoft.com tenant (actually you’d see the STS url that correlates to this tenant) for an account that doesn’t exist in that tenant (eg testuser@btro365dev.onmicrosoft.com). Whilst this is a legitimate access token, when you present it to the Graph API, it attempts to retrieve information about the user in the issuing tenant, which of course fails, since the user doesn’t exist there.

Ok, let’s see what happens if I attempt to launch the admin consent prompt. In this case, after I sign in (now using admin@btro365dev.onmicrosoft.com which is a global administrator) I get a more useful error message saying “AADSTS50020: User account … does not exist in tenant”.

image

The reason this error message is useful is that it prompts me to think about what I’m attempting to do – I’ve been prompting the user to sign into the nicksdemodir.onmicrosoft.com tenant, which is fine if I’m a user that belongs to that tenant but since I’m attempting to use a different user, this is clearly not correct. So, the first step in making my application multi-tenanted is to change the authorization url that I’m directing the user to in order to sign in, to one that is more generic and will allow signing in by users from any tenant. This involves exchanging the “nicksdemodir.onmicrosoft.com” with “common” in the url – the following code shows how I adapted the code in my sample application to support urls that are single tenanted (ie AuthorizationUrl and AdminConsentUrl) as well as the multi-tenanted equivalent (ie MultiTenantAuthorizationUrl and MultiTenantAdminConsentUrl).

private string BaseAuthorizationUrl =>
    "
https://login.microsoftonline.com/{0}/oauth2/authorize?" +
    "client_id=40dba662-4c53-4154-a5cf-976473306060&" +
    "response_type=code&" +
    "redirect_uri=sample://callback&" +
    "nonce=1234&" +
    "resource=
https://graph.windows.net";

private string AuthorizationUrl => string.Format(BaseAuthorizationUrl, "nicksdemodir.onmicrosoft.com");

private string AdminConsentUrl => $"{AuthorizationUrl}&prompt=admin_consent";
private string MultiTenantAuthorizationUrl => string.Format(BaseAuthorizationUrl, "common");
private string MultiTenantAdminConsentUrl => $"{MultiTenantAuthorizationUrl}&prompt=admin_consent";

For example:

Authorization url: https://login.microsoftonline.com/nicksdemodir.onmicrosoft.com/oauth2/authorize?client_id=40dba662-4c53-4154-a5cf-976473306060&response_type=code&redirect_uri=sample://callback&nonce=1234&resource=https://graph.windows.net

Multi-tenant authorization url: https://login.microsoftonline.com/common/oauth2/authorize?client_id=40dba662-4c53-4154-a5cf-976473306060&response_type=code&redirect_uri=sample://callback&nonce=1234&resource=https://graph.windows.net

Attempting to sign in using the multi-tenant authorization url with an account that doesn’t belong to the nicksdemodir.onmicrosoft.com tenat now yields the following error:

image

This error seems to be correct, considering the application registration exists in the nicksdemodir.onmicrosoft.com tenant. Unfortunately it’s not very clear what you need to do in order to fix this issue – you can’t add the application to the btro365dev.onmicrosoft.com tenant, and even if you could, you wouldn’t want to have to manually do that for every tenant that you want to support. Luckily, there is a mechanism that allows Azure AD to essentially add the application to new tenants on an as required basis (similar to how applications are added to a users list of applications at https://myapps.microsoft.com as they consent to use of the application). In order for Azure AD to do this, the application registration has to be configured to support multiple tenants. Click on the Manifest button for the application registration in Azure AD – the property “availableToOtherTenants” should be set to true (default is false).

image

Now when we attempt to sign in (again with a non-global administrator user) we see a familiar error saying that the calling principal (ie the signed in user) doesn’t have permissions.

image

We know how to fix this from my previous post, the only difference is that we need to direct the user to the multi-tenant admin consent url eg

https://login.microsoftonline.com/common/oauth2/authorize?client_id=40dba662-4c53-4154-a5cf-976473306060&response_type=code&redirect_uri=sample://callback&nonce=1234&resource=https://graph.windows.net&prompt=admin_consent

The global administrator, after signing in, will again see the admin consent prompt – it’s worth pointing out here that it lists both the directory the user is signed into (ie BTR Office Dev – btro365dev.onmicrosoft.com) and the tenant that the application is published (ie registered) in (ie DemoDirectory – nicksdemodir.onmicrosoft.com).

image

Again, consenting will enable all users in the foreign tenant (ie btro365dev.onmicrosoft.com) to then access the application via the multi-tenant authorization url.

There is one last adjustment that has to be made, and that’s to the Token url. When exchanging the code for an access token, it’s important that the token url is also adjusted to be either single or multi-tenant. Previously the url included the tenant that the application was registered to ie nicksdemodir.onmicrosoft.com. This needs to be changed in the multi-tenant scenario to use “common”. In order to allow authorization to occur for both single and multi-tenant scenarios within the application, I needed a way to dynamically control the token url based on whether the user signed in via the single tenant or multi-tenant authorization url. Currently, all we get back when the user has signed in is a code which we need to exchange for an access token. Luckily, we can pass an additional parameter, “state,” into the authorization url, which will get passed back to the application along with the code – we can use this to determine which authorization url was used. I’m only going to adjust the multi-tenant authorization url as the application will treat the lack of state parameter to mean that the user was directed to the single tenant authorization url.

private string MultiTenantAuthorizationUrl => string.Format(BaseAuthorizationUrl, "common") + "&state=multi";
private string MultiTenantAdminConsentUrl => $"{MultiTenantAuthorizationUrl}&prompt=admin_consent";

Now, the token url is updated based on the state parameter value:

private string BaseTokenUrl => "https://login.microsoftonline.com/{0}/oauth2/token";
private string TokenUrl(bool isMulti)
{
    return string.Format(BaseTokenUrl, isMulti ? "common" : "nicksdemodir.onmicrosoft.com");
}

var isMulti = uri?
                    .Split('?').Skip(1).FirstOrDefault()?
                    .Split('&').Select(q => q.Split('='))
                    .Where(x => x.Length == 2 && x[0] == "state")
                    .Select(x => x[1])
                    .FirstOrDefault() == "multi";

var tokenUrl = TokenUrl(isMulti);

And that’s it – a user can sign in from any tenant (assuming the global administrator has signed in an consented) and retrieve information from the Azure Graph API.

Admin Consent for Permissions in Azure Active Directory

In the previous posts I’ve discussed authenticating and authorizing a user with Azure Active Directory (Azure AD) using a basic application registration. All application registrations are given default permissions to access the Azure Graph API – this was used in my previous post to retrieve information about the signed in user. The default permission set is a delegated permission that allows the user to sign in and view their own profile. This can be viewed in the Azure portal by extending the Required permissions tab for the application.

image

In this post I’m going to extend this permission set to include the “Read directory data” permission. You’ll notice in the previous image that there is a green tick in the “Requires Admin” column. What this means is that in order for a regular user (ie a user that is not a global administrator for the tenant) to sign in, a global administrator must first sign in and consent to permission on behalf of the organisation. If a regular user attempts to sign in, they’ll be confronted with an error message such as:

image 

Essentially the error “AADSTS90093: Calling principal cannot consent due to lack of permissions” indicates that a global administrator needs to sign in an consent on behalf of the organisation before users can sign in. If a global administrator signs in, they’ll see a prompt where they can consent permissions – this is slightly confusing as it would imply that the administrator is consenting on behalf of the organisation. Unfortunately this is not the case, they’re only consenting for use by their account.

image

In order for a global administrator to consent on behalf of an organisation, so that all users can make use of the “admin consent” permissions, they have to be directed to a new sign in page with the parameter “prompt=admin_consent” set in the query. In other words, the admin consent url is exactly the same as the authorization url, except it has “&prompt=admin_consent” appended to the end.

https://login.microsoftonline.com/nicksdemodir.onmicrosoft.com/oauth2/authorize?client_id=40dba662-4c53-4154-a5cf-976473306060&response_type=code&redirect_uri=sample://callback&nonce=1234&resource=https://graph.windows.net&prompt=admin_consent

The admin consent prompt looks slightly different to a regular consent prompt as it highlights that consent is going to be assigned for the entire organisation

image

As this is a one-off operation, a global administrator can either navigate to the url in the browser, or the application can have a separate button that would launch the url so that the admin can consent. After the global administrator has consented, user’s will still be prompted to consent but this is for the delegated permission. In the same way that user permissions can be revoked by going to https://myapps.microsoft.com and deleting the application entry, organisation permissions can be revoked by opening the Enterprise applications tab for the Active Directory in the Azure portal. Select the application you want to remove and click the Delete button.

image

After the global administrator has consented for the organisation, any user can then read the directory data (ie more than just their own profile).

Verifying Azure Active Directory JWT Tokens

When working with OAuth and Open ID Connect, there are times when you’ll want to inspect the contents of id, access or refresh tokens. The website https://jwt.io is useful as you can drop in the token in the pane on the left, and the site dynamically decodes the header, body and signature for the JWT.

image

Unfortunately by itself the signature on the JWT can’t be verified as the website doesn’t know what key to use to validate the signature. The header of the JWT does provide information about the algorithm used (ie RS256) and the id of the key used but this by itself isn’t enough to locate the key to be used.

image

As RS256 is a public/private key algorithm, there is a private key, which the issuer holds, and a public key which is available to anyone to access. The former is used to generate the signature for a JWT; the later can then be used to validate the signature. To find the public key to use to validate the signature I’ll start with the OpenID Connect configuration document, which is available for any tenant at:

https://login.microsoftonline.com/{tenantId}/.well-known/openid-configuration

eg https://login.microsoftonline.com/nicksdemodir.onmicrosoft.com/.well-known/openid-configuration

The returned configuration document contains an attribute, jwks_uri, which points at https://login.microsoftonline.com/common/discovery/keys

image

Loading the jwks_uri returns another JSON document which lists a number of keys. Now we can use the kid from the header of the JWT to identify which key to use, in this case the first key in the list.

image

Attempting to simply copy the x5c value from the list of keys into the Public Key or Certificate box on the jwt.io website will still not verify the signature of the JWT. In order to verify the signature, wrap the key in BEGIN and END CERTIFICATE markers as follows:

-----BEGIN CERTIFICATE-----
MIIDBTCCAe2gAwIBAgIQEsuEXXy6BbJCK3bMU6GZ/TANBgkqhkiG9w0BAQsFADAtMSswKQYDVQQDEyJhY2NvdW50cy5hY2Nlc3Njb250cm9sLndpbmRvd3MubmV0MB4XDTE2MTEyNjAwMDAwMFoXDTE4MTEyNzAwMDAwMFowLTErMCkGA1UEAxMiYWNjb3VudHMuYWNjZXNzY29udHJvbC53aW5kb3dzLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKd6Sq5aJ/zYB8AbWpQWNn+zcnadhcMYezFvPm85NH4VQohTm+FMo3IIJl6JASPSK13m9er3jgPXZuDkdrEDHsF+QMEvqmffS2wHh3tKzasw4U0jRTYB0HSCbmnw9HpUnv/UJ0X/athO2GRmL+KA2eSGmb4+5oOQCQ+qbaRXic/RkAOLIw1z63kRneLwduQMsFNJ8FZbWkQFj3TtF5SL13P2s/0PnrqwGD59zcbDu9oHOtciu0h++YhF5CWdWEIgafcZk9m+8eY12BKamvPdBnyfpz6GVTenJQe2M+AGz5RSNshvI976VUbBiaIeNzvzaG91m62kFWLRqE3igq6D02ECAwEAAaMhMB8wHQYDVR0OBBYEFAgoZ9HLgFxH2VFGP6PGc4nFizD2MA0GCSqGSIb3DQEBCwUAA4IBAQBSFXalwSJP/jihg04oJUMV2MTbuWtuFhdrdXiIye+UNc/RX02Q9rxd46BfGeKEBflUgNfEHgyEiWTSLAOSDK70vu+ceCVQCGIQPjnGyYOpm80qAj/DNWZujVcSTTV3KZjMFsBVP7miQowfJQ58u9h8yuJHNhPpB2vOFmNhm4uZq3ve529Xt51HdtQGG9+Z9n1DhObqzkbz8xEFjA+KdfcRsZXa14ZkpAOe35VgyY0f8x34Y0LPfibWcNpfp0AhxKzyqT1GRRlKTjiBA6WNJIJIEeqh/nfOnwM0UQKRnt+2qeV3u00a5lrvJtEy7nq+s7xYtpVAsCvn5T0U1/8IHkxt
-----END CERTIFICATE-----

Entering the wrapped key into the Public Key or Certificate box on the jwt.io website will successfully verify the signature of the JWT.

image

Authorizing Access to Resources using Azure Active Directory

In my previous post I discussed authenticating a user using Azure Active Directory (Azure AD), returning an id_token that can be used to identify the user that has signed in. However, this token isn’t an access token and as such can’t be presented in order to access remote services. In this post I’m going to show how you can request an access token that can be presented in the Authorization header when calling a service. The workflow is very similar to the workflow to retrieve the id_token:

- User attempts to sign into an application

- Application launches the Authorize URL in an external browser (includes “resource” parameter in Authorize URL)

- User is directed to a Microsoft URL where they are prompted to sign in

- User signs in

- User is prompted to consent that the application can access the specified resource

- After sign in, the User is redirected back to the application via a custom protocol

- Application receives an authorization code

- Application performs a POST request to the Token URL in order to exchange authorization code for an access token

- Application receives the access token

- Application makes call to remote service, attaching the access token in the Authorization header

To demonstrate this workflow I’m going to adapt the sample application I created in my previous post in order to access the Azure Graph API. The sample application is already configured with access to the Azure Graph API – this is done by default for all application registrations. In order to request access to a resource, you need to know the url of the resource you want to access. In this case the url for the Azure Graph API is https://graph.windows.net.

In addition to including the resource url in the authorization url, the other change I need to make is to switch the response type from id_token to code. The updated authorization url is:

var  authorizationUrl=
    "https://login.microsoftonline.com/nicksdemodir.onmicrosoft.com/oauth2/authorize?" +
    "client_id=40dba662-4c53-4154-a5cf-976473306060&" +
    "response_type=code&" +
    "redirect_uri=sample://callback&" +
    "nonce=1234&" +
    "resource=https://graph.windows.net";

Launching this url in the external browser will again prompt the user to sign in (unless they have previously signed in for this application, such as if you followed my previous post) but rather than immediately being redirected back to the application, the user will see a consent prompt – you’ll note that similar to the sign in prompt, the name of the application specified in Azure AD is used when requesting permissions.

image

The other thing to note is that once you’ve consented permissions for the application, you won’t be prompted again – Azure AD remembers that you’ve granted permissions. Permissions can be revoked by going to https://myapps.microsoft.com, selecting the application and clicking Remove.

image

The same “Remove” option is available if you turn on the new look (it’s the same url to get there – https://myapps.microsoft.com)

image

After completing the sign in and consent workflow, the user is navigated back to the application using the custom protocol. This time, instead of an id_token, the application receives a code as part of the url:

sample://callback/?code=AQABAAAAAADRN…….L7YiQ7PIAA&session_state=ffffd83b-3820-489e-9f35-70e97d58fd04

Unlike the id_token, and as you’ll see soon, the access_token, the code is not a jwt token that you can interrogate for information about the signed in user. Instead the next step in the process is to do the code-token exchange to retrieve the required access token. This involves doing a POST request to the Token URL, passing parameters in the body of the request.

Token URL: https://login.microsoftonline.com/{tenantId}/oauth2/token

eg https://login.microsoftonline.com/nicksdemodir.onmicrosoft.com/oauth2/token

The POST body needs to contain the following values:

var postBody = new Dictionary<string, string>
{
    {"grant_type", "authorization_code"},
    {"client_id", "40dba662-4c53-4154-a5cf-976473306060"},
    {"redirect_uri", "sample://callback"},
    {"resource", "https://graph.windows.net"},
    {"code", code}
};

40dba662-4c53-4154-a5cf-976473306060 – This is the client id (aka application id) of the application registration in Azure AD

sample://callback – This is the redirect uri specified in the application registration

https://graph.windows.net – This is the resource that you’re requesting an access token for. Make sure this is the URL for the Azure Graph API, not to be confused with the Microsoft Graph API (https://graph.microsoft.com)

code – This is the actual code that is returned from the sign in process (ie don’t use the word “code”)

The resulting code for parsing the code from the application redirect, and then exchange for an access token is as follows:

protected override async void OnActivated(IActivatedEventArgs args)
{
    base.OnActivated(args);
    if (args.Kind == ActivationKind.Protocol)
    {
        var eventArgs = args as ProtocolActivatedEventArgs;

        var uri = eventArgs.Uri.AbsoluteUri;
        var code = uri?
                    .Split('?').Skip(1).FirstOrDefault()?
                    .Split('&').Select(q => q.Split('='))
                            .Where(x=>x.Length==2 && x[0]=="code")
                            .Select(x=>x[1])
                            .FirstOrDefault();

        var tokenUrl = "https://login.microsoftonline.com/nicksdemodir.onmicrosoft.com/oauth2/token";
        var postBody = new Dictionary<string, string>
        {
            {"grant_type", "authorization_code"},
            {"client_id", "40dba662-4c53-4154-a5cf-976473306060"},
            //{"redirect_uri", "sample://callback"},
            {"resource", "
https://graph.windows.net"},
            {"code", code}
        };
        using (var client = new HttpClient())
        {
            var content = new FormUrlEncodedContent(postBody);
            var result = await client.PostAsync(tokenUrl, content);
            var resultContent = await result.Content.ReadAsStringAsync();
        }
    }
}

The resultContent variable will include a JSON string which consists of an access_token, refresh_token etc.

image

In order to extract the access_token, the resultContent can be deserialized to an entity:

public class TokenData
{
    public string expires_in { get; set; }
    public string access_token { get; set; }
    public string refresh_token { get; set; }
    public string id_token { get; set; }
}

var resultContent = await result.Content.ReadAsStringAsync();
var token =  JsonConvert.DeserializeObject<TokenData>(resultContent);

Finally, the token.access_token value can be used to make a call to the Azure Graph API:

var graphUri = "https://graph.windows.net/me?api-version=1.6";
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",token.access_token);
var graphProfile = await client.GetStringAsync(graphUri);

The following screenshot shows the resulting profile information that’s returned from the Graph API

image

Note that the access token is relatively short lived. The refresh token can be used to renew the access token or to retrieve an access token for an alternative resource.

Authenticating an Application using Azure Active Directory

In my previous post I discussed in brief the use of the OAuth Authorization Code workflow and the corresponding endpoints. As a brief recap, the workflow I’ll going to walk through is the following:

- User attempts to sign into an application

- Application launches the Authorize URL in an external browser

- User is directed to a Microsoft URL where they are prompted to sign in

- User signs in

- After sign in, the User is redirected back to the application via a custom protocol

- Application receives the token containing information about the user that has signed in

In this walk through I’ll use a UWP application but the workflow works well for any platform that supports custom protocol. Before I get started I’m going to need a few things:

Authorize URL - https://login.microsoftonline.com/{tenantId}/oauth2/authorize
Tenant Id - nicksdemodir.onmicrosoft.com (this can also be specified as a guid)

Next, I’m going to register an application with Azure Active Directory (Azure AD). You can think of this registration as identifying the application that is going to connect to Azure AD. In the Azure portal, open the Active Directory management pane and select App registrations

image

At the top of the app registrations pane, click the Add button. In the Create form I’ll give the application registration a name (the name is used both in the Azure portal as well as on the sign in page when a user is signing into the application). The application type needs to be set to Native – this allows the application to exchange an Authorization Code for an Access Token without having to provide a client secret.

image

The final property is the Redirect URI, which is the URL that the browser will be directed to after the user has signed in. In this case I’m specifying a custom protocol which will be used to redirect back to the application. Once the application registration is complete I can copy the Application Id from the application pane.

image

I have all the information I need in order to authenticate a user; all I need to do is form the authorization url that will be launched in the external browser:

private async void AuthenticateClick(object sender, RoutedEventArgs e)
{
    var  authorizationUrl=
        "
https://login.microsoftonline.com/nicksdemodir.onmicrosoft.com/oauth2/authorize?" +
        "client_id=40dba662-4c53-4154-a5cf-976473306060&" +
        "response_type=id_token&" +
        "redirect_uri=sample%3A%2F%2Fcallback&" +
        "nonce=1234";
    await Launcher.LaunchUriAsync(new Uri(authorizationUrl));
}

There are various components to the authorization url:

nicksdemodir.onmicrosoft.com – The tenant where the application is registered. Alternatively use “common” for multi-tenanted applications.

0dba662-4c53-4154-a5cf-976473306060 – This is the Application ID (also referred to as the client ID) of the application registration in Azure AD

id_token – This is the requested response, which in this case is a JWT token that represents information about the user. When using OAuth to authorize access to a resource, either specify “code” or “code id_token”.

sample://callback – This is the url that the browser will be redirected to after the sign in process has been completed.

1234 – This is a application specific nonce which can be used to ensure the returned token matches the authentication request from the application.

In order for the user to be redirected back to the UWP application the “sample” custom protocol needs to be registered to the application. For a UWP application this is done by adding the following XML to the package.appxmanifest, immediately after the closing VisualElements tag.

<Extensions>
  <uap:Extension Category="windows.protocol">
    <uap:Protocol Name="sample">
      <uap:Logo>assets\StoreLogo.png</uap:Logo>
      <uap:DisplayName>Sample</uap:DisplayName>
    </uap:Protocol>
  </uap:Extension>
</Extensions>

In the App.xaml.cs file for the application, the OnActivated method needs to be overridden. This method will be invoked when the user is switched back to the application after signing in. The args property can be interrogated in order to retrieve the id_token that has information about the authenticated user.

image

The site http://jwt.io can be used to pull apart the id_token which shows the name of the user that’s signed in. It also shows the nonce which the application can match with the nonce specified in the authentication request.

image

In this post I’ve shown how you can use Azure Active Directory to authenticate a user. Note however, this is not enough to authorize a user for access to any resources. In the next post I’ll walk through using OAuth to authorize user access to a resource.

Azure Active Directory and Google OAuth 2.0 Endpoints

There are a lot of arguments for and against using pre-built SDKs for doing OAuth authentication with Azure AD and Google. Having worked with the ADAL library for Azure quite a bit I think the team have done a reasonable job, especially considering it now works across the three mobile platforms (iOS, Android and Windows), and works with a PCL that is .NET Standard based. However, using any library does force you into working within the bounds of the library. For example, we recently found two shortcomings in the library:

- It doesn’t provide a good solution for doing a browser based workflow for signing in – instead it uses a webview hosted within the context of the application (depending on the platform this may be augmented with more security, for example the Web Authentication Broker - https://msdn.microsoft.com/en-us/library/windows/apps/windows.security.authentication.web.webauthenticationbroker.aspx). A browser based workflow involves launching the external browser for the user to sign in; upon successful sign on, the user is redirected back to the app.

- It doesn’t provide a mechanism to clear cached credentials. Whilst the tokens can be cleared, this doesn’t clear the cookies held within the hosted webview, which can lead to issues if the application is multi-tenanted.

If the provided libraries don’t align with what you want, you may have to roll your own solution. The Authorization Code workflow requires two endpoints:

- Authorize URL – this is the URL that you navigate the user to in order for them to sign into your application. After signing in an Authorization Code is returned to the application

- Token URL – this is the URL that the application does a POST request to in order to convert the Authorization Code into an access token.

For Azure Active Directory, these endpoints are:

Authorize - https://login.microsoftonline.com/{tenantId}/oauth2/authorize

Token - https://login.microsoftonline.com/{tenantId}/oauth2/token

For Google, these endpoints are:

Authorize - https://accounts.google.com/o/oauth2/v2/auth

Token - https://www.googleapis.com/oauth2/v4/token

As both services conform to OAuth/OpenID Connect, the parameters are the same, although there are some variations on the values that you need to supply for scope and client id.

Useful OAuth, OpenID Connect, Azure Active Directory and Google Authentication Links

Over the past couple of weeks I’ve been assisting with the development work of an enterprise system that uses both Azure Active Directory (Azure AD) and Google to authenticate users. It’s a cross platform solution which means we need code that works across both authentication platforms, and the three mobile platforms. Unfortunately this is easier said than done – The Azure AD team have done a reasonable job with the ADAL library but it’s not like we can repurpose that library for authenticating against Google. This is a tad annoying since both Azure AD and Google both use OAuth and OpenID Connect, so you’d expect there to be a good library that would work across both.

In trying to find a workable solution I can across a number of links that I want to bookmark here for future reference:

OAuth 2

Home - https://oauth.net/2/

The OAuth home page is a good starting point if you want to get more links and information about OAuth (1 and 2) but I actually found it’s main use for me was to point at the OAuth 2.0 Framework RFC

OAuth 2.0 Framework RFC - https://tools.ietf.org/html/rfc6749

You can think of the OAuth 2.0 Framework RFC as being the specification for OAuth 2.0. There are some extensions and other standards that relate to OAuth 2.0 but this is a must read if you want to understand what OAuth 2.0 is all about. You may need to refer back to this when reading other blogs/tutorials as it can help clarify what each of the roles and responsibilities are in the process.

Simple overview of OAuth 2 - https://aaronparecki.com/2012/07/29/2/oauth2-simplified

This overview provides a quick summary of the various flows for OAuth 2.0. However, I disagree with the use of the implicit workflow for mobile applications. Whilst mobile applications are not “trusted,” which would normally imply the use of the implicit workflow, the reality is that the implicit workflow can’t issue refresh tokens. This means that unless you want your users to have to log in each time they use your mobile application, you need to use the Authorization Code workflow (the client secret shouldn’t be required when requesting access tokens for mobile apps – this depends on which authentication provider you’re using).

 

OpenID Connect

Home - http://openid.net/connect/

The OpenID Connect home page is again a good starting point as it links to the many different parts of the OpenID Connect standard. OpenID Connect builds on top of OAuth 2.0 in order to provide a mechanism for users to be authenticated as well as authorized for resource access. In addition to the creation of access tokens, OpenID Connect defines an id_token which can be issued in absence of any resource that is just used to identify the user that has authenticated.

OpenID Connect Core 1.0 - http://openid.net/specs/openid-connect-core-1_0.html

This is the core specification of OpenID Connect. Similar to the specification for OAuth, this is worth both a read and to be used as a reference when working with OpenID Connect implementations.

OpenID Connect Session Management 1.0 - http://openid.net/specs/openid-connect-session-1_0.html

Whilst still in draft this standard covers how implementers are supposed to handle log out scenarios, which is useful as your application can’t simply delete it’s access tokens when a user opts to log out. Ideally when a user logs out, you’d want to make sure both cached tokens are cleared, along with invalidating any access or refresh tokens.

 

Google

OAuth 2.0 Overview - https://developers.google.com/identity/protocols/OAuth2

OpenID Connect - https://developers.google.com/identity/protocols/OpenIDConnect

Google’s documentation isn’t too bad but does require you to read all of the pages as the OAuth and OpenID Connect implementation details seem to be scattered across the pages. The assumption is that for any given type of application you can simply read the one page – unfortunately, if you want to get an understanding of the Google implementation, you really need to read everything. Authenticating/authorizing with Google is significantly simpler than with Azure AD as there is no notion of linking your application registration with specific permissions to other applications registered with Azure AD. This is a significant limitation of using Google sign in, as you can really only use it to authenticate and then use the token to access various Google APIs.

 

Azure Active Directory

Azure AD Developer’s Guide - https://docs.microsoft.com/en-au/azure/active-directory/develop/active-directory-developers-guide

Authentication Scenarios for Azure AD - https://docs.microsoft.com/en-au/azure/active-directory/develop/active-directory-authentication-scenarios

Azure AD is a much longer read, and it’s very easy to get lost in the world of application configuration and settings. My recommendation is to start with something simple, and then grow from that. For examples, start by authenticating a use to sign into your mobile app, then extend it so that you can use the access token to connect to a Web API, and then on to retrieve information from other Microsoft services within the Web API, and then perhaps make it all multi-tenanted (that’s one for another post!).

NuGet does my head in….. No thanks to Xamarin.Forms

This is a bit of a rant with hopefully a fix that will help others. Firstly, the rant:

In my post on Building Cross Platform Apps I used the new project templates in Visual Studio 2017 to create a new Xamarin.Forms application that targets iOS, Android and UWP. What I didn’t mention is the time I wasted trying to upgrade NuGet packages in order to get the thing to build and run. Namely I get the following exception when attempting to build the newly created application.

Severity    Code    Description    Project    File    Line    Suppression State
Error        Exception while loading assemblies: System.IO.FileNotFoundException: Could not load assembly 'Xamarin.Android.Support.v7.RecyclerView, Version=1.0.0.0, Culture=neutral, PublicKeyToken='. Perhaps it doesn't exist in the Mono for Android profile?
File name: 'Xamarin.Android.Support.v7.RecyclerView.dll'
   at Java.Interop.Tools.Cecil.DirectoryAssemblyResolver.Resolve(AssemblyNameReference reference, ReaderParameters parameters)
   at Xamarin.Android.Tasks.ResolveAssemblies.AddAssemblyReferences(DirectoryAssemblyResolver resolver, ICollection`1 assemblies, AssemblyDefinition assembly, Boolean topLevel)
   at Xamarin.Android.Tasks.ResolveAssemblies.Execute(DirectoryAssemblyResolver resolver)    App5.Droid           

I figured that there was something wrong with the Xamarin.Forms and/or Xamarin Android NuGet packages, so I thought I’d just go an upgrade the Xamarin.Forms NuGet package. Note: Don’t every try to upgrade the Xamarin Android packages independently – let the Xamarin.Forms NuGet package determine which versions of those libraries you need. Anyhow, unfortunately that just generates another exception:

Severity    Code    Description    Project    File    Line    Suppression State
Error        Unable to resolve dependencies. 'Xamarin.Android.Support.Compat 24.2.1' is not compatible with 'Xamarin.Android.Support.Design 24.2.1 constraint: Xamarin.Android.Support.Compat (= 24.2.1)'.            0   

At this point I was starting to get annoyed – it looks like there was already an inconsistency between the Xamarin.Forms package and the Xamarin Android packages included in the template. Luckily it was easier to fix than I thought it was. I opened up the packages.config file for the Android head project and delete the Xamarin.Android libraries.

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Xamarin.Android.Support.Design" version="23.4.0.1" targetFramework="monoandroid60" />
  <package id="Xamarin.Android.Support.v4" version="23.4.0.1" targetFramework="monoandroid60" />
  <package id="Xamarin.Android.Support.v7.AppCompat" version="23.4.0.1" targetFramework="monoandroid60" />
  <package id="Xamarin.Android.Support.v7.CardView" version="23.4.0.1" targetFramework="monoandroid60" />
  <package id="Xamarin.Android.Support.v7.MediaRouter" version="23.4.0.1" targetFramework="monoandroid60" />

  <package id="Xamarin.Forms" version="2.3.2.127" targetFramework="monoandroid60" />
</packages>

Then, I just upgraded Xamarin.Forms to the latest NuGet package and all was good again. Lastly, I upgraded all the other NuGet packages (excluding the Xamarin.Android packages) to the latest stable versions.

When I grow up I want to be a .NETStandard Library!

A month or so ago we made the decision to upgrade some of the portable libraries we use for projects from being based on PCL Profiles (eg profile 111 or profile 259) across to .NET Standard. To do this, we followed the upgrade prompt in the project properties page in Visual Studio.

image

After clicking the “Target .NET Platform Standard” you can then pick which .NET Standard you want. Where possible we try for .NETStandard 1.0, which aligns with PCL Profile 259, or .NETStandard 1.1, which aligns with PCL Profile 111 (see https://docs.nuget.org/ndocs/schema/target-frameworks). The theory being that a .NETStandard 1.0 library can be consumed by any .NETStandard library 1.0 and above, as well as any PCL profile library that is profile 259 – in other words, we’re aiming for maximum reach.

Take for example, BuildIt.General, which is a general purpose utility library. This is now a .NETStandard 1.0 library….. or so we thought. I was doing some testing on the current stable version of the library to make sure it could be added into a Xamarin Forms application. In my previous post I showed how easily you can create a new Xamarin Forms project that has a PCL that contains all the UI for the application, and then head projects for each target platform (iOS, Android, UWP). Before adding in BuildIt.General I upgraded all the existing NuGet references – always good practice when creating new project (disclaimer: this sounds easier than it is due to an issue with the current Xamarin.Forms template which makes it hard to upgrade – more on this in a future post).

Next I added a reference to the BuildIt.General NuGet package – I made sure it was added to all projects as it includes a UWP library that has some useful extensions such as converters that are specific to UWP. At this point everything was able to build and I was able to run the UWP application (I didn’t get round to running the other platforms but I assumed that they would also work since I hadn’t really modified anything from what comes out of the box). I then wanted to test that I could invoke functions from the BuildIt.General library, so I added the following into the MainPage.xaml.cs file within the Xamarin.Forms PCL library:

LogHelper.Log("test");

Now, when I attempted to build the library I got the following error:

The primary reference "BuildIt.General, Version=1.0.0.20, Culture=neutral, processorArchitecture=MSIL" could not be resolved because it was built against the ".NETPortable,Version=v5.0" framework. This is a higher version than the currently targeted framework ".NETPortable,Version=v4.5,Profile=Profile259".

This completely confused me….. what’s this reference to .NETPortable and what’s the difference between v5.0 and v4.5. Immediately I thought that it was an issue with Visual Studio 2017 but after a bit of investigating it turns out that it’s a more fundamental issue with the way that we, actually MSBuild/Visual Studio, is creating the BuildIt.General library. I came across this thread which includes this comment:

image

(Oren has one of the best explanations on the whole .NET Standard v’s PCL Profile discussion at https://oren.codes/2016/06/23/portable-is-dead-long-live-netstandard/)

Anyhow, I wondered whether our library was suffering from the same ill fate. Using ILSpy I took a look at what was included as the TargetFramework and sure enough it’s listed as .NETPortable, v5.0.

image

The workaround for this was listed in this changeset. In summary it requires a change to the project file to override the default generation of the Target Framework Moniker (See bold pieces in the following extract). There are two parts to the change: the first specifies the filename where the TargetFrameworkMoniker assembly attribute will be written to, and then included in the build of the application; the second overwrites the generated TargetFrameworkMoniker.

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="
http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
    ...
    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
    <TargetFrameworkProfile>
    </TargetFrameworkProfile>
    <TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
   <TargetFrameworkMonikerAssemblyAttributesPath>$(IntermediateOutputPath)AssemblyTFMAttribute.cs.exclude</TargetFrameworkMonikerAssemblyAttributesPath>
    ...
  </PropertyGroup>
  ...
  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
  <Target Name="_SetTargetFrameworkMonikerAttribute" BeforeTargets="GenerateTargetFrameworkMonikerAttribute">
    <PropertyGroup>
      <RealTargetFrameworkMoniker>.NETStandard,Version=v1.0</RealTargetFrameworkMoniker>
      <RealTargetFrameworkMonikerDisplayName>$(RealTargetFrameworkMoniker)</RealTargetFrameworkMonikerDisplayName>
      <TargetFrameworkMonikerAssemblyAttributeText Condition="'$(RealTargetFrameworkMoniker)' != '' and '$(TargetingClr2Framework)' != 'true'">
        // &lt;autogenerated /&gt;
        using System%3b
        using System.Reflection%3b
        [assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(&quot;$(RealTargetFrameworkMoniker)&quot;, FrameworkDisplayName = &quot;$(RealTargetFrameworkMonikerDisplayName)&quot;)]
      </TargetFrameworkMonikerAssemblyAttributeText>
    </PropertyGroup>
  </Target>
</Project>

After making this change, and building a new version of the BuildIt.General library I can now see the correct Target Framework:

image

Out of interest, it appears that if you’re using the xproj project format targeting .NETStandard, it creates a library with the correct target framework. Hopefully this fix, will help you if you’re not.

Building Cross Platform Applications with Visual Studio 2017

Ok, before I jump into this, I want to point out a couple of things:

- Visual Studio 2017 is still in RC

- When you install the RC of Visual Studio 2017 and enable the options to install Xamarin, you will break any existing Xamarin support for earlier versions of Visual Studio (see https://www.visualstudio.com/en-us/news/releasenotes/vs2017-relnotes#KIXamarin).

I noticed the other day when I was creating a throwaway project is that there’s a new dialog when creating cross platform applications within Visual Studio 2017. In the New Project dialog, select the Cross Platform node and there is a single Cross Platform App option.

image

Selecting this option presents you with some project templates – there are only a couple at the moment but I’m hoping that they provide more examples.

image

Unfortunately, and it’s a little hard to see in this screenshot, for the Master Detail template, you can only select Shared Projects. Without exploring the template, I can only assume it was setup this way to share UI code that has platform specific code that compiles based on conditional flags. I really like the way that you can switch between a Forms application and a Native (and no they don’t literally mean “native” (eg Objective-C/Swift or Java/C++), they mean traditional Xamarin where you have platform specific UI.

I opted for the “Blank App (XAML)” which requires Forms, I selected PCL, but unfortunately the “Host in the cloud” option was then disabled. After hitting Accept, the new solution was created and I was immediately able to build and run the application across iOS, Android and Windows (UWP). Very nice.

Building a Mulit-Tenant Rich Client (UWP) that Connects via an Azure AD Protected WebAPI Through to an External Service

Wow, that title is a mouthful. Just reading that makes you think that this is some weird edge case that you’d never have to deal with but this is actually quite a common scenario. Let me give you the scenario we were trying to get to work:

- The user of the rich client application (I’ll use a UWP application but could be an iOS, Android, WPF, or in fact an external web site) needs to retrieve some information from their Office365 account. The required information isn’t currently available via the Graph API, so it requires the use of the Exchange Web Service (EWS) library, which is really only usable in applications written using the full .NET Framework (ie no PCL support). This means any calls to Exchange have to be proxied via a service (ie Web API) interface. Routing external calls via a service proxy is often a good practice as it makes the client application less fragile, making it possible to change the interactions with the external service without having to push out new versions of the application.

- Access to the WebAPI is protected using Azure AD. The credentials presented to the Web API will need to include appropriate permissions to connect through to Exchange using the EWS library.

- The user will need to sign into the rich client application. Their credentials will be used to access the Web API, and subsequently Exchange.

- Any user, from any tenant, should be able to sign into the rich client application and for information to be retrieved from their Exchange (ie Office 365) instance. In other words both the rich client and Web API need to be multi-tenanted.

Single Tenanted

I’ll start by walking through creating a single tenanted version of what we’re after. For this, I’m going to borrow the basic getting started instructions from Danny Strockis’ post (https://azure.microsoft.com/en-us/documentation/samples/active-directory-dotnet-webapi-onbehalfof/).

Creating the Applications

Let’s start by creating a new solution, Exchange Contacts, with a Universal Windows Platform (UWP) application, call it ExchangeContactsClient.

image

Next we’ll create a new ASP.NET Web Application project, call it ExchangeContactsWeb

image

For the moment I’m not going to setup either Authentication or hosting in Azure

image

Next I need to add the Active Directory Authentication Library (ADAL) NuGet package to both the WebAPI and UWP projects

image

To make it easy to debug and step through the interaction between the UWP application and the WebAPI I recommend setting Visual Studio up to start both projects when you press F5 to run. To do this, right-click the solution and select Set Startup Projects

image

I’d also suggest at this point running the solution to firstly make sure both applications are able to be run (ie that they were created correctly by Visual Studio) – I had to upgrade the Microsoft.NETCore.UniversalWindowsPlatform NuGet package in order for the UWP project to run. You also need to retrieve the localhost URL of the WebAPI that will be used later.

Local WebAPI URL: http://localhost:8859/

Configuring Azure AD

Before we continue developing the applications we’ll step over to Azure and configure the necessary applications in Azure Active Directory (Azure AD) – https://portal.azure.com. When you land on the Azure portal, make sure you’re working with the correct subscription – this is shown in the top right corner, under your profile information. In this case I’m going to be working with our Office 365 developer subscription (available for MSDN subscribers) called BTR Office Dev. This is associated with the btro365dev.onmicrosoft.com Azure AD tenant.

image

From the left side of the portal, select the Azure Active Directory node

image

Followed by selecting App registrations – this will list any existing Azure AD applications your organisation has.

image

You can think of an Azure AD application as a connector that allows your application to connect to Azure AD, so in order for both the UWP and WebAPI projects to connect to Azure AD I’ll need two new Azure AD applications

Register the WebAPI application

Click the Add button at the top of the list of the Azure AD applications

Give the application a friendly name (ExchangeContactsWeb), make sure the Application Type is set to Web app/API and specify the Sign-on URL. The Sign-on URL should be the Local WebAPI URL recorded earlier, ie https://localhost:8859/

image

After creating the Azure AD application for the Web API application, immediately select it from the list of Azure AD applications and take note of the Application Id.

image

Web API Client Id: 88e4051b-9f88-4ccb-9d0b-e7fca46c4430

Click on Keys and create a new key – the value of the key won’t appear until you save the new key. The name of the key isn’t that important, so just give it a name that will make sense to you. This key will be used by the web service as part of creating the authentication context when connecting to Azure AD in order to perform actions on behalf of the signed in user.

image

After clicking Save, the value of the new key will appear – make sure you take a copy of the key now as you won’t ever be able to see it again via the Azure portal.

image

App Key: T35aTVE9vrA5TEGCg9Jyw8wOzO47/IZpcN3NPeMDF/A=

 

Register the UWP application

Click the Add button at the top of the list of Azure AD applications

Give the application a friendly name (ExchangeContactsClient), make sure the Application Type is set to Native, and specify the Redirect URI (eg https://ContactsClient). The URL you specify for the Redirect URL doesn’t matter, so long as it’s a valid URL and that you specify the same Redirect URI within the UWP application when attempting to authenticate.

image

After creating the Azure AD application for the UWP application, immediately select it from the list of Azure AD applications and take note of the Application Id.

image

UWP Client Id: 1b64d2a6-32f4-4dba-9e3f-73def5520baa

 

Connecting the Azure AD applications

At this point you have two Azure AD application: one that the UWP application will use to connect to Azure AD, the other that the Web API will connect with. In order for a user to sign into the UWP application and request access to the Web API, these two Azure AD applications need to be connected. This is done by selecting the native application (ie ExhcnageContactsClient) from the list of Azure AD applications, selecting All Settings, followed by Required permissions, followed by the Add button. Type the start of the name of the WebAPI Azure AD application eg “exchange” to bring up the list of applications that can be added

image

image

As you can see from the images, this brings up No Results. This is because there appears to be an issue with the way that Azure AD applications are registered when created through the new Azure portal. Note that this is true at the time of writing this post, but may well be fixed in the future as the Azure AD management experience comes out of preview. The following step is required in order to fix this issue: Click on the Overview node, then at the top of the overview pane, click the link to the Classic portal. Alternatively you can just go to https://manage.windowsazure.com

image

Once in the classic portal, from the list of icons on the left side, select Active Directory (diamond icon), then select the WebAPI Azure AD application, followed by the Configure tab. Once on the configure tab, remove the trailing slash from the Sign-on URL (eg https://localhost:8859) and click Save. Then add the slash back to the Sign-on URL (eg https://localhost:8859/).

image

Doing this seems to re-register (correctly) the Web API Azure AD application. Whilst in the Classic portal, scroll down and locate the section entitled “single sign-on” and retrieve the App ID URI – this is the resource identifier for the Web API

image

Web API Resource Id: https://btro365dev.onmicrosoft.com/a52151ed-8e86-4827-b657-1cd20061b86c

In the Azure portal (https://portal.azure.com) navigate back to the UWP Azure AD application (ie ExchangeContactsClient), All settings, Required permissions, Add and then again enter the start of the name of the WebAPI Azure AD application (eg “exchange”). This should now display the Web API Azure AD application (ie ExchangeContactsWeb).

image

Select the Azure AD application (ie ExchangeContactsWeb) and click Select to move onto selecting permissions

image

Check the box alongside “Access ExchangeContactsWeb” and click Select, followed by Done to complete the process of setting up permissions.

 

Building the Web Application

Add a new controller,ContactsController, into the Web API project.

image

In order to take advantage of Azure AD in order to authorize access to the Web API I need to add a reference to Microsoft.Owin.Security.ActiveDirectory.

image

At this point, it’s also worth making sure that other NuGet packages are updated – when preparing this sample the Newtonsoft.Json package had to be updated, along with making sure the binding redirect in web.config is updated

<dependentAssembly>
  <assemblyIdentity name="Newtonsoft.Json" culture="neutral" publicKeyToken="30ad4fe6b2a6aeed" />
  <bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
</dependentAssembly>

The other NuGet reference that the ContactsController will need is Microsoft.Graph so that information can be retrieved on behalf of the user.

image

Next I’ll add a Get method to the new ContactsController. I’ll also apply the Authorize attribute to the ContactsController which will ensure any request has a bearer token. I’ll come back to the Get method later and add implementation details to retrieve Contacts

[Authorize]
public class ContactsController : ApiController
{
    public async Task<IEnumerable<string>> Get()
    {
        return new[]{"To be determined"};
    }

}

In order to use Azure AD to authenticate requests it’s also necessary to modify the Startup.Auth.cs

public partial class Startup
{
    public void ConfigureAuth(IAppBuilder app)
    {
        app.UseWindowsAzureActiveDirectoryBearerAuthentication(
            new WindowsAzureActiveDirectoryBearerAuthenticationOptions
            {
                Audience = ConfigurationManager.AppSettings["ida:Audience"],
                Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
                TokenValidationParameters = new TokenValidationParameters
                {
                    SaveSigninToken = true
                }
            });
    }
}

The Startup relies on two app settings that need to be added to the web.config

<add key="ida:Tenant" value="btro365dev.onmicrosoft.com" />
<add key="ida:Audience" value="https://btro365dev.onmicrosoft.com/a52151ed-8e86-4827-b657-1cd20061b86c" />

The Tenant value is the name of the tenant where the Azure AD applications are defined. You’ll notice that the Audience value is the Web API Resource Id that was recorded earlier.

 

Building the UWP Application

I’ll start by adding a simple button to the MainPage of the application by modifying the file MainPage.xaml to include the following:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <StackPanel>
        <Button Click="AuthenticateClick">Authenticate</Button>
    </StackPanel>
</Grid>

In the code behind file, MainPage.xaml.cs, I’ll add the following:

private const string Authority = "https://login.microsoftonline.com/btro365dev.onmicrosoft.com/";
private const string WebAPIResourceId = "https://btro365dev.onmicrosoft.com/a52151ed-8e86-4827-b657-1cd20061b86c";
private const string UWPClientId = "1b64d2a6-32f4-4dba-9e3f-73def5520baa";
private static Uri RedirectUri { get; } = new Uri("https://ContactsClient");

private const string BaseServiceUrl = "http://localhost:8859";


private async void AuthenticateClick(object sender, RoutedEventArgs e)
{
    var authContext = new AuthenticationContext(Authority);

    try
    {
        var result = await authContext.AcquireTokenAsync(WebAPIResourceId, UWPClientId, RedirectUri,
            new PlatformParameters(PromptBehavior.Always, false));

        using (var httpClient = new HttpClient())
        {
            // Once the token has been returned by ADAL, add it to the http authorization header, before making the call to access the To Do list service.
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",result.AccessToken);

            // Retrieve the list of contacts
            var response = await httpClient.GetAsync(BaseServiceUrl + "/api/contacts");

            if (response.IsSuccessStatusCode)
            {
                // Read the response and databind to the GridView to display To Do items.
                var contacts = await response.Content.ReadAsStringAsync();
                Debug.WriteLine(contacts);
            }
        }

    }
    catch (AdalException)
    {
        // Handle both user cancelling sign in and/or authentication failure  
    }
}

This code defines a number of constants as follows:

Authority: This is the url where the user is navigated to in order to be authenticated against Azure AD – the BTR Office Dev tenant is clearly visible at the end of the Authority
WebAPIResourceId: This identified the resource that the initial authentication attempt is request access to
UWPClientId: In order to access Azure AD the UWP application uses the Azure AD native application setup earlier
RedirectUri: As the authentication is done via a web page, the RedirectUri defines where the browser will be navigated to at the end of the authentication process. In this case it’s a fake Uri, which has to correspond with the RedirectUri specified in the Azure AD native application.
BaseServiceUrl: This is the base url of the Web APIs that the application will be retrieving data from.

The code uses ADAL to acquire an access token, which can then be presented when invoking a Get operation on the ContactsController.

 

When you run the solution, you should see a web browser appear, as well as the ExchangeContacts application. Clicking the Authenticate button launches a familiar dialog that prompts for email address and password. At this point the user has to be a member of the btro365dev.onmicrosoft.com  tenant.

image

After signing in, the user will also be prompted to grant permission for the application to access information.

image

Side Note on the Access Token

After the authentication process is completed, it’s possible to extract the access token and then use a website like jwt.io, to unpackage the access token. For example, the following is taken from the results.AccessToken object after the user signs into the application.

eyJ0eXAiOiJKV1QiLCJub25jZSI6IkFRQUJBQUFBQUFEUk5ZUlEzZGhSU3JtLTRLLWFkcENKaEFrMWJhQjJnRHpaN1J3OUh4WkI4dEdJUVFGdzI4WWVDd2dlRFYxRUZhRjJvMFd5MzFORG0tS0dWZTc1Rm9JOGdvSlBJa1hLSkVydmQzV19MajQwMWlBQSIsImFsZyI6IlJTMjU2IiwieDV0IjoiSTZvQnc0VnpCSE9xbGVHclYyQUpkQTVFbVhjIiwia2lkIjoiSTZvQnc0VnpCSE9xbGVHclYyQUpkQTVFbVhjIn0.eyJhdWQiOiJodHRwczovL2dyYXBoLm1pY3Jvc29mdC5jb20iLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC85MjY2ZmE2Yy0yYTU4LTRmMjQtYTI0Yi0yYTEzMTk4NTliM2UvIiwiaWF0IjoxNDc2ODg2MzAxLCJuYmYiOjE0NzY4ODYzMDEsImV4cCI6MTQ3Njg5MDQ5NywiYWNyIjoiMSIsImFtciI6WyJwd2QiXSwiYXBwX2Rpc3BsYXluYW1lIjoiRXhjaGFuZ2VDb250YWN0c1dlYiIsImFwcGlkIjoiODhlNDA1MWItOWY4OC00Y2NiLTlkMGItZTdmY2E0NmM0NDMwIiwiYXBwaWRhY3IiOiIxIiwiZV9leHAiOjExMDk1LCJmYW1pbHlfbmFtZSI6IlJhbmRvbHBoIiwiZ2l2ZW5fbmFtZSI6Ik5pY2siLCJpcGFkZHIiOiI2MC4yNDEuMTg1LjUwIiwibmFtZSI6Ik5pY2sgKE9mZmljZSAzNjUgRGV2KSIsIm9pZCI6IjdkY2NhYWQxLTZiZDgtNDZjMi1hZGM3LWQ1ODY2MjllMTAxMiIsInB1aWQiOiIxMDAzQkZGRDhFRDRBREUxIiwic2NwIjoiVXNlci5SZWFkIiwic3ViIjoiaW4wQklSdFNOblhHckhTNWlncGdCb2JvdU9Nc0x3V2NkRFhNVXdPbjNaZyIsInRpZCI6IjkyNjZmYTZjLTJhNTgtNGYyNC1hMjRiLTJhMTMxOTg1OWIzZSIsInVuaXF1ZV9uYW1lIjoibmlja0BidHJvMzY1ZGV2Lm9ubWljcm9zb2Z0LmNvbSIsInVwbiI6Im5pY2tAYnRybzM2NWRldi5vbm1pY3Jvc29mdC5jb20iLCJ2ZXIiOiIxLjAifQ.CfeVUjnJt8dGdKGFEK39piuhB4imbWJh06uqoonfU-gQmHB4VWgY0i43b-YyXZRP9z4SD7dXGiS1IzDUX4GT3VvlsCXq48RkkbSKVzZLVZk_VojiPDn3jSczw70VKFZrXqPCfRcvhbwnFBGTlY_06vtDT3jE-TACLc8jR3D_mTSL9d8akWsxUhVIw6vKaRuyTpBtnO7KO8KS87oLf0wJlKaSfWTO5Nykp5AUhQHfAOij33XOejy5dNIWkml00kO1agBP4WMCHm3EklLlOrnpW8K71KHweqflVK8Zzy8H6XORt3UZIFiCUUF1ORPxQgHpSNJ8Sqw7LlKGPxC6NHd9wA

Entering this into the site http://jwt.io this token can be extracted to show relevant information about the user and their permissions.

{
  "aud": "https://btro365dev.onmicrosoft.com/a52151ed-8e86-4827-b657-1cd20061b86c",
  "iss": "https://sts.windows.net/9266fa6c-2a58-4f24-a24b-2a1319859b3e/",
  "iat": 1476887372,
  "nbf": 1476887372,
  "exp": 1476891272,
  "acr": "1",
  "amr": [
    "pwd"
  ],
  "appid": "1b64d2a6-32f4-4dba-9e3f-73def5520baa",
  "appidacr": "0",
  "e_exp": 10800,
  "family_name": "Randolph",
  "given_name": "Nick",
  "ipaddr": "60.241.185.50",
  "name": "Nick (Office 365 Dev)",
  "oid": "7dccaad1-6bd8-46c2-adc7-d586629e1012",
  "scp": "user_impersonation",
  "sub": "Qu6BNhi6dbma-rLraV_3B06be5DsdohiMlt8hJsHpVM",
  "tid": "9266fa6c-2a58-4f24-a24b-2a1319859b3e",
  "unique_name": "nick@btro365dev.onmicrosoft.com",
  "upn": "nick@btro365dev.onmicrosoft.com",
  "ver": "1.0"
}

As you can see, the information in this json the user is nick@btro365dev.onmicrosoft.com. What’s not immediately obvious is that this token has been issued by the BTR Office Dev tenant, which is the tenant that the Azure AD applications are defined – to be expected in a single tenanted scenario. In the Classic portal you can see the tenant Id when you select the Azure AD instance – it’s the guid that appears in the address bar. This is much less obvious in the new portal. This guid matches the guid in the iss field in the access token (ie "iss": https://sts.windows.net/9266fa6c-2a58-4f24-a24b-2a1319859b3e/)

image

 

Accessing Graph API

In the previous section we can see that the audience of the access token is https://btro365dev.onmicrosoft.com/a52151ed-8e86-4827-b657-1cd20061b86c, which essentially is the identifier of the Web API in Azure, meaning that this access token can be presented when making requests to the Web API. However, if we then want to call on another service, in this case the Microsoft Graph API, we have to exchange this access token for one that is valid for the Graph API. The following code retrieves an access token for connecting to the Graph API and then uses it to retrieve the display name of the current user (Currently we haven’t assigned enough permissions to the Azure AD apps in order to query the Contacts for the user but by default they have permission to query information about themselves)

[Authorize]
public class ContactsController : ApiController
{
    private static string Authority { get; } = ConfigurationManager.AppSettings["ida:Authority"];
    private static string WebAPIClientId { get; } = ConfigurationManager.AppSettings["ida:WebAPIClientID"];
    private static string WebAPIAppKey { get; } = ConfigurationManager.AppSettings["ida:AppKey"];
    private static string GraphResourceId { get; } = ConfigurationManager.AppSettings["ida:GraphResourceId"];

    public async Task<IEnumerable<string>> Get()
    {
        var accessToken = await RetrieveAccessToken();
        return await RetrieveContacts(accessToken);
    }

    private static async Task<string> RetrieveAccessToken()
    {
        var clientCred = new ClientCredential(WebAPIClientId, WebAPIAppKey);
        var bootstrapContext =
            ClaimsPrincipal.Current.Identities.First().BootstrapContext as
                System.IdentityModel.Tokens.BootstrapContext;
        var userName = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn) != null
            ? ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn).Value
            : ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email).Value;
        var userAssertion = new UserAssertion(bootstrapContext?.Token, "urn:ietf:params:oauth:grant-type:jwt-bearer",
            userName);
        var authContext = new AuthenticationContext(Authority);

        var result = await authContext.AcquireTokenAsync(GraphResourceId, clientCred, userAssertion);
        var accessToken = result.AccessToken;
        return accessToken;
    }


    public static async Task<IEnumerable<string>> RetrieveContacts(string accessToken)
    {
        var graphClient = new GraphServiceClient(
                    "https://graph.microsoft.com/v1.0",
                    new DelegateAuthenticationProvider(
                        async (requestMessage) =>
                        {
                            requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", accessToken);
                        }));


        var data = graphClient.Me.Request();
        var getresult = await data.GetAsync();
        Debug.WriteLine(getresult != null);

        return new[] { getresult.DisplayName };
         
    }
}

This code relies on some additional web.config app settings

<appSettings>
  <add key="ida:Tenant" value="btro365dev.onmicrosoft.com" />
  <add key="ida:Audience" value="https://btro365dev.onmicrosoft.com/a52151ed-8e86-4827-b657-1cd20061b86c" />
  <add key="ida:WebAPIClientID" value="88e4051b-9f88-4ccb-9d0b-e7fca46c4430" />
  <add key="ida:AppKey" value="T35aTVE9vrA5TEGCg9Jyw8wOzO47/IZpcN3NPeMDF/A=" />
  <add key="ida:Authority" value="https://login.microsoftonline.com/btro365dev.onmicrosoft.com" />
  <add key="ida:GraphResourceId" value="https://graph.microsoft.com" />
</appSettings>

 

Multi-Tenanted

So far we have an application that a user can sign into and invoke a protected service in order to retrieve information from the Graph API. Unfortunately this only works for users that are part of the BTR Office Dev tenant. For example if I sign in with the user tester@builttoroam.com, I see the following error: AADSTS50020: User account 'tester@builttoroam.com' from identity provider 'https://sts.windows.net/9236ecf1-cfae-41f7-829c-af7e3d09a7e6/' does not exist in tenant 'BTR Office Dev' and cannot access the application '1b64d2a6-32f4-4dba-9e3f-73def5520baa' in that tenant. The account needs to be added as an external user in the tenant first. Sign out and sign in again with a different Azure Active Directory user account.

image

Essentially this is saying that we’ve attempted to sign into a single-tenanted application. More specifically we’re attempting to sign into an application via an authority that doesn’t know or understand about the user we’re attempting to sign in with. The first change we’ll make is to the sign in authority in the UWP application.

private const string Authority = "https://login.microsoftonline.com/common/";

Now when we sign in, we see a different error: AADSTS70001: Application with identifier '1b64d2a6-32f4-4dba-9e3f-73def5520baa' was not found in the directory builttoroam.com

image

In this case, the error is saying that the UWP client application (ie the application with Azure Ad Client Id '1b64d2a6-32f4-4dba-9e3f-73def5520baa') doesn’t exist within the Built to Roam directory. This is correct, since it was created in the Btr Office Dev tenant. To address this issue, we need to indicate that this application should be enabled for other tenants (ie multi-tenanted). Open the Azure Ad application for the UWP application in the Azure portal and click the Manifest button. Adjust the “availableToOtherTenants” attribute to “true”

image

Now when you run the UWP application and attempt to sign in with a foreign user (eg tester@builttoroam.com) you see a different error, this time it appears in code, rather than the Azure authentication UI: Additional information: AADSTS50001: The application named https://btro365dev.onmicrosoft.com/a52151ed-8e86-4827-b657-1cd20061b86c was not found in the tenant named builttoroam.com.  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.
This can be a little confusing as it’s not immediately obvious where the identifier “https://btro365dev.onmicrosoft.com/a52151ed-8e86-4827-b657-1cd20061b86c “ comes from – the guid doesn’t match the application Id for any of the Azure Ad applications. It is in fact the Web API Resource Id, and it’s essentially saying that the Azure Ad application for the Web API doesn’t exist in the Built to Roam tenant. Again, this is true, since it was created in the Btr Office Dev tenant. Again, we need to adjust the Azure Ad application for the Web API to allow use for other tenants, by modifying the availableToOtherTenants attribute in the manifest.

image

Again, if you run the UWP application and sign in using a foreign user, you’ll see another, different, exception: Additional information: AADSTS65005: Resource '88e4051b-9f88-4ccb-9d0b-e7fca46c4430' does not exist or one of its queried reference-property objects are not present.

This error is much harder to diagnose as the error basically just says that either the Web API doesn’t exist (the resource it references is the Application Id of the Azure Ad application for the Web API) or that it isn’t configured correctly, but it doesn’t say what configuration isn’t correct. This is actually a very poorly documented configuration change required to get multi-tenancy to work. You have to let the Web API know about the UWP application by updating the manifest of the Web API Azure Ad application to include the application id of the UWP Azure Ad application in it’s list of known client applications. Set the knownClientApplications attribute to include the application id of the UWP Azure AD application (ie 1b64d2a6-32f4-4dba-9e3f-73def5520baa)

image

Running the UWP application and signing in using a foreign user now yields a permissions prompt, granting the UWP application permissions to access the user’s profile:

image

After giving approval, the UWP application will receive an access token eg eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ikk2b0J3NFZ6QkhPcWxlR3JWMkFKZEE1RW1YYyIsImtpZCI6Ikk2b0J3NFZ6QkhPcWxlR3JWMkFKZEE1RW1YYyJ9.eyJhdWQiOiJodHRwczovL2J0cm8zNjVkZXYub25taWNyb3NvZnQuY29tL2E1MjE1MWVkLThlODYtNDgyNy1iNjU3LTFjZDIwMDYxYjg2YyIsImlzcyI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0LzkyMzZlY2YxLWNmYWUtNDFmNy04MjljLWFmN2UzZDA5YTdlNi8iLCJpYXQiOjE0NzY5MjAwNTYsIm5iZiI6MTQ3NjkyMDA1NiwiZXhwIjoxNDc2OTIzOTU2LCJhY3IiOiIxIiwiYW1yIjpbInB3ZCJdLCJhcHBpZCI6IjFiNjRkMmE2LTMyZjQtNGRiYS05ZTNmLTczZGVmNTUyMGJhYSIsImFwcGlkYWNyIjoiMCIsImVfZXhwIjoxMDgwMCwiZmFtaWx5X25hbWUiOiJVc2VyIiwiZ2l2ZW5fbmFtZSI6IlRlc3QiLCJpcGFkZHIiOiIxMTAuMTc0LjQ1LjIxOSIsIm5hbWUiOiJUZXN0IFVzZXIiLCJvaWQiOiJhNGE4OTA2Zi1hY2NmLTQyNDQtYmMyNC1kZmE5ODg3YTFiYTEiLCJzY3AiOiJ1c2VyX2ltcGVyc29uYXRpb24iLCJzdWIiOiJEMHVZTnF5QnJabkdidXRmbUhTaGg5WlR5UjhFcW51YW1ULURYeFlocmdnIiwidGlkIjoiOTIzNmVjZjEtY2ZhZS00MWY3LTgyOWMtYWY3ZTNkMDlhN2U2IiwidW5pcXVlX25hbWUiOiJ0ZXN0ZXJAYnVpbHR0b3JvYW0uY29tIiwidXBuIjoidGVzdGVyQGJ1aWx0dG9yb2FtLmNvbSIsInZlciI6IjEuMCJ9.YjLGoycr8pRdMaoJRD6FqhVzrV-TDsw3RJdzQ_IIwULAsyUVtjgQtq0wlsYo6O19JLxq99LhZMt4VwgCpaJzwoLQcL1TOOBR9LiBsEs9NdF2LJjMKLtC2_9tnaCjZA1o0ZqThWlwYlFfFRlRXn9M4Dx1CM-pRen3t4qnIP4jfkSFhVEKKxLnm_frUebpYDn2b3OyvlisP3V1uAhIHLUrjTr5vB4RZPkjfaWDxMFr2J4zzalnlTBgeB8FvbPxPfqr47AssfQ81gczKlFOI1lpnc2ddLndzNAoSG3TmrkesBYO_mtXHNjkQiersbbs-q3Mt1F4kY7AOMg64_9R72_wpg

If you expand this token, you’ll see that whilst the Audience hasn’t changed (since we’re still requesting access to the same resource), the issuing authority has (eg "iss": https://sts.windows.net/9236ecf1-cfae-41f7-829c-af7e3d09a7e6/). The issuing authority is now the Built to Roam tenant.

Even though the token now looks correct, when you attempt to call the Web API you’ll get a 401 Unauthorized exception, with almost no further information in the exception in the UWP application, nor will there be any exception thrown within the Web API. Luckily there is a configuration setting on the Web API that allows you to see more information about authentication failures. Add the following within the <configuration> tags of the Web.config file:

<system.diagnostics>
  <switches>
    <add name="Microsoft.Owin" value="Verbose" />
  </switches>
</system.diagnostics>

Now you’ll see something similar to the following in the Output window when debugging:

Microsoft.Owin.Security.OAuth.OAuthBearerAuthenticationMiddleware Error: 0 : Authentication failed
System.IdentityModel.Tokens.SecurityTokenInvalidIssuerException: IDX10205: Issuer validation failed. Issuer: 'https://sts.windows.net/9236ecf1-cfae-41f7-829c-af7e3d09a7e6/'. Did not match: validationParameters.ValidIssuer: 'null' or validationParameters.ValidIssuers: 'https://sts.windows.net/9266fa6c-2a58-4f24-a24b-2a1319859b3e/'.
   at System.IdentityModel.Tokens.Validators.ValidateIssuer(String issuer, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.JwtSecurityTokenHandler.ValidateIssuer(String issuer, SecurityToken securityToken, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.JwtSecurityTokenHandler.ValidateToken(String securityToken, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
   at Microsoft.Owin.Security.Jwt.JwtFormat.Unprotect(String protectedText)

Again, this error states what is failing but doesn’t really give much of an indication of what to do to fix it. This error essentially is saying that the authentication, despite configuring Azure Ad to be multi-tenanted, is still setup to only validate the Btr Office Dev users (ie against the https://sts.windows.net/9266fa6c-2a58-4f24-a24b-2a1319859b3e/ issuer). You just need to modify the Startup class of the WebAPI to disable issue validation:

public partial class Startup
{
    public void ConfigureAuth(IAppBuilder app)
    {
        app.UseWindowsAzureActiveDirectoryBearerAuthentication(
            new WindowsAzureActiveDirectoryBearerAuthenticationOptions
            {
                Audience = ConfigurationManager.AppSettings["ida:Audience"],
                Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
                TokenValidationParameters = new TokenValidationParameters
                {
                    SaveSigninToken = true,
                    ValidateIssuer = false
                }
            });
    }
}

Running again…. and you’d hope we’re close by now… you guessed it…. a different exception. This time it occurs when attempting to retrieve information from the Graph API: Operation not supported as user tester@builttoroam.com not found in tenant 9266fa6c-2a58-4f24-a24b-2a1319859b3e

Looking at this, it’s clear that the wrong tenant is being used. This is because when we’re requesting the access token for the Graph API resource, we’re again doing this against the Btr Office Dev tenant (to be honest, I’m not sure why that works at all but it does seem to issue an access token, that is probably useless for accessing any external resource not defined within the Btr Office Dev tenant). The fix is to change the Authority used by the Web API that’s in the web.config file:

<add key="ida:Authority" value="https://login.microsoftonline.com/common" />

Now, hey presto, it works… the user (in fact any Azure Ad user from any tenant) can sign into the UWP application and retrieve their display name via a call to the Web API.

 

Retrieving Contacts from Exchange

The last step is for us to extend this to connect through to Exchange (ie Office 365) in order to retrieve a list of contacts. Retrieving Contacts can now be done via the Graph API but there are still some things, such as querying for rooms, that can only be done via the Exchange Web Services (EWS). So, for this exercise we’re going to use the EWS to connect to Office 365 in order to retrieve a list of contacts.

Add the Microsoft.Exchange.WebServices NuGet package to the WebAPI project.

image

I’ll update the service code to retrieve an access token for the Office 365 instead of the Graph API and then retrieve contacts using EWS

private static string Office365ResourceId { get; } = ConfigurationManager.AppSettings["Office365ServerUrl"];
private static string EWSUrl { get; } = ConfigurationManager.AppSettings["EWSUrl"];

public async Task<IEnumerable<string>> Get()
{
    var accessToken = await RetrieveOffice365AccessToken();
    return RetrieveContacts(accessToken);
}


private static async Task<string> RetrieveOffice365AccessToken()
{
    var clientCred = new ClientCredential(WebAPIClientId, WebAPIAppKey);
    var bootstrapContext =
        ClaimsPrincipal.Current.Identities.First().BootstrapContext as
            System.IdentityModel.Tokens.BootstrapContext;
    var userName = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn) != null
        ? ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn).Value
        : ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email).Value;
    var userAssertion = new UserAssertion(bootstrapContext?.Token, "urn:ietf:params:oauth:grant-type:jwt-bearer",
        userName);
    var authContext = new AuthenticationContext(Authority);

    var result = await authContext.AcquireTokenAsync(Office365ResourceId, clientCred, userAssertion);
    var accessToken = result.AccessToken;
    return accessToken;
}

public static IEnumerable<string> RetrieveContacts(string accessToken)
{
    var exchangeService = new ExchangeService
    {
        Url = new Uri(EWSUrl),
        TraceEnabled = true,
        TraceFlags = TraceFlags.All,
        Credentials = new OAuthCredentials(accessToken)
    };

    var contactsfolder = ContactsFolder.Bind(exchangeService,
                                            WellKnownFolderName.Contacts,
                                            new PropertySet(BasePropertySet.IdOnly, FolderSchema.TotalCount));
    var numItems = contactsfolder.TotalCount < 50 ? contactsfolder.TotalCount : 50;
    var view = new ItemView(numItems);

    // To keep the response smaller, request only the display name.
    view.PropertySet = new PropertySet(BasePropertySet.IdOnly, ContactSchema.DisplayName);
    // Request the items in the Contacts folder that have the properties that you selected.
    var contactItems = exchangeService.FindItems(WellKnownFolderName.Contacts, view);

    return contactItems.Items.Select(x => (x as Contact)?.DisplayName).ToArray();


}

This code relies on two additional app settings in the web.config file

<add key="Office365ServerUrl" value="https://outlook.office365.com" />
<add key="EWSUrl" value="https://outlook.office365.com/ews/exchange.asmx" />

Update 20/11/2016: At this point you may see build issues with your code due to Visual Studio not being able to correctly resolve some types. To resolve this you need to add a reference to the System.IdentityModel assembly.

bo8

If you attempt to run this you’ll run into exceptions where the Azure AD applications don’t have permissions on the Office 365 Exchange Online resource. To resolve this open both Azure Ad applications (ie for the Web API and the UWP application) and add the Office 365 Exchange Online (Microsoft.Exchange) resource

image

Make sure you assign the “Access mailboxes as the signed-in user via Exchange Web Service” option which is a delegated permission that doesn’t require administrator approval.

image

When you run the application and sign in, the first time for each user, you’ll see a permissions request, giving access to the Exchange mailbox for the user.

image

Once approval has been granted, the UWP application will be able to connect to the Web API, and retrieve information from Office 365 via the Exchange Web Services.

Using BuildIt.States for Managing States

Almost every software development course at some point covers object orientated programming where the concept of encapsulation is drummed in. We’re taught to create classes that track state – a typical example is an Order that has a series of items, and then goes through various states as the order is processed. All this information is held within the Order object, including some basic functions such as calculating the total of the items being ordered. As the systems we work on grows in complexity, so does the complexity of the classes that are used to encapsulate aspects of the system. Unfortunately this often results in large, bloated classes, where it’s hard to make changes without fear of breaking other parts of the system.

One common mistake that seems to creep in over time is that it becomes difficult to manage what state a class is in. This can result from either a lack of documentation about what states the class can be in, or the states themselves aren’t clearly defined. Take the Order example, the Order class may have properties such as OrderTimestamp and OrderId which are set when the Order is placed. If the Order is rejected, the OrderTimestamp may be reset, leaving the class is some weird state where it has an OrderId, yet no OrderTimestamp. This is one of the scenarios that BuildIt.States is designed to help with.

Before we jump in, we need to set down a basic understanding of how we define states. States can appear in groups but within a group, there can only ever be one current state. For example in the Order scenario, there might be a group called TransactionStates, and the Order can only be in one of the states, Unprocessed, Processing, Processed, OrderRejected, at any given time. This leads me to the starting point of working with BuildIt.States: I’m going to define an enumeration that defines the states that my class can go between – you’ll notice this includes a Default (I often use Base instead) which BuildIt.States will use to determine if the state has been set or not.

public enum MainStates
{
    Default,
    One,
    Two,
    Three,
    Four
}

The next thing we need is our class, in this case one that inherits from NotifyBase, and raises a PropertyChanged event when the CurrentState property changes.

public class MainViewModel:NotifyBase
{
    private string currentState;

    public string CurrentState
    {
        get { return currentState; }
        set
        {
            currentState = value;
            OnPropertyChanged();
        }
    }
}

Defining the states that this class can be in is as simple as adding a reference to the BuildIt.States NuGet package and then defining each of the states:

public IStateManager StateManager { get; } = new StateManager();

public MainViewModel()
{
    StateManager
        .Group<MainStates>()

        .DefineState(MainStates.One)
        .ChangePropertyValue(vm => CurrentState, "State One")

        .DefineState(MainStates.Two)
        .ChangePropertyValue(vm => CurrentState, "State Two")

        .DefineState(MainStates.Three)
        .ChangePropertyValue(vm => CurrentState, "State Three")

        .DefineState(MainStates.Four)
        .ChangePropertyValue(vm => CurrentState, "State Four");

}

The notation for defining state groups and states is very fluid in nature and we’re always looking for ways to make defining states more intuitive. Essentially each of these states updates a single property, CurrentState, with a new constant value.

Making use of this class is as simple as creating an instance of the MainViewModel and setting it as the DataContext for the page:

public sealed partial class MainPage : Page
{
    private MainViewModel ViewModel { get; } = new MainViewModel();
    public MainPage()
    {
        this.InitializeComponent();

        DataContext = ViewModel;
    }

    private void StateOneClick(object sender, RoutedEventArgs e)
    {
        ViewModel.StateManager.GoToState(MainViewModel.MainStates.One);
    }

    private void StateTwoClick(object sender, RoutedEventArgs e)
    {
        ViewModel.StateManager.GoToState(MainViewModel.MainStates.Two);
    }

    private void StateThreeClick(object sender, RoutedEventArgs e)
    {
        ViewModel.StateManager.GoToState(MainViewModel.MainStates.Three);
    }

    private void StateFourClick(object sender, RoutedEventArgs e)
    {
        ViewModel.StateManager.GoToState(MainViewModel.MainStates.Four);
    }
}

When this is run, clicking through each of the buttons triggers a state change in the MainViewModel instances. This in turn causes the CurrentState property to change, which is shown on the page via data binding. The really awesome thing about the way states are defined, is that you can have any number of properties being set, and the library is smart enough to set the property values back to what they were originally when the class moves to a different state.

*Note that this library is currently in beta

Migrating BuildIt to .NETStandard

At the beginning of the year I blogged quite a bit about a set of libraries that we use at Built to Roam that are available either from NuGet (https://www.nuget.org/packages?q=BuildIt) or as source on GitHub (https://github.com/builttoroam/BuildIt). These started a few years ago as an accumulation of helper functions for building, as the time Windows Phone applications. Since then the libraries have matured a bit and have evolved somewhat. The BuildIt.General library is still just a collection of helper method, whilst some, like BuildIt.Lifecycle, are more framework in nature. Over the coming weeks we’re investing a bit into tidying up these libraries, including:

  • Migrating any of the libraries that were targeting PCL profile 259 across to .NET Standard 1.0
  • Updating, where possible, all NuGet references
  • Setting up an automated build and release process, including support for publishing directly to NuGet
  • Rationalise the number of libraries on NuGet – namely where there are platform specific libraries, these will be combined in with the core library (eg BuildIt.General.UWP will get packaged with BuildIt.General and will be installed for UWP projects)
  • Add some additional packages
    • BuildIt.Media.UWP – This allows you to easily add Cortana voice commands for controlling media playback with the MediaElement control
    • BuildIt.Web.Config (this name may change) – This allows you to easily define application configuration values server side and have them flow to the client application

Right now, we’re going through and migrating the libraries to .NET Standard. This is a painful process as there are often NuGet references that don’t work with .NET Standard – we’re either removing these or deciding to wait on the package author to update. During this phase a lot of the packages will be marked as beta -  you should be able to start using these libraries but just be aware we haven’t completed the migration, so things may change over the coming weeks.

NetStandard, what is it and why do I care?

Over the past couple of years there hasn’t been a single project where at some point or another it hasn’t encountered NuGet pain – this is the pain associated with trying to upgrade packages, only to discover that you have to carefully select specific package versions due to incompatibilities, and then try and fight the nasty Visual Studio NuGet package manager interface to get them to install correctly. I’m no expert on topics like PCL Profiles, so I thought that I’d spend some time researching a bit more about what’s going on, and just why NuGet seems to fragile. This interest was also driven by the recent release of the .NET Platform Standard (ie NetStandard) and the fact that I need to migrate the BuildIt libraries we use, away from PCL Profiles (yay!) across to NetStandard.

As I said, I’m no guru on this, so rather than post third or fourth hand info. Here’s where I started: Oren Novotny’s post entitled Portable- is dead, long live NetStandard. Start there, and make sure you follow the links in his post as they provide some essential background reading on the topic.

Cryptic Build Failure in Release Mode for Universal Windows Platform Application

We’ve just managed to solve an issue that’s been plaguing us for a while when we attempt to do a Release build (either via the Store –> Create App Package, or just by setting the build configuration to Release) we were seeing an error message similar to:

RHBIND : error RHB0011: Internal error: 'declModule == m_pLoaderModule'

This error makes no sense, and there’s nothing at all helpful to go on from any of the usual logs etc. A quick search only returned two links, one of which was to a GitHub thread (https://github.com/dotnet/core/blob/master/Documentation/ilcRepro.md) posted by Microsoft that talks about capturing a .NET Native Repro…. not quite what I was interested in. However, further down the post there’s a section entitled “Compilation Failure on Update 1” which lists almost exactly the error we were seeing. The section refers to a new feature called SharedLibrary but doesn’t really talk about how to turn it on or off. It does however link to another post https://blogs.msdn.microsoft.com/dotnet/2015/09/28/whats-new-for-net-and-uwp-in-win10-tools-1-1/.

Initially I didn’t think that there was anything relevant in the post, since it was entitled “What’s new for .NET and UWP in Win10 Tools 1.1” and starts off talking about app-locally and shared appx framework packages. It then talks about how to enable this feature….but in the other post it said that SharedLibrary was on by default…. Anyhow, instead of following this post and setting the UseDotNetNativeSharedAssemblyFrameworkPackage to true (ie enabling it), I figured I’d try setting it to false (ie <UseDotNetNativeSharedAssemblyFrameworkPackage>true</UseDotNetNativeSharedAssemblyFrameworkPackage>). For example the Release section of the UWP project file now looks like:

<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
  <OutputPath>bin\x86\Release\</OutputPath>
  <DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
  <Optimize>true</Optimize>
  <NoWarn>;2008</NoWarn>
  <DebugType>pdbonly</DebugType>
  <PlatformTarget>x86</PlatformTarget>
  <UseVSHostingProcess>false</UseVSHostingProcess>
  <ErrorReport>prompt</ErrorReport>
  <Prefer32Bit>true</Prefer32Bit>
  <UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
<UseDotNetNativeSharedAssemblyFrameworkPackage>false</UseDotNetNativeSharedAssemblyFrameworkPackage>
</PropertyGroup>

Doing this fixed the Release build for this application and allows us to create a package ready for Store deployment. Hope this helps others.

Updating BuildIt

It's been a while but I've just published an update to the BuildIt libraries with the aim to streamline the syntax for declaring states. For example, the following are the state declarations for the Flickr viewer sample application:
StateManager.Group<RegionStates>()
 .WithHistory()
  .DefineStateWithData<RegionStates, MainViewModel>(RegionStates.Main) 
   .WhenChangedTo(vm => vm.Load())
   .OnDefaultCompleteWithData(vm => vm.SelectedPhoto)
    .ChangeState(RegionStates.Details)
     .InitializeNewState<RegionStates, MainViewModel, DetailsViewModel, Photo>  
         ((vm, d) => vm.Photo = d)
  .DefineStateWithData<RegionStates, DetailsViewModel>(RegionStates.Details);