This is the 3rd post in a 3 part series on custom claims identity management in the enterprise. Firstly, I would like to apologise for those who have been waiting for this post.
ThinkTecture is a custom identity provider which is a great choice to enable claims authentication from existing applications. This post will show you how to extend IdentityServer to your own identity store.
In order to follow this blog you will need to download the identity server source-code which can be found on GitHub https://github.com/thinktecture/Thinktecture.IdentityServer.v2
Once downloaded, the easiest way to extend ThinkTecture is to open the solution in Visual Studio, this will give you full debug while you make the modifications.
ThinkTecture is a well-organised and easy to follow solution making good use of SOLID principles. This makes the solution very easy to read, extend and adapt.
One of the common requirements for SSO extensibility is providing custom claims and access control mechanisms. There are many ways to achieve this, but I would recommend utilising the existing core libraries without a pass-through mechanism. This enables you to continue to use the membership provided with ThinkTecture, but provide additional access control from your own solution.
From the above Image you will see I have created a new assembly (Gstt.Icm.Repository). This will be my extension to identity-server.
Identity server makes use of 2 primary interfaces for user and claim management, IUserRepository and IClaimsRepository. These types can be found in the ThinkTecture.IdentityServer.Core assembly. As we are also extending the existing User and Claims Repositories you will need the following assembly references.
With these references you are now ready to setup the environment to implement this tutorial. To execute this tutorial we will need a sample database, which will represent our 3rd party system. For this sample I am using SQL Server 2012 and am using the sample data as below.
Once the database has been configured you should see the SQL schema below:
With the above complete, we can now create our data access components. To do this I have created a Domain folder in the class library and generated a new Entity Framework edmx model. This database is a representation of the schema above created in .NET EF 5.0 Database First.
With the schema generated we will need to include the connection string generated by EF. Identity Server stores all configuration in the configuration folder under the web application. Open the connectionString.config settings and add the new connectionString to the SQL database as created above. Please remember that as a web-application the identity of the application pool should have the required rights to the SQL database, alternatively configure SQL authentication in the configuration file and encrypt the config.
Once complete you should have a new entry in the connectionString.config.
Moving on, you will need to create 2 new class files in your extension project. These classes will derive from IUserRepository and IClaimsRepository as above. To make life easier, copy the existing code from the Thinktecture core repositories below to these new files. Rename the files relative to your identity store.
This will leave you with a project that has the skeleton from Identity Server. What we need now is an additional type to our new library which we will use as a repository to talk to *our* SQL database. Below is a sample of the interface and implementation for the new database module.
With the new types in the project you should have a class library project which looks something like below.
The eager eyes out there will notice that I also have 3 additional types in my project, GsttConfigurationSection and IcmExportProvider. IcmClaimsRepository and IcmRepository are my custom implementations of IUserRepository and IClaimsRepository.
ThinkTecture makes use of the Microsoft Extensibility Framework (MEF) to enable runtime initialisation of components and dependency injection. This provides the software with the ability to swap out components at Runtime (such as the repositories we are building). To keep our new assembly in alignment with the conventions provided in ThinkTecture we will make use of MEF, this means creating our own configuration file and MEF Export Provider.
Below is a sample of the Config section and IcmExportProvider. As you can see from the code below, we are creating a new config section called gstt.repositories with an attribute of icmUserManagement. This will provide MEF with the catalogue type entries for runtime type configuration.
Out of the box ThinkTecture comes with a RepositoryExportProvider type providing the catalogue services for Core components. To keep consistent with ThinkTecture, we create the following MEF export catalogue. This is a direct copy of the existing code but with my custom type registered, this enables you to swap out my component and hook into your own identity store if you wish to use my extension approach.
As you can see from the above the ExportProvider is used to provide a dynamic type registration from our new config section.
With the config section complete and the MEF export catalogue configured we can now modify identity server to include the additional files and configuration. To start this process we need to modify the Global.ascx.cs file and register the new MEF Export Provider. Inside the global ascx file, we need to register the new Export Provider, this is achieved via the CompositionContainer constructor (SetupCompositionContainer method):
Now the Global configuration has been set you will be able to use the MEF [Import] attribute to include your types dynamically via configuration at runtime. To complete this part of the tutorial you will need to include the config file, this is done via modification of the web.config, including the new config section. The section below shows the GSTT configuration section registration xml element.
Configuration sections and types are registered using the Gstt.Icm.Repository.IcmUserRepository, Gstt.Icm.Repository (Fully Qualified Type Name, Assembly Name).
Now we are ready to use all the types and modifications we have made and change the ThinkTecture configuration. As we are only extending the role system and login system I add a domain level qualifier to the ThinkTecture UserRepository and ClaimRepository. The code snippet below shows my custom implementation of the UserRepository service, this service utilises a domain qualifier of TT\* to identify ThinkTecture users and allows backwards compatibility.
If you login to ThinkTecture using TT\Admin we direct to the ASP.NET membership system, alternatively we use the MEF imported repository to check against our custom SQL store.
The same logic applies to the claims repository, we swap out the roles with the roles from the SQL database:
With all the above complete and our new database referenced the final step is to modify the configuration/repositories.config in the web project, registering our new User and Claims Repository.
One thing to remember, in order to get the best developer experience bind the VS project to IIS root and on the first run, ensure you visit the /InitialConfiguration controller.