Compliant Implementation of RP on ASP.NET
- 1 Summary
- 2 Status
- 3 Implementation
- 3.1 Version Control
- 3.2 Implementation on ASP.NET only
- 3.3 Adding Functionality for Dynamic Registration
- 4 References and Coordination
Compliant Implementation of a relying party (RP) on ASP.NET using OpenID Connect with a variety of federated OpenID Connect Providers (OP).
This is a sample of a new category to show how compliant implementations of Relying Parties can be created using existing technologies.
This example is built on OpenId Connect protocols on an ASP.NET technology from Microsoft. An attempt is made to avoid more dependencies than necessary.
Each implementation needs to have its own identity together with a versioning system to be incremented when changes to the implementation are made.
Versions of ASP.NET
While all versions of ASP.NET based on Microsoft Identity Model can be used to create a Relying Party (RP) implementation, this will focus on those where OpenId Connection was functional.
Note that as of March 2017 no version of ASP.NET supported dynamic registration of OpenId Providers (known in the protocol specification as OP or in this document as Identity Providers IdP). So we will first discuss implementation of the supported versions of OpenId Connect and later on the dynamic and other implementations of OpenId connect protocols.
- Version 4.5 of .NET framework will allow building a compliant RP on Visual Studio 2013. In this version the Identity Model and other features are separate ASP.NET features and some operations have been made asynchronous.
- Version 1.0 and 1.1 of ASP.NET core will allow building a compliant RP on Visual Studio 2015 community (free) edition with a restricted project control file. The model is rebuilt to use asynchronous calls for a more performant implementation that is fully integrated. There are some breaking changes with ASP.NET core that are discussed in the following section.
- Version 1.1.1 of ASP.NET core will allow building a compliant RP on Visual Studio 2017 community (free) edition with more robust project and dependency definitions. Upgrading to this version from the previous version is possible, but not recommended.
- Version 2.0 of ASP.NET core will be introduced in mid 2017 as will have other breaking changes in the way that it handles User Objects.
As of version 1.1.1 all of the ASP.NET core is open source, so that will be assumed to be the best solution for what follows. But only the 1.0 version qualifies for long term support.
RP Version without dynamic IdP Registration
Using ASP.Net core with no significant dependencies provides an implementation that appears to be fully OpenId Connect compliant except for the shortage of error messages. Unfortunately that cannot be verified by the OpenId Connection RP API test suite as it depends on dynamic registration and a frankly non-compliant user ID to be entered into the RP to trigger the protocol interchange with the OP.
ASP.Net Core is a change from the role based authorization model to a claims based model which is more in conformance with the IDESG Identity Model. This change is both good news (claims are a better way to understand the user) and bad news (roles are the methods in current wide use throughout industry). In line with the Identity Model the changes available from ASP.Net core are considered to be the better way for new projects and will be followed in examples produced starting in 2017.
RP Version with dependency on dynamic IdP Registration
ASP.NET requires two additions to pass the OpenId Connect RP API test suite:
- it must implement the optional dynamic registration capability,
- it must cope with a non-compliant ID configuration or in some other method map a compliant ID to a OP authority host IP address with a port number.
There are two definitions of the scheme used for an identifier that are supported by OpenID Connect and a third which might appear in other contexts:
- mailto: scheme specified in RFC 822 and RFC 1122 where it is defined as "firstname.lastname@example.org" where "a" is usually considered to be a name and "b.c" to be the host name of the Identity Provider (IdP).
- acct: scheme specified in RFC 7565 which allows compatibility with Open ID 1.0, but is not used anywhere else.
- xmpp: scheme specified in RFC 6122 which enables presence protocols, but does not appear widely in identity protocols.
Only the mailto: scheme is supported by ASP.NET. Note that none of the IETF standard schemes allows for the inclusion of a port number with the host name. What is confusing is that RFC 3986 does define an "Authority" which does allows a port number in section 3.2, but there is no scheme associated with this so it is not realizable in practice.
Implementation on ASP.NET only
In all of the cases described above OpenID Connect is implemented as an authentication filter on the MVC (model/view/controller) pipeline, which was originally called OWIN (in the Katana release), but now is just part of ASP.NET core. Just using Visual Studio to create an MVC web application with individual authentication will enable this pipeline and show where to add any of the available OpenID components. This pipeline is dependent on a set of authentication options that are defined on each middleware add-in to the pipeline. The authentication options are an updatable state of the connection between the authentication middleware and a single web host address for configuration information from the OP. That information can change from time to time reflecting the relationship between the middleware and the OP. There is no method for supporting more than one host address associated with more than one set of middleware. The result is that there is one unique middleware for supporting Google, Facebook, Microsoft and other well known authentication sources. While a somewhat generic middleware is provided for OpenID Connect, it can only be bound to a single host address for authentication information. No clear method is provided for adding information that varies from one user or OP to another within the same middleware, not is it possible to override the authentication options as they are in a class bound to several of the middleware generic classes and methods as a type. All of the OpenID Connect add-ons run with "authorization code flow", which is the preferred way for a Relying Parting web site to operate for security reasons. Specifically only the "authorization code flow" will keep all access to User Private Information behind protected TLS connections between the RP and OP at all times. A diagram is available by clicking on this link to the Identity Model.
If the relying party web site can accommodate the above limitations for its initial implementation, the following steps describe one easy way to get operational.
- Select the version of ASP.Net Core to use. While it is not recommended there is a great description of versions 1.0 that has a very informative protocol flow diagram here.
- Select the version of Visual Studio to build the solution. The recommendation is to use VS 2017 and .NET 1.1.1 if possible. But note that only 1.0 is slated for long term support by Microsoft.
- Start Visual Studio and create an MVC web app, it is recommended to select (.NET Core) rather than (.NET Framework). This option will allows deployment on most open source platforms as well as Windows.
- Pick a good name and file folder for the solution and click OK.
- After a short delay another dialog box will allow the selection of "Web Application" and "Change Authentication". Click "Change Authentication" and then "Individual User Accounts". This is slightly misleading in that the app build will allow for local user accounts by default, which may or may not be part of the design, but this will give the developer the opportunity to add OpenID Connect middleware. Later the Individual Local Accounts can be disabled, but there are reasons why leaving that option could be useful later. Note that the structure of the database built by this application does require that there are user records for every user that is registered. Also note that the signin (or login) records that are created for OpenID federated logons can be added to a local account without requiring that the email address associated with the federated signin is stored anywhere in the database. That is because Id Providers like Google, Facebook and Microsoft provide account identifiers that are only linked to the email address in the IdP internal database.
- At this point you should be able to hit F5 to start debug and see the web site. If you look at the Startup.cs page you will see links to enable the various OpenID Providers.
- You may need to create a sql logon: CREATE LOGIN "NT AUTHORITY\NETWORK SERVICE" FROM WINDOWS
An alternate to that method is to use the code described in the Best Practices and Example for RP System which has a description on ways to make your relying party web site compliant with less effort on your part.
Protecting the data in Transit
OpenID Connect requires the use of encryption (usually SSL or TLS) on any path that carries secret or private information. During development this can be a challenge, but since all compliant production sites have it implemented, it may become necessary during development. It is always necessary for deployment.
Enable SSL(TLS) on the project by clicking on the debug tab in the project properties and selecting "Enable SSL". Then go to the launchSettings JSON file to change the application URL to contain the SSL port (something like "https://localhost:443xx/".
Now make a self-signed SSL certificate. The makecert utility is typically in some directory like "C:\Program Files (x86)\Windows Kits\10\bin\x64. Use the following with your own file and program names. The example are shown run in PowerShell.
PS C:\Program Files (x86)\Windows Kits\10\bin\x64> .\makecert -sv IDESGrp.pvk -n "CN=IDEGrp" IDESGrp.cer -r Succeeded PS C:\Program Files (x86)\Windows Kits\10\bin\x64> .\pvk2pfx.exe -pvk .\IDESGrp.pvk -spc .\IDESGrp.cer -pfx .\IDESGrp.pfx PS C:\Program Files (x86)\Windows Kits\10\bin\x64> dir IDESGrp * Directory: C:\Program Files (x86)\Windows Kits\10\bin\x64 *Length Name *-------- ---- * 750 IDESGrp.cer * 2488 IDESGrp.pfx * 1212 IDESGrp.pvk
Adding Functionality for Dynamic Registration
Using the ASP.NET Core code for dynamic OpenID Connect registration requires either a separate piece of proxy code or a separate middleware added to the ASP.NET as a dependency. The latter case is the most compact solution known at the present time. Some limitations with ASP.NET Core 1.x releases are:
- URI fragments are not supported by ASP.NET Core 1.x, which means that only "authorization code flow" is supported for IDESG compliance, which is the preferred flow for security reasons. A description about why the other flows were added to OpenID connect is here which describes the benefits of the id_token used in those other flows. The major reason was to limit the number of web requests from the RP (client) to the OP, which is more important for client code running in the device than for the client code running in a RP web application as is described in this paper.
To construct a dynamic OpenID Connect compliant web site there are two options available:
- first follow the above steps and then add the dependency on dynamic code as show below,
- get the sample code from GitHub which will bring in the ASP.NET and other dependencies as required.
This sample code and TC.AUTHENTICATION library for supporting OpenID Connect with dynamic registration is freely available here.
Currently a working draft of the Relying Party example web site that has been certified by the OpenID foundation is running here.
Getting a certificate of compliance from the OpenID foundation is a challenge that seems to be unrelated to constructing a successful implementation. Here are some of the challenges and solutions:
- The relying party testing regime requires test like basic authentication. Since the test sends a configuration that allows for other authentication types it is necessary for the relying party code to enforce base authentication in a situation that normal operations would consider to be against best practices.
- The certification for the OpenID Identity Provider (OP) does not test for all fields, like response_mode which requires to the relying party code to adapt to OPs that will not accept that option.
- Dynamic registration is required which means that the standard library from Microsoft will not build a web site that can be easily certified. The dynamic library described below will make certification much easier. It also solves the above issues with certification.
References and Coordination
- Best Practices and Example for RP System gives a better description of the user experience of an IDESG compliant RP system.
- The ASP.NET core is open source and runs on most web servers. This reference compares the core version to the older .NET framework which only runs on Windows.
- The Introduction to ASP.NET Identity provides links to the various components for managing User Objects with the new versions of ASP.NET.
- Adding Microsoft Account Sign In to the above implementation.
- Andrew Lock has a good description on the change of ASP.Net from role-based to claims-based authorization in this paper. He does make one common mistake in discussing claims-based AUTHENTICATION when what he means is claims-base AUTHORIZTION. As is described in the Identity Model authentication should be carried out with no claims (attributes) from the user at all. There is a part of the Microsoft community that defines authorization as providing the information about who you are, in all its detail.
- Any comments, suggestions or issues with the best practices or code can be tracked at this site.
- General comments about this web page can be made on the "Discussion" tab at the top of the page.