Single Sign-on with OpenID Connect
Single Sign-on with OpenID Connect enables you to leverage existing credentials configured in a UAA Server or TAS Single-Sign-on service for authentication and authorization in ASP.NET 4.x (via OWIN middleware) and ASP.NET Core applications.
Usage
Usage in ASP NET Core
Steeltoe builds on top of Microsoft.AspNetCore.Authentication.OpenIdConnect
. You may benefit from reading more about using OpenID Connect in ASP.NET Core.
Usage of Steeltoe's OpenID Connect provider is effectively identical to that of the OAuth2 provider, although the behind-the-scenes story is a little different. The OpenID Connect provider uses Microsoft's OpenId Connect implementation, and settings are based on Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectOptions
, with these additional properties:
Name | Description | Default |
---|---|---|
additionalScopes | Scopes to request for tokens in addition to openid |
string.Empty |
validateCertificates | Validate Auth server certificate | true |
Note: Each setting above must be prefixed with security:oauth2:client
.
Aside from the different base class for options, the only usage change is to call .AddCloudFoundryOpenId
instead of .AddCloudFoundryOAuth
.
Usage in ASP NET 4
This package is built on OpenID Connect and OWIN Middleware. You should take some time to understand both before proceeding to use this provider.
Resources are available elsewhere for understanding OpenID Connect. For example, see Understanding OAuth 2.0 and OpenID Connect.
To learn more about OWIN, start with the Overview of Project Katana.
Additionally, you should know how the .NET Configuration service and the ConfigurationBuilder
work and how to add providers to the builder.
With regard to Cloud Foundry, you should know how Cloud Foundry OAuth security services (for example, UAA Server or TAS Single Signon) work.
In order to use the Security provider:
- Create an instance of a Cloud Foundry OAuth service and bind it to your application.
- (Optional) Configure any additional settings the Security provider needs.
- Add the Cloud Foundry configuration provider to the
ConfigurationBuilder
. - Add the security provider to the OWIN pipeline in the application.
- Secure your endpoints.
Add NuGet Reference
To use the provider, use the NuGet package manager to add a reference to the Steeltoe.Security.Authentication.CloudFoundryOwin
package.
Configure Settings
Configuring settings for the provider beyond what is provided in a service binding is not typically required, but when Cloud Foundry is using self-signed certificates, you might need to disable certificate validation, as shown in the following example:
{
"security": {
"oauth2": {
"client": {
"validateCertificates": false
}
}
}
}
The samples and most templates are already set up to read from appsettings.json
.
This full list of settings can also be configured, though AuthDomain
, ClientId
and ClientSecret
will be overridden by service bindings (if present).
Name | Description | Default |
---|---|---|
additionalScopes | Scopes to request for tokens in addition to openid |
string.Empty |
authDomain | Location of the OAuth2 server | https://Default_OAuthServiceUrl |
authenticationType | Corresponds to the IIdentity AuthenticationType | CloudFoundry |
callbackPath | Path the user is redirected back to after authentication | /signin-cloudfoundry |
clientId | App credentials with auth server | Default_ClientId |
clientSecret | App credentials with auth server | Default_ClientSecret |
validateCertificates | Validate OAuth2 server certificate | true |
Note: Each setting above must be prefixed with security:oauth2:client
.
NOTE: Prior to Steeltoe 2.2, the default value for CallbackPath was
/signin-oidc
Cloud Foundry
As mentioned earlier, there are two ways to use OAuth2 services on Cloud Foundry. We recommend you read the offical documentation (UAA Server and TAS SSO) or follow the instructions included in the samples for UAA Server and TAS SSO to quickly learn how to create and bind OAuth2 services.
Regardless of which provider you choose, once the service is bound to your application, the settings are available in VCAP_SERVICES
.
Configure OWIN Startup
In order to configure the Cloud Foundry OWIN OAuth provider in your application, you will need an OWIN Startup class if you do not already have one.
using Steeltoe.Security.Authentication.CloudFoundry.Owin;
using System;
using System.IdentityModel.Claims;
using System.Linq;
using System.Web.Helpers;
[assembly: OwinStartup(typeof(CloudFoundrySingleSignon.Startup))]
namespace CloudFoundrySingleSignon
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType("ExternalCookie");
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "ExternalCookie",
AuthenticationMode = AuthenticationMode.Active,
CookieName = ".AspNet.ExternalCookie",
LoginPath = new PathString("/Account/AuthorizeSSO"),
ExpireTimeSpan = TimeSpan.FromMinutes(5)
});
app.UseCloudFoundryOpenIdConnect(ApplicationConfig.Configuration);
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
}
}
}
The app.UseCloudFoundryOpenIdConnect
method call adds an authentication middleware that has been configured to work with UAA or TAS SSO to the OWIN Request pipeline.
TIP: This code is commonly refactored into a separate class (for example
Startup.Auth.cs
), particularly when there is additional configuration on the OWIN pipeline.
Redirecting to OAuth Server
To redirect the user to the OAuth server for authentication, invoke IAuthenticationManager.Challenge
, specifying a redirect uri (for the user to land on after authentication) and the string value configured as the authentication type.
In Steeltoe 2.2 and up, the default value for AuthenticationType is CloudFoundryDefaults.DisplayName
or "CloudFoundry". Prior to Steeltoe 2.2, this value was PivotalSSO
and was not configureable. The now-deprecated extension .UseOpenIDConnect()
still uses that as the default, but can be overridden in OpenIDConnectOptions
.
public void AuthorizeSSO(string returnUrl)
{
var properties = new AuthenticationProperties { RedirectUri = returnUrl ?? Url.Action("Secure", "Home") };
HttpContext.GetOwinContext().Authentication.Challenge(properties, CloudFoundryDefaults.DisplayName);
}
NOTE: The second parameter passed to
Authentication.Challenge
must match the authentication type used to configure the provider; this is the piece that hands the flow over to Steeltoe.
If you wish to allow your controller action to return ActionResult
instead of void, refactor the call to Challenge
into a class that inherits HttpUnauthorizedResult
such as this
internal class ChallengeResult : HttpUnauthorizedResult
{
public ChallengeResult(string authType, string redirectUri)
{
AuthenticationType = authType;
RedirectUri = redirectUri;
}
public string AuthenticationType { get; set; }
public string RedirectUri { get; set; }
public override void ExecuteResult(ControllerContext context)
{
var properties = new AuthenticationProperties { RedirectUri = RedirectUri };
context.HttpContext.GetOwinContext().Authentication.Challenge(properties, AuthenticationType);
}
}
The updated controller code would then look like this:
public ActionResult AuthorizeSSO(string returnUrl)
{
return new ChallengeResult(CloudFoundryDefaults.DisplayName, returnUrl ?? Url.Action("Secure", "Home"));
}
Securing Endpoints
Once the Startup
class is in place and the middleware is configured, you can use the standard ASP.NET Authorize
attribute to require authentication, as shown in the following example:
using System.Web.Mvc;
...
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[Authorize]
public ActionResult Secure()
{
ViewData["Message"] = "This page requires authentication";
return View();
}
...
}
Requiring claims is not built into the framework, so it is not quite as simple as in ASP.NET Core, but is still possible in a variety of ways. The Steeltoe SSO sample demonstrates extending the Thinktecture ClaimsAuthorizeAttribute with a CustomClaimsAuthorizeAttribute to redirect to an "Access Denied" page when a user is authenticated but lacks the required claim. Using either of those attributes is straightforward, as shown in this example:
// When using this attribute, an authenticated user who does not have the claim will be redirected to the login page
[ClaimsAuthorize("testgroup")]
public ActionResult TestGroupV1()
{
ViewBag.Message = "Congratulations, you have access to 'testgroup'";
return View("Index");
}
[CustomClaimsAuthorize("testgroup")]
public ActionResult TestGroupV2()
{
ViewBag.Message = "Congratulations, you have access to 'testgroup'";
return View("Index");
}