Authorization

Identity Server: Using Entity Framework Core for Configuration Data

This post is a continuation of a series of posts that follow my initial looking into using IdentityServer4 in ASP.NET Core with an API and an Angular front end. The following are the related posts.

Identity Server: Introduction
Identity Server: Sample Exploration and Initial Project Setup
Identity Server: Interactive Login using MVC
Identity Server: From Implicit to Hybrid Flow
Identity Server: Using ASP.NET Core Identity
Identity Server: Using Entity Framework Core for Configuration Data (this post)
Identity Server: Usage from Angular

This post is going to take the existing solution this series has been using and switch from using hard coded configuration data, found in the Config class of the Identity Application and moving it to a database using Entity Framework Core. As with prior entries, this will be following the intent of one of the official quick starts for Using Entity Framework Core for configuration data. This post is fairly different just because our example project already uses entity framework so a lot of steps can be skipped. The starting point of the code can be found here. All the changes in this post will be taking place in the Identity Application.

Identity Application

Thankfully the creators of IdentityServer provide a NuGet package that includes all the bits needed to move configuration data and operational data to Entity Framework Core. Start by added the following NuGet package.

  • IdentityServer4.EntityFramework
Startup

With the above NuGet package installed the ConfigureServices function of the Startup class needs to be changed to tell IdentityServer the new place to pull data from. The following is the new version of the AddIdentityServer call updated to use Entity Framework Core.

var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

services
  .AddIdentityServer()
  .AddTemporarySigningCredential()
  .AddAspNetIdentity<ApplicationUser>()
  .AddConfigurationStore(builder =>
    builder
     .UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
                   options =>
            options.MigrationsAssembly(migrationsAssembly)))
  .AddOperationalStore(builder =>
    builder
     .UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
                   options =>
            options.MigrationsAssembly(migrationsAssembly)));

Notice that the following have all been replaced by AddConfigurationStore and AddOperationalStore.

  • AddInMemoryPersistedGrants
  • AddInMemoryIdentityResources
  • AddInMemoryApiResources
  • AddInMemoryClients

The other thing of note is the migrationsAssembly and its usage via options.MigrationsAssembly. This is moving the management of the migrations from the assembly that the contexts are defined to the Identity Application. This is needed in this case since the two contexts in question are defined in a NuGet package.

Migrations

Now that the configuration is done for the new contexts migrations need to be added to them. As always there are two ways to handle this either via the Package Manager Console or from a command prompt. I am going to use the command prompt this round to match the IdentityServer docs. Run the following two commands from the same path as the Identity Application’s csproj file.

dotnet ef migrations add InitConfigration -c ConfigurationDbContext -o Data/Migrations/IdentityServer/Configuration

dotnet ef migrations add InitPersistedGrant -c PersistedGrantDbContext -o Data/Migrations/IdentityServer/PersistedGrant

This is the first time I have used the -o argument which controls where the migration is output and following the docs example I am putting the migrations that are for entities outside of the control of the application into a subdirectory. Speaking of the entities being outside of the control of the main application, this means anytime the NuGet package that contains the entity is updated a check will need to be made to see if new migrations are needed.

Database Migrations and Seed Data

Since the DbContext classes that need migrations run are outside of the control our application if automatic migrations must be handled in a different way than with the identity-related context used previously in this series. Following the official docs, I am going to create an InitializeDatabase function that will apply any needed migrations as well as add seed data. To do this I am adding a new IdentityServerDatabaseInitialization class in the Data/IdentityServer directory. The following is the full class.

public static class IdentityServerDatabaseInitialization
{
    public static void InitializeDatabase(IApplicationBuilder app)
    {
        using (var serviceScope = app.ApplicationServices
                                     .GetService<IServiceScopeFactory>()
                                     .CreateScope())
        {
            PerformMigrations(serviceScope);
            SeedData(serviceScope);
        }
    }

    private static void PerformMigrations(IServiceScope serviceScope)
    {
        serviceScope.ServiceProvider
                    .GetRequiredService<ConfigurationDbContext>()
                    .Database
                    .Migrate();
        serviceScope.ServiceProvider
                    .GetRequiredService<PersistedGrantDbContext>()
                    .Database
                    .Migrate();
    }

    private static void SeedData(IServiceScope serviceScope)
    {
        var context = serviceScope
                       .ServiceProvider
                       .GetRequiredService<ConfigurationDbContext>();

        if (!context.Clients.Any())
        {
            foreach (var client in Config.GetClients())
            {
                context.Clients.Add(client.ToEntity());
            }
            context.SaveChanges();
        }

        if (!context.IdentityResources.Any())
        {
            foreach (var resource in Config.GetIdentityResources())
            {
                context.IdentityResources.Add(resource.ToEntity());
            }
            context.SaveChanges();
        }

        if (!context.ApiResources.Any())
        {
            foreach (var resource in Config.GetApiResources())
            {
                context.ApiResources.Add(resource.ToEntity());
            }
            context.SaveChanges();
        }
    }
}

The InitializeDatabase takes an IApplicationBuilder in order to be able to control the lifetime of the two DbContext classes needed. Normally this wouldn’t be needed and the lifetime would be controlled automatically, but since this code is being called from the Startup class instead of during a request (which is how the DI system does auto scoping) the scope is being created by the app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope() call.

The PerformMigrations function pulls the two DbContext objects from the container and applies migrations. Finally in SeedData if the DbSets don’t already contain data then the seed data is pulled from the Config class and saved to the database.

Back to Startup

In the Configure function of the Startup class add the following call to make sure migrations and seed data are run when the application starts.

IdentityServerDatabaseInitialization.InitializeDatabase(app);

Wrapping up

With the above changes, the Identity Application is now using the database for all its persistence. The missing bits are of course UI to manage the related data, but those can be built out as needed. The code in its completed state can be found here.

The next steps for this project will be utilizing IdentityServer from Angular in the Client Application instead of the temporary IdentityController that has had to be used in all the examples so far.

Identity Server: Using Entity Framework Core for Configuration Data Read More »

Identity Server: Using ASP.NET Core Identity

This post is a continuation of a series of posts that follow my initial looking into using IdentityServer4 in ASP.NET Core with an API and an Angular front end. The following are the related posts.

Identity Server: Introduction
Identity Server: Sample Exploration and Initial Project Setup
Identity Server: Interactive Login using MVC
Identity Server: From Implicit to Hybrid Flow
Identity Server: Using ASP.NET Core Identity (this post)
Identity Server: Using Entity Framework Core for Configuration Data
Identity Server: Usage from Angular

This post is going to cover using ASP.NET Core Identity instead of an in-memory user store like the previous examples. As I write this I am working through the Using ASP.NET Core Identity quick start from the docs. This isn’t going to differ a whole lot from the official docs, but I still want to document it to help solidify everything in my head. The starting point of the code for this post can be found here.

Identity Application

The Identity Application will be where the bulk of the changes happen. Since it is much easier to add IdentityServer to a project than it is to add ASP.NET Core Identity we are going to delete the existing Identity Application project and re-create it with Identity from the start. Right click on the IdentityApp project and click remove.

This removes the project from the solution, but the files also need to be deleted off of disk or use a different name. I chose to rename the old project folder on disk so I could still grab any files I might need.

Create a new Identity Application

Right-click on the solution and select Add > New Project.

On the Add New Project dialog under Visual C# > .NET Core select ASP.NET Core Web Application and enter the name of the project (IdentityApp in this example) and click OK.

On the next dialog select the Web Application template.

Next, click the Change Authentication button and select the Individual User Accounts option.

Click OK on the Change Authentication dialog and then click OK on the template dialog. After a few seconds, the solution will contain a new IdentityApp that is using ASP.NET Core Identity with Entity Framework Core.

Adding Identity Server to the Identity App Project

Using NuGet install the IdentityServer4.AspNetIdentity package which will also install IdentityServer4 which the old project was using. Next, copy the Config class from the old IdentityApp project and delete the GetUsers function.

Startup Changes

In the Startup class at the end of ConfigureServices function add the following.

services.AddIdentityServer()
    .AddTemporarySigningCredential()
    .AddInMemoryIdentityResources(Config.GetIdentityResources())
    .AddInMemoryApiResources(Config.GetApiResources())
    .AddInMemoryClients(Config.GetClients())
    .AddAspNetIdentity<ApplicationUser>();

The only difference between this and the one used with the previous posts is instead of AddTestUsers being used to pull a hard coded list of uses our of the Config class users are pulled from the database using ASP.NET Core Identity using this AddAspNetIdentity<ApplicationUser>() call. Identity Server is very flexible and this is only of the option for an identity store.

Next, in the Configure function add app.UseIdentityServer() after app.UseIdentity().

app.UseStaticFiles();
app.UseIdentity();
app.UseIdentityServer();
app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");
});
Database

There are a couple of ways to make sure the database is created and migrated when changes happen. One is via the command line in the project directory using the following command.

dotnet ef database update

The way I normally us when at this stage in development is to add code to the DB context to automatically apply migrations. The following is the full ApplicationDbContext class modified to automatically run migrations when the context is constructed.

public sealed class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    private static bool _migrated;

    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
        if (_migrated) return;
        Database.Migrate();
        _migrated = true;
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
    }
}
Now throw that all away

The above is good to go through to know how things work, but I got to this point and wanted the functionality to be on par with the previous entries. The docs made this sound simple, but it was not simple at all I had a list of at least 30 points of files to be moved and changes made to existing files. I am going to spare you all those details and recommend that you just pull the Identity Application from my GitHub repo for this project instead. I did basically the same thing out of the official samples repo to get things working as they should with contents, errors, and log out.

If you want the auto migrations then make sure and keep the version of the ApplicationDbContext from above.

Client Application

No changes are actually required to the client application, but as in the official docs, I made changes to show hitting the API Application using both a user access token and client credentials. The following is the index action on the IdentityController which has been changed to call two functions one for each type of API access.

[Authorize]
public async Task<IActionResult> Index()
{
    var apiCallUsingUserAccessToken = await ApiCallUsingUserAccessToken();
    ViewData["apiCallUsingUserAccessToken"] 
        = apiCallUsingUserAccessToken.IsSuccessStatusCode 
          ? await apiCallUsingUserAccessToken.Content.ReadAsStringAsync() 
          : apiCallUsingUserAccessToken.StatusCode.ToString();

    var clientCredentialsResponse = await ApiCallUsingClientCredentials();
    ViewData["clientCredentialsResponse"] 
        = clientCredentialsResponse.IsSuccessStatusCode 
          ? await clientCredentialsResponse.Content.ReadAsStringAsync() 
          : clientCredentialsResponse.StatusCode.ToString();

    return View();
}

The following is the function to access the API Application using a user access token.

private async Task<HttpResponseMessage> ApiCallUsingUserAccessToken()
{
    var accessToken 
        = await HttpContext.Authentication.GetTokenAsync("access_token");

    var client = new HttpClient();
    client.SetBearerToken(accessToken);

    return await client.GetAsync("http://localhost:5001/api/identity");
}

Now the function to access the API Application using client credentials.

private async Task<HttpResponseMessage> ApiCallUsingClientCredentials()
{
    var tokenClient 
        = new TokenClient("http://localhost:5000/connect/token", 
                          "mvc", "secret");
    var tokenResponse 
        = await tokenClient.RequestClientCredentialsAsync("apiApp");

    var client = new HttpClient();
    client.SetBearerToken(tokenResponse.AccessToken);

    return await client.GetAsync("http://localhost:5001/api/identity");
}

Finally, Index.cshtml found in the Views/Identity directory has the following change.

Replace:
@ViewData["apiResult"]

With:
<dt>api response called with user access token</dt>
<dd>@ViewData["apiCallUsingUserAccessToken"]</dd>

<dt>api response called with client credentials</dt>
<dd>@ViewData["clientCredentialsResponse"]</dd>

Wrapping up

Now the Identity Application is using ASP.NET Core Identity with Entity Framework Core to store users in the database. The next post will cover moving the items now in the Config class into the database. The completed version of the code can be found here.

Identity Server: Using ASP.NET Core Identity Read More »

Identity Server: From Implicit to Hybrid Flow

This post is a continuation of a series of posts that follow my initial looking into using IdentityServer4 in ASP.NET Core with an API and an Angular front end. The following are the related posts.

Identity Server: Introduction
Identity Server: Sample Exploration and Initial Project Setup
Identity Server: Interactive Login using MVC
Identity Server: From Implicit to Hybrid Flow (this post)
Identity Server: Using ASP.NET Core Identity
Identity Server: Using Entity Framework Core for Configuration Data
Identity Server: Usage from Angularsing MVC

This post is going to cover adding back in the API access that was lost in the last post by changing the MVC client to use a hybrid grant instead of an implicit grant. This post was written while working through Switching to Hybrid Flow and adding API Access back in the official docs.

Identity Application

The changes to the Identity Application are pretty simple and only involve tweaking the settings on the MVC client found in the GetClients function of the Config class. First, change the AllowedGrantTypes from Implicit to HybridAndClientCredentials. Next, a client secret should be added.

ClientSecrets =
{
    new Secret("secret".Sha256())
}

This is, of course, a bad secret, but this is only an example. Next, add “apiApp” to the AllowedScopes and finally add AllowOfflineAccess = true. The following is the full client code.

new Client
{
    ClientId = "mvc",
    ClientName = "MVC Client",
    AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,

    ClientSecrets =
    {
        new Secret("secret".Sha256())
    },

    RedirectUris           = { "http://localhost:5002/signin-oidc" },
    PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },

    AllowedScopes =
    {
        IdentityServerConstants.StandardScopes.OpenId,
        IdentityServerConstants.StandardScopes.Profile,
        "apiApp"
    },
    AllowOfflineAccess = true
};

Most of the above are straight forward. AllowedGrantTypes is what is moving to the hybrid flow which then needs a client secret to ensure everything is on the up and up. This client should be able to hit the API application so it is added to the allowed scopes. AllowOfflineAccess is less clear to me. According to the docs, it allows the requesting refresh tokens for long-lived API access. This would take some more digging before production to ensure authorization isn’t too long lived.

Client Application

Changes to the client application were pretty minimal as well. First, in the Configure function of the Startup class, the UseOpenIdConnectAuthentication call must pass a few more items. The following is the full set up.

app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
    AuthenticationScheme = "oidc",
    SignInScheme = "Cookies",

    Authority = "http://localhost:5000",
    RequireHttpsMetadata = false,

    ClientId = "mvc",
    ClientSecret = "secret",

    ResponseType = "code id_token",
    Scope = { "apiApp", "offline_access" },

    GetClaimsFromUserInfoEndpoint = true,
    SaveTokens = true
});

ClientSecret should match what was set up for the client in the Identity Application. According to the docs setting ResponseType to code id_token means use a hybrid flow. This is another point that I would want to dig more on. Scope is requesting access to the API Application and offline access which is the matching part to the offline access set up in the Identity Application. GetClaimsFromUserInfoEndpoint tells the middleware to go to the user info endpoint to retrieve additional claims after getting an identity token.

Identity Controller

The Index action in the IdentityController ends up being much simpler than it was in the previous posts. The following is the full function.

[Authorize]
public async Task<IActionResult> Index()
{
  var accessToken = 
       await HttpContext.Authentication.GetTokenAsync("access_token");

  var client = new HttpClient();
  client.SetBearerToken(accessToken);

  var apiResponse = 
       await client.GetAsync("http://localhost:5001/api/identity");

  ViewData["apiResult"] = 
       apiResponse.IsSuccessStatusCode 
       ? await apiResponse.Content.ReadAsStringAsync() 
       : apiResponse.StatusCode.ToString();

  return View();
}

In the new version, the token can be retrieved from the HTTP context instead of using the DiscoveryClient and TokenClient like the previous version of this code did. The general idea is the same in both which is to get a token, use the token as part of a request to the API application, and finally display the response in a view.

Identity View

The last set of changes is to the Index.cshtml file in the View/Identity directory which is the view that goes with the Index action of the IdentityController. The view displays the access token, refresh token, results of the API call, and the logged in user’s claims.

@using Microsoft.AspNetCore.Authentication
@{
    ViewData["Title"] = "Identity";
}

<dt>access token</dt>
<dd>@await ViewContext.HttpContext.Authentication.GetTokenAsync("access_token")</dd>

<dt>refresh token</dt>
<dd>@await ViewContext.HttpContext.Authentication.GetTokenAsync("refresh_token")</dd>

@ViewData["apiResult"]

<h3>User claims</h3>

<dl>
    @foreach (var claim in User.Claims)
    {
        <dt>@claim.Type</dt>
        <dd>@claim.Value</dd>
    }
</dl>

<form asp-controller="Identity" asp-action="Logout" method="post">
    <button type="submit">Logout</button>
</form>

Wrapping up

Adding back API access was pretty easy and the new setup will make managing other resources pretty simple. The identity space is still pretty new to me but working through the IdentityServer quickstarts are helping get me up to a basic level of knowledge. The finished code for this post can be found here. Come back next week to convert this example to use ASP.NET Core Identity.

Identity Server: From Implicit to Hybrid Flow Read More »

Identity Server: Interactive Login using MVC

This post is a continuation of a series of posts that follow my initial looking into using IdentityServer4 in ASP.NET Core with an API and an Angular front end. The following are the related posts.

Identity Server: Introduction
Identity Server: Sample Exploration and Initial Project Setup
Identity Server: Interactive Login using MVC (this post)
Identity Server: From Implicit to Hybrid Flow
Identity Server: Using ASP.NET Core Identity
Identity Server: Using Entity Framework Core for Configuration Data
Identity Server: Usage from Angular

As before the end goal will be having authorization happen from Angular, but in the short term, the Client Application is using MVC/Razor for testing and verifications. The code as it stood before this post can be found here. If you are following along with the official docs I wrote this post while working through the Adding User Authentication with OpenID Connect quickstart.

The main point of this post is to add a way for a user to enter their username and password and get access to a page that requires authorization using the OpenID Connect protocol.

Identity Application

To enable this scenario the Identity Application will need MVC added along with some UI that will be used to handle login, permissions, and log off. First, using NuGet install the following two packages.

  • Microsoft.AspNetCore.Mvc
  • Microsoft.AspNetCore.StaticFiles

Next, in the ConfigureServices of the Startup class MVC needs to be added as a service.

services.AddMvc();

Then in the Configure function use static files and use MVC should be added after the use statement for IdentityServer.

app.UseIdentityServer();
app.UseDeveloperExceptionPage();

// Following are adds
app.UseStaticFiles();
app.UseMvcWithDefaultRoute();
UI Changes

For the type of flow being used in this sample, the Identity Application will be in control of the login, grant, log out, and related UI. This is not a small amount of thing to get set up properly. Thankfully the IdentityServer team provides a Quickstart UI for use with the in-memory items we are currently using. The files can be downloaded from the repo linked in the previous line or an easier way is to open a Powershell prompt in the same directory of the Identity application as the Startup.cs file and run the following command.

iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/IdentityServer/IdentityServer4.Quickstart.UI/release/get.ps1'))

After the download the project will contain a Quickstart folder with the needed controllers, a Views with of course the needed views, and wwwroot will have all the related files that need to be served with the views.

Config Changes

The Config class needs to be changed to return some more in-memory information to make this new process work. The first is to add a new client for MVC to the GetClients function. The following is the full function, but it is the second Client is the new one.

public static IEnumerable<Client> GetClients()
{
    return new List<Client>
    {
        new Client
        {
            ClientId = "clientApp",
            AllowedGrantTypes = GrantTypes.ClientCredentials,

            // secret for authentication
            ClientSecrets =
            {
                new Secret("secret".Sha256())
            },

            // scopes that client has access to
            AllowedScopes = { "apiApp" }
        },

        // OpenID Connect implicit flow client (MVC)
        new Client
        {
            ClientId = "mvc",
            ClientName = "MVC Client",
            AllowedGrantTypes = GrantTypes.Implicit,

            RedirectUris = { "http://localhost:5002/signin-oidc" },
            PostLogoutRedirectUris = 
                { "http://localhost:5002/signout-callback-oidc" },

            AllowedScopes =
            {
                IdentityServerConstants.StandardScopes.OpenId,
                IdentityServerConstants.StandardScopes.Profile
            }
        }
    };
}

Notice that for the OpenID Connect implicit flow there are URLs that are needed that so this flow knows how to call back into the client application. At this point, I haven’t dug into everything that is going on in the client. The ClientId, ClientName, and URLs related properties are pretty clear. I am not 100% on the AllowedGrantTypes and AllowedScopes, but at this point, I am not going to dive into on these two options.

Next, add a GetIdentityResources function matching the following. This fall in the same category as the two properties above, we are using them without fully digging into them.

public static IEnumerable<IdentityResource> GetIdentityResources()
{
    return new List<IdentityResource>
    {
        new IdentityResources.OpenId(),
        new IdentityResources.Profile(),
    };
}

The last change to the Config class is to add a function to return the in-memory users.

public static List<TestUser> GetUsers()
{
    return new List<TestUser>
    {
        new TestUser
        {
            SubjectId = "1",
            Username = "alice",
            Password = "password",

            Claims = new List<Claim>
            {
                new Claim("name", "Alice"),
                new Claim("website", "https://alice.com")
            }
        },
        new TestUser
        {
            SubjectId = "2",
            Username = "bob",
            Password = "password",

            Claims = new List<Claim>
            {
                new Claim("name", "Bob"),
                new Claim("website", "https://bob.com")
            }
        }
    };
}
Startup Changes

The last change in the Identity Application is to add the new in-memory items to the IdentityServer service in the ConfigureServices function. The following is the full function.

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    services.AddIdentityServer()
        .AddTemporarySigningCredential()
        .AddInMemoryIdentityResources(Config.GetIdentityResources())
        .AddInMemoryApiResources(Config.GetApiResources())
        .AddInMemoryClients(Config.GetClients())
        .AddTestUsers(Config.GetUsers());
}

Client Application

In order to get the client application to play well with the changes in the Identity Application, a few changes need to be made. First, the following NuGet packages need to be installed.

  • Microsoft.AspNetCore.Authentication.Cookies
  • Microsoft.AspNetCore.Authentication.OpenIdConnect

Next, in the Configure function of the Startup class, the application’s middleware pipeline needs some changes. Add the following line to turn off the JWT claim type mapping. This must be done before calling UseOpenIdConnectAuthentication.

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

Now add in the cookie authentication middleware.

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationScheme = "Cookies"
});

The last change is to add OpenID Connect authentication to the pipeline placed after the cookies middleware.

app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
    AuthenticationScheme = "oidc",
    SignInScheme = "Cookies",

    Authority = "http://localhost:5000",
    RequireHttpsMetadata = false,

    ClientId = "mvc",
    SaveTokens = true
});

Notice that the URL of the authority is the URL the Identity Application runs on as well as the client ID match the one we set up in the GetClients function of the Config class in the Identity Application.

Identity Controller

Now that the above is set up we can switch over to the IdentityController and add the Authorize attribute to the Index function.

[Authorize]
public async Task<IActionResult> Index()

This means if a user hits the index action of this controller and isn’t logged in they will be presented with the login page and after login, they will be redirected back to the above index action. That whole process is handled by the OpenId Connect Authentication middleware. The first time I tested the flow and it just worked was magical.

 

The final set of changes for this post is going to be added a way to log out. In the IdentityController add a Logout function.

public async Task Logout()
{
    await HttpContext.Authentication.SignOutAsync("Cookies");
    await HttpContext.Authentication.SignOutAsync("oidc");
}
Identity View Changes

The last change is to add a logout button to the Index.cshtml found in the Views/Identity directory. At the bottom of the page, the following was added to call the Logout action.

<form asp-controller="Identity" asp-action="Logout" method="post">
    <button type="submit">Logout</button>
</form>

Wrapping Up

I already liked the idea of IdentityServer before this post, but after playing with it with the changes above it is emphasized how nice it is. I am very happy I am going down this path instead of trying to work this all out on my own. Stay tuned as this exploration will continue in future posts.

The code in the finished state can be found here.

Update

Turns out there is a bug in the code that goes with this example. In the client application’s IdentityConroller the call to get a token is using clientApp instead of mvc for the client ID when requesting a token. With that change, the call to the API Application will fail since the MVC client doesn’t have access to the API scope. Look for next weeks post where API access will be added to the MVC client.

Identity Server: Interactive Login using MVC Read More »

Identity Server: Introduction

In the SPA based sample applications, this blog has used so far user authentication has either been completely ignored in order to keep the examples simpler or the sites have used ASP.NET Core’s built in identity to encapsulate the whole SPA. In this post (or series of posts) I am going to share what I learn along the way of creating an Angular (2+) application that utilizes ASP.NET Core as its host/API/backend.

This post isn’t going to cover any code it is just going to be a lot of the information I gathered in the process of learning more about Identity Server.

Following are all the post in this series.

Identity Server: Introduction (this post)
Identity Server: Sample Exploration and Initial Project Setup
Identity Server: Interactive Login using MVC
Identity Server: From Implicit to Hybrid Flow
Identity Server: Using ASP.NET Core Identity
Identity Server: Using Entity Framework Core for Configuration Data
Identity Server: Usage from Angular

Identity Server

According to their docs IdentityServer4 is an OpenID Connect and OAuth 2.0 framework for ASP.NET Core which enables Authentication as a Service, Single Sign-on, API Access Control and a Federation Gateway.

Obviously, that covers a lot of scenarios. The two that I am interested in are Authentication as a Service and the API Access Control which has driven my research which means that the other aspects of IdentityServer4 will not be included.

Official Samples

The IdentityServer GitHub account has a samples repo that contains a ton of examples. I have found the quickstart area of the repo to be the most helpful when starting out.

Based on all the quickstarts samples it looks like a typical setup involves a minimum of three projects. One for the API, one for the client and one for Identity Server. As you go through the samples the number of projects increase, but that is because of a wider range of scenarios that the sample is trying to cover.

References for learning

Damienbod has a whole series of blog posts related to IdentityServer4 and code to go along with it which can be found here. As a side note if you are interested in ASP.NET Core and you aren’t following damienbo you should be he has a ton of great content.

Blog posts
Videos

Identity Server Alternatives

Identity Server isn’t the only way to go there is a number of Software as a Service options that cover a lot of same scenarios. The following are some examples.

Auth0 – Check out the .NET Core related blogs by Jerrie Pelser
Stormpath
Amazon Cognito

Wrapping up

Obviously, I didn’t get a lot covered on how to actually do something with IdentityServer, but I wanted to share my starting point. This is an area I am going to continue digging it to and sharing information about as I learn more.

If you have any resources in this area please leave a comment below.

Identity Server: Introduction Read More »

Adding Authorize to a Web API

In the post Aurelia with ASP.NET 5 and Web API I removed the authorize attribute from the contacts API controller to reduce complexity. That change simplified some things but it also effectively made the API useless for multiple users.

In this post I am going to add back in authorization as well as making sure a user identifier is used in contact creation and retrieval. Also note that this authorization is taking place in the web application not via the API so the user must logged in via the main site before access to the API is allowed.

All the changes are in the controller class that needs to be protected. First add two new namespaces.

using Microsoft.AspNet.Authorization;
using System.Security.Claims;

Microsoft.AspNet.Authorization is where the Authorize attribute is found and System.Security.Claims contains an extension method on to the User class to make it easy to get the user ID.

Next add the Authorize attribute to the class level if the whole class should require authorization or at the function level if only some functions need authorization.

[Authorize]
[Route("api/[controller]")]
public class ContactsController : Controller

Next add a filter to the query for contacts to makes sure a user only sees their contacts. User is provided by the Controller base class and the GetUserId is the extension method from System.Security.Claims namespace referenced above.

private IQueryable<Contact> GetContacts()
{
    var contacts = from c in _dbContext.Contacts
                             .Include(c => c.Addresses)
                             .Include(c => c.EmailAddresses)
                             .Include(c => c.PhoneNumbers)
                   where c.UserId == User.GetUserId()
                   select c;
    return contacts;
}

In the create function, which handles HTTP post, the contact user ID must be set based on the current user before the contact is added to the DB context.

[HttpPost]
public async Task Create([FromBody] Contact contact)
{
    if (contact == null)
    {
        return HttpBadRequest();
    }

    if (!ModelState.IsValid)
    {
        return new BadRequestObjectResult(ModelState);
    }

    contact.UserId = User.GetUserId();

    _dbContext.Add(contact);
    await _dbContext.SaveChangesAsync();
    return CreatedAtRoute("GetById",
                          new
                          {
                              controller = "Contacts",
                              id = contact.Id
                          },
                          contact);
}

Adding Authorize to a Web API Read More »

ASP.NET 5 IIS Express Configuration and OAuth 2

I am still in the process of getting all the features from my ASP.NET 4 contacts application moved into ASP.NET 5. Today I was working on getting OAuth 2 working with Google. All the code changes are in the Startup.cs in the root of the project.

In the Configuration function the options need to be set for Google authentication. This is where you set your client ID and secret. I covered the steps of getting this information from Google in this post if you need a reference.

services.Configure<GoogleAuthenticationOptions>(options =>
{
    options.ClientId = "Your Client ID";
    options.ClientSecret = "Your Client Secret";
});

In the Configure function add the following.

app.UseGoogleAuthentication();

The above is changing the Configuration and Configure functions which are pretty similar names that could be clearer. Configuration is where services are registered withASP.NET 5’s built in dependency injection container. Examples of potential services include Entity Framework, MVC, Web API, Application Settings and in my case Google Authentication.

The Configure function is where the HTTP request pipeline is set up. This can include things like serving static files, error handlers, MVC routes and Web API routes.

At this point I tried to run and use Google to login. I was greeted with at 400 – redirect_uri_mismatch. The URL my new project was using did not match the one I used when I setup OAuth with Google. I would like to say this was not a big deal, but it took me way longer to solve than I would like to admit. The settings for which port to use when debugging is in a bit of a different place than before. It can now be found on the debug tab of the project properties.

ProjectDebugProps

Under Other IIS Express setting there is also a check box for Enable SSL which I had to check as well since the URL I used with Google was HTTPS. In addition to the settings in the project properties I also had to edit the applicationhost file which is used by IIS Express. You can find this file in a hidden folder in the same directory as the solution file. The path is .vs\config. To find the relevant section search for your project name or for “site name=” and that should get you to the right area. I tweaked the setting I found there to match the changes I had made in my project properties. I don’t think this is something everyone will have to do and more than likely was a result of a misstep on my part.

I ended up having to manually edit my Contacts.xproj file to get the port settings I needed. The project properties UI will let you set a port, but not edit the HTTPS URL which meant I could not get the URL I need to make Google happy without manual changes. Following is the relevant portion of my Contacts.xproj file and it is the SSLPort I had to edit.

<PropertyGroup>
  <SchemaVersion>2.0</SchemaVersion>
  <DevelopmentServerPort>44301</DevelopmentServerPort>
  <SSLPort>44300</SSLPort>
</PropertyGroup>

At this point I can now start the application, but I have to manually use the HTTPS URL to get auth with Google to work since I have not found away to get Visual Studio to launch the using the HTTPS URL.

The good news is Google auth does work now!

ASP.NET 5 IIS Express Configuration and OAuth 2 Read More »

More OAuth

Last week I covered using OAuth with Google for authentication. I thought I would try GitHub next only to find out Microsoft does not have a built in provider. After a little searching I came across OWIN OAuth Providers on GitHub. This project has a ton for providers ranging from BattleNet to Yammer.

To install run the following from the package manager console.

Install-Package Owin.Security.Providers

The rest of the process is very similar to last weeks post. I am going to walk through GitHub for this example but the others are very similar. The big difference for each provider is getting API access.

At the top of Statup.Auth.cs in the App_Start folder add the following.

using Owin.Security.Providers.GitHub;

And at the bottom of the ConfigureAuth function.

app.UseGitHubAuthentication(
    clientId: "Your Client ID",
    clientSecret:"Your Client Secret");

The next setup is to set up API access with GitHub. Login to GitHub and go to Developer applications.

oauthgithub

Click the Register new application button in the upper right of the page. On the registration page enter an application name, homepage URL and authorization callback URL. As last week the URL options will be need to be based on your project settings. After entering all your information click Register application.

oauthgithubRegisterApplication

Then next page will show your client ID and client secret which just need to be entered in Statup.Auth.cs. That is all there is to adding an additional OAuth provider and give your users even more authentication options.

oauthgithubLogin

Using OWIN OAuth Providers makes adding access other OAuth providers just as simple as the providers from Microsoft.

More OAuth Read More »

OAuth 2.0 with Google

After getting Basic Authentication and Authorization working I thought it would be neat to add login via Google which involves using OAuth 2.0. To get started I used NuGet to update all the OWIN related packages in my project. I ran across some people who had issues with older versions of OWIN so I recommend getting the latest to avoid any potential problems.

Some third parties require SSL when using their auth services so I decided to go a head and change my application to use SSL. I hit a couple of issues during this part of the process that I want to point out. The first is that when you change to SSL IIS Express defaults to using port 44300. I missed this the first try and it took a good bit of searching before I spotted the problem. Even after reverting all my changes I could not get my site to load without errors. A reboot got my reverted site working which I am assuming was a configuration issue with IIS Express that got reset on reboot.

To enable SSL select the project in Solution Explorer and press F4 to bring up the properties window (which has different options that the project properties you get if you right-click the project and click properties). Set the SSL Enabled property to true. Copy the SSL URL to use when updating the project.ContactsPropertiesSsl

Back in the Solution Explorer right-click on the project and click properties. On the Web tab under the Servers section paste the SSL URL from above into the Project Url and save.ContactsProjectPropertiesSslUrl

When running the first time after enabling SSL Visual Studio will prompt asking if you would like to trust the self-signed certificate that IIS Express generated. I chose to trust in order to avoid warnings from the browser.

OAuthTrustIISSSL

The last change need in the project is in the Statup.Auth.cs found in the App_Start folder. In the ConfigureAuth function add the following code using your own ClientId and ClientSecret.

app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
{
    ClientId = "Your Client ID",
    ClientSecret = "Your Client Secret"
});

If you don’t have a client ID and client secret head to the Google Developers Console. The first step in the process is to Click the Create Project button.

GoogleDevelopersConsoleEnter a project name and project ID. The refresh button on the project ID field will randomly generate project IDs in case the one you want is already in use. When finished click Create.
GoogleDevelopersConsoleNewProjectAfter the project creation process finishes click on the name of your project. Next click on the APIs & auth section and then click the Consent screen option. This set of options determines what the user sees when Google prompts a user for consent to use information from their Google account. The minimum needed is email address and product name. For a live application I would recommend filling out as much as possible to give the user the best experience. When done click Save.GoogleDevelopersConsoleAPIsAndAuthConsentScreenIn the same APIs & auth section click the APIs option. Search for Google+ API. Click the name Google+ API and on the next screen click Enable API.GoogleDevelopersConsoleAPIsAndAuthApisGooglePlusAgain in the APIs & auth section click on Credentials option and then in the OAuth section fo the page click Create new Client ID.
GoogleDevelopersConsoleAPIsAndAuthCredentialsThe following dialog will show. Select the appropriate Application type which is Web application for this example. For Authorized JavaScript origins use the value from Project Url listed above which in my case is https://localhost:44300/. For Authorized redirect URIs the base URI is the same but with an added level. For MVC 5 the redirect should be set to https://localhost:44300/signin-google changing the base URI as needed of course. Click Create Client ID and you will be returned to the previous page that will now list the Client ID and Client Secret needed in Statup.Auth.cs.
GoogleDevelopersConsoleAPIsAndAuthCredentialsCreateClientId

Now the login page will have a button for Google which will allow users to create an account and associate it with their Google account. After the association users will be able to login with their Google account.LoginWithGoogle

 

From this point adding Microsoft, Facebook or Twitter would just be a matter of adding the desired options to ConfigureAuth Startup.Auth.cs and going to each service and requesting API access.

OAuth 2.0 with Google Read More »

Basic Authentication and Authorization

When I created my contact application I did so with authentication set to Individual User Accounts as seen below.
vs2013NewAspProject

 

By choosing an authentication option during project creation Visual Studio takes care of a lot of the work involved with getting authentication and authorization up and running. For individual user accounts the default data store is SQL and Visual Studio sets up the need classes and data using entity framework to create a database and the needed tables to store authentication data. An AccountController and associated views are also created to handle user creation and login.

I am not going to cover everything that Visual Studio created automatically. I will be walking you through the other changes are needed to start using authentication and authorization with all the bits Visual Studio has provided.

The first step is to add AuthorizeAttribute to the FilterConfig which is found in the App_Start folder.

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
        filters.Add(new AuthorizeAttribute());
    }
}

Now that the AuthorizeAttribute is added to the applications filters any page that is requested by a user that is not authorized will be redirected to a login page to authenticate.

With authorization and authentication now in play any controller action that should allow anonymous usage will need to have the AllowAnonymous attribute added. The following example is using AllowAnonymous on the index action of the home controller.

public class HomeController : Controller
{
    [AllowAnonymous]
    public ActionResult Index()
    {
        return View();
    }
}

That is all there is to get the very basics going. This is a big subject, but Visual Studio and .Net do a lot of work to make getting basics up and going simple.

Basic Authentication and Authorization Read More »