IdentityServer.v3, MembershipReboot, AngularJs, WebApi 2 and MVC : Mix It ! : Part 1

Home

This article is part of a series dealing with IdentityServer.v3 authentication and authorization.

This Part deals with IdentityServer.V3 installation and configuration using MemberShipReboot as the undelying account repository. We will also add BrockAllen’s IdentityManager for admin purposes.

Step 1 : Create the web project

start visual studio and create an empty web project

empty web project

Step 2 : add the Dependencies

Add the following Nuget packages ( some of them are in pre realease, so if you use Nuget UI tool, check that ‘prerelease’ is selected in the checkbox.)

For identity server

install-package Microsoft.Owin.Host.Systemweb
install-package Thinktecture.IdentityServer.v3 -pre

for use with membershipreboot

install-package Thinktecture.IdentityServer.v3.MembershipReboot -pre

for use of Identity Manager

install-package Thinktecture.IdentityManager.MembershipReboot - pre
Install-Package BrockAllen.MembershipReboot.Ef

Step 3: Create a self signed certificate.

Check this post for the long story

simply create a cmd file with the following content:

makecert.exe ^
-n "CN=MixItCARoot" ^
-r ^
-pe ^
-a sha512 ^
-len 4096 ^
-cy authority ^
-sv MixItTest.pvk ^
IdentitySrvCAROOT.cer

pvk2pfx.exe ^
-pvk MixItTest.pvk ^
-spc MixItTest.cer ^
-pfx MixItTest.pfx ^
-po IAmAPassword

on line 2 you have to specify a CA Root (choose whatever example : ‘DevRoot’) and line 15 a password (here : IAmAPassword).

open a visual studio command prompt. (for me it was located here : C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools\Shortcuts , but really depends on your installation) and execute your command file. This will create 3 files. (a .cer for the certificate,  a .pvk which is the private key and a .pfx which contains both)

Create a Config folder in your solution and copy the YourCertFileName.pfx over there. (here MixItTest.pfx)

1.2

On the properties of the pfx file, set The Copy to Output Dir to ‘Copy if newer

1.3

Step 4 : Create the Configuration classes.

In this step we will create a Clients.cs class that will hold our Client and a Scopes.cs class that will hold our InMemory Scope Objects. (these could come from a database or another repository.)

For the Users, we will use a MemberShipReboot repository.

Below is the Clients.cs listing that contains a single Client for now. It uses the Resource Owner flow.

namespace  MixIt.Identity.Server.Config
{
    public static class Clients
    {
        public static IEnumerable<Client> Get()
        {
            return new[]{
            new Client
                {
                    //Resource Owner Flow Client (our web UI)
                    ClientName = "WebUI",
                    Enabled = true,

                    ClientId = "IdentityWebUI",
                    ClientSecret = "secret",

                    Flow = Flows.ResourceOwner,
                    AccessTokenType = AccessTokenType.Jwt,
                    AccessTokenLifetime = 3600

                }
            };
        }
    }
}

The Scopes.cs contains the scopes for our application. for now there are the standard scope (openid…) and a scope that we defined to access our public api (we will create it later).


namespace MixIt.Identity.Server.Config
{
    public static class Scopes
    {
        public static IEnumerable<Scope> Get()
        {
            var scopes = new List<Scope>
            {
                new Scope
                {
                    Enabled = true,
                    Name = "publicApi",
                    Description = "Access to our public API",
                    Type = ScopeType.Resource
                }
            };

            scopes.AddRange(StandardScopes.All);

            return scopes;
        }
    }
}

add a MemberShip Reboot User Service:

 public class MembershipRebootUserServiceFactory
    {
        public static IUserService Factory(string connString)
        {
            var db = new DefaultMembershipRebootDatabase(connString);
            var repo = new DefaultUserAccountRepository(db);
            var userAccountService = new UserAccountService(config, repo);
            var userSvc = new MembershipRebootUserService<UserAccount>(userAccountService, db);
            return userSvc;
        }

        static MembershipRebootConfiguration config;
        static MembershipRebootUserServiceFactory()
        {
            System.Data.Entity.Database.SetInitializer(new System.Data.Entity.MigrateDatabaseToLatestVersion<DefaultMembershipRebootDatabase, BrockAllen.MembershipReboot.Ef.Migrations.Configuration>());

            config = new MembershipRebootConfiguration();
            config.PasswordHashingIterationCount = 50000;
            config.AllowLoginAfterAccountCreation = true;
            config.RequireAccountVerification = false;
        }
    }

and a Factory.cs class to configure all stores and services (here : scopes, clients and users)

  public class Factory
    {
        public static IdentityServerServiceFactory Configure(string connString)
        {
            var factory = new IdentityServerServiceFactory();

            factory.UserService =
                new Registration<IUserService>(resolver => MembershipRebootUserServiceFactory.Factory(connString));

            var scopeStore = new InMemoryScopeStore(Scopes.Get());
            factory.ScopeStore = new Registration<IScopeStore>(resolver => scopeStore);

            var clientStore = new InMemoryClientStore(Clients.Get());
            factory.ClientStore = new Registration<IClientStore>(resolver => clientStore);

            return factory;
        }
    }

Step 5 : Glue it with the Startup.cs

public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.Map("/identity", idsrvApp =>
            {
                idsrvApp.UseIdentityServer(new IdentityServerOptions
                {
                    SiteName = "Identity Server",
                    IssuerUri = "https://idsrv3/mixit",
                    SigningCertificate = LoadCertificate(),

                    Factory = Factory.Configure("MyIdentityDb"),

                    CorsPolicy = CorsPolicy.AllowAll
                });
            });

        }

        X509Certificate2 LoadCertificate()
        {
            return new X509Certificate2(
                string.Format(@"{0}\bin\Config\MixItTest.pfx", AppDomain.CurrentDomain.BaseDirectory), "IAmAPassword");
        }
    }

Step 6 : add configuration in the Web.config file

  • add the RAMMFAR
<system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
  </system.webServer>
  • add the connection string (for the membershipreboot repository)
 <connectionStrings>
    <add name="MyIdentityDb" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=Identity;Integrated Security=True" providerName="System.Data.SqlClient" />
  </connectionStrings>

Step 7 : enable SSL

easy to do with visual studio in dev mode : set the property SSL Enabled to true:

1.4

then copy the SSL URL to the clipboard and right click on the project to open the properties. Click the ‘Web’ Tab and copy the ssl url to Start Url and Project URL .

1.5

Step 8 : Test it

At this point, you should have a running IdentityServer. Just run the project and check the following address (your port might be different than 44305:

https://localhost:44305/identity/.well-known/openid-configuration

the browser should display something like this:

1.6

Step 9 : configure IdentityManager.

Identity Manager is a tool created by BrockAllen to manage Identity (can be through MembershipReboot or Asp.net Identity). Here we deal with MembershipReboot. We will create a class to configure the IdentityManager (MembershipRebootIdentityManagerFactory.cs) then map it in the Startup.cs file. here is the class taken from the MembershipReboot samples:

namespace MixIt.Identity.Server.Config
{
    public class MembershipRebootIdentityManagerFactory
    {
        static MembershipRebootConfiguration<RelationalUserAccount> config;
        static MembershipRebootIdentityManagerFactory()
        {
            System.Data.Entity.Database.SetInitializer(new System.Data.Entity.MigrateDatabaseToLatestVersion<DefaultMembershipRebootDatabase, BrockAllen.MembershipReboot.Ef.Migrations.Configuration>());

            config = new MembershipRebootConfiguration<RelationalUserAccount>();
            config.PasswordHashingIterationCount = 5000;
            config.RequireAccountVerification = false;
        }

        string connString;
        public MembershipRebootIdentityManagerFactory(string connString)
        {
            this.connString = connString;
        }

        public IIdentityManagerService Create()
        {
            var db = new DefaultMembershipRebootDatabase(this.connString);
            var userrepo = new DefaultUserAccountRepository(db);
            var usersvc = new UserAccountService<RelationalUserAccount>(config, userrepo);

            var grprepo = new DefaultGroupRepository(db);
            var grpsvc = new GroupService<RelationalGroup>(config.DefaultTenant, grprepo);

            var svc = new MembershipRebootIdentityManagerService<RelationalUserAccount, RelationalGroup>(usersvc, userrepo, grpsvc, grprepo);
            return new DisposableIdentityManagerService(svc, db);
        }
    }
}

In the Startup.cs class add the following mapping

...
  app.Map("/admin", adminApp =>
            {
                var factory = new MembershipRebootIdentityManagerFactory("MyIdentityDb");
                adminApp.UseIdentityManager(new Thinktecture.IdentityManager.IdentityManagerConfiguration()
                {
                    IdentityManagerFactory = factory.Create
                });
            });

...

“MyIdentityDb”  is the connection string that you configured in the Web.config.

To test it go to the following address: https://localhost:44305/admin#/
you should see something like this:
1.7

 

Try it and create a user ‘test’ for example. we will use ‘Fiddler’ to get a token using post requests with the Client that we have configured.

NB : the menus (All Users, Create new…) may take a moment to load.

Step 10 : Test IdentityServer with Fiddler

When you check the document received from https://localhost:44305/identity/.well-known/openid-configuration, you can see that the property token_endpoint is set to : https://localhost:44305/identity/connect/token.
We will use that endpoint to get a token. Therefor, just issue the following HTTP POST request to that endpoint:

-------------------
Post :
https://localhost:44305/identity/connect/token

Headers:
User-Agent: Fiddler
Content-Type: application/x-www-form-urlencoded
Authorization: Basic SWRlbnRpdHlXZWJVSTpzZWNyZXQ=

Body:
grant_type=password&username=test&password=tes5&scope=openid
------------------

(the string SWRlbnRpdHlXZWJVSTpzZWNyZXQ= comes from the Base64 encoding of IdentityWebUI:secret which is our clientId and client secret located in our Clients.cs file. I use the Fiddler text wizard to do that.)

1.8

If you have created a user with username = ‘test’ and password  =’test’, then the result will give you an access token:

1.9

If you try with an incorrect password for example, you should receive the following:

{“error”:”invalid_grant”}

That’s it ! in the next article, we will create the webapi that will be used to create a user using membershipreboot

As Usual, comments are welcome and even remarks to update this little documentation.

16 thoughts on “IdentityServer.v3, MembershipReboot, AngularJs, WebApi 2 and MVC : Mix It ! : Part 1”

  1. yes i have to update my code to use the new released version. i ve been following thinktecture identity server for month now and wanted to check if i could use it in my own use case. response is yes of course, but i have not much time to update

    1. Hey Cedric,
      Do you have any plans on updating your solution to match the recent MembershipReboot changes.

      Awesome articles, helped me a lot on getting things setup!!!

  2. Hello Cedric,

    Your artcile helping several people. Yours is the best among all other whatever I came accross.

    Could you please update your solution on GitHub with new packages?

    There are two errors with new packages.
    1) Not finding IdentityManagerConfiguration in Startup.cs
    public void Configuration(IAppBuilder app)
    {
    app.Map(“/admin”, adminApp =>
    {
    var factory = new MembershipRebootIdentityManagerFactory(“MyIdentityDb”);
    adminApp.UseIdentityManager(new IdentityManagerConfiguration()
    {
    IdentityManagerFactory = factory.Create
    });
    });
    2) Not finding DisposableIdentityManagerService in MembershipRebootIdentityManagerFactory
    return new DisposableIdentityManagerService(svc, db);

    I tried to remove these errors but could not succeeded.

    Thanks for all your hardwork.

  3. Hello Cedric,

    Your artcile helping several people. Yours is the best among all other whatever I came accross.

    Could you please update your solution on GitHub with new packages?

    There are two errors with new packages.
    1) Not finding IdentityManagerConfiguration in Startup.cs
    public void Configuration(IAppBuilder app)
    {
    app.Map(“/admin”, adminApp =>
    {
    var factory = new MembershipRebootIdentityManagerFactory(“MyIdentityDb”);
    adminApp.UseIdentityManager(new IdentityManagerConfiguration()
    {
    IdentityManagerFactory = factory.Create
    });
    });
    2) Not finding DisposableIdentityManagerService in MembershipRebootIdentityManagerFactory
    return new DisposableIdentityManagerService(svc, db);

    I tried to remove these errors but could not succeeded.

    Thanks for all your hardwork.

  4. Hi, in fact I will update it with some changes : Owin to asp.net 5 (or vnext in Vs 2015) and angular to aurelia…. but I have a huge heap of work and I started a new own project where I will use Idsrv 3 and aurelia (aurelia.io) … so it’s taking me a lot of time. But perhaps it would be better to just update the code for now (with a new angular-toolkit.js file I’ve created to get openid (idsrv3, salesforce, google… ) support and add changes later on… I will try to do it this weekend

  5. Now it’s required for the secret to be hashed. You can simply change “secret” to “secret”.Sha256()

  6. Hey Cedric,

    Just downloaded your sample from Github and complied it but the MembershipReboot part doesn’t work probably. The call to /admin/api when hitting https://localhost:44305/admin#/ returns an error with the following JSON truncated message:
    exceptionMessage=An error occurred when trying to create a controller of type ‘MetaController’. Make sure that the controller has a parameterless public constructor.
    exceptionMessage=An exception was thrown while executing a resolve operation. See the InnerException for details. —> A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 – Error Locating Server/Instance Specified) (See inner exception for details.)

    Therefor, “All Users”, “Create new” menu items are not showing up.

    Note, I get the same error whether am updating NuGet packages with latest versions or not.

    Can you help with that?

    Firas

  7. Cedric,
    Below packages are not available on nuget

    install-package Thinktecture.IdentityServer.v3.MembershipReboot -pre
    nstall-package Thinktecture.IdentityManager.MembershipReboot – pre
    install-package Thinktecture.IdentityServer.v3 -pre

    So, can you tell how can we get this ?
    Rohit

    1. New package are :
      install-package Thinktecture.IdentityServer3 -pre
      install-package IdentityServer3.MembershipReboot -pre

  8. To whoever is using the latest Beta package, this is how you configure Identity Manager
    app.UseCookieAuthentication(new Microsoft.Owin.Security.Cookies.CookieAuthenticationOptions
    {
    AuthenticationType = “Cookies”
    });
    app.Map(“/admin”, adminApp =>
    {

    var options = new IdentityManagerOptions
    {
    Factory = new IdentityManagerServiceFactory
    {
    IdentityManagerService = new IdentityManager.Configuration.Registration(
    new MembershipRebootIdentityManagerFactory(“abhyankars.authdb.connection”).Create(), “membershiprebootSvc”)
    },
    SecurityConfiguration = new HostSecurityConfiguration
    {
    RequireSsl = false,
    HostAuthenticationType = “Cookies”,

    }
    };
    app.UseIdentityManager(options);

    });

    And for the MembershiprebootFactory:
    public IIdentityManagerService Create()
    {
    var db = new DefaultMembershipRebootDatabase(“Server=.;Database=abhyankars.authdb;Trusted_connection=true; Connection Timeout=180”);
    var userrepo = new DefaultUserAccountRepository(db);
    var usersvc = new UserAccountService(config, userrepo);

    var grprepo = new DefaultGroupRepository(db);
    var grpsvc = new GroupService(config.DefaultTenant, grprepo);

    return new MembershipRebootIdentityManagerService(usersvc, userrepo, grpsvc, grprepo);
    // return new DisposableIdentityManagerService(svc, db);
    }

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: