Custom access tokens
Overview
Requests can be authorized with access tokens other than Sitefinity's OAuth2 tokens if necessary. Since Sitefinity CMS` authorization is based entirely on user accounts, only external identity providers that issue a unique user identifier can be used. The user must have logged into Sitefinity CMS at least once using the specific IP for its related local user account to have been created.
(A) The exact method of obtaining the token is up to the specific implementation and use case - it could be an OpenID Connect with OAuth2 flow or some other standardized or non-standardized protocol.
(B) The IP access token needs to be validated in Sitefinity CMS via custom code.
Sample validator
This sample show how to validate a custom access token issued by a generic OIDC.
using System;
using System.IdentityModel.Tokens;
using System.Linq;
using System.Threading;
using Microsoft.IdentityModel.Protocols;
using Microsoft.Owin;
using Telerik.Sitefinity.Abstractions;
using Telerik.Sitefinity.Authentication.Owin.SitefinityAuthentication;
namespace SitefinityWebApp
{
public class IdentityServerTokenValidator : ICustomAccessTokenValidator
{
public CustomAccessTokenValidatorResult TryAuthenticateWithCustomToken(IOwinContext ctx)
{
string result = null;
SecurityToken validatedToken = null;
string rawTokenValue = null;
if (ctx.Request.Headers.ContainsKey("Authorization"))
{
rawTokenValue = ctx.Request.Headers["Authorization"];
if (rawTokenValue != null)
{
rawTokenValue = rawTokenValue.Split(' ')[1];
try
{
string issuer = "https://localhost:5001";
var configurationManager = new ConfigurationManager<OpenIdConnectConfiguration>($"{issuer}/.well-known/openid-configuration", new System.Net.Http.HttpClient());
var openIdConfig = configurationManager.GetConfigurationAsync(CancellationToken.None).Result;
var validationParameters =
new TokenValidationParameters
{
IssuerSigningTokens = openIdConfig.SigningTokens,
ValidIssuer = issuer,
ValidateAudience = false
};
JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
var user = handler.ValidateToken(rawTokenValue, validationParameters, out validatedToken);
result = user.Claims.FirstOrDefault(c => c.Type == "sub")?.Value;
}
catch (Exception e)
{
Log.Write("Error authorizing thir party token: " + e.Message, System.Diagnostics.TraceEventType.Warning);
}
}
}
if (result != null)
{
return new CustomAccessTokenValidatorResult()
{
ExternalUserId = result, // the unique identifier returned by the identity provider
Provider = null, // the external auth provider is using the default local provider to store the local accounts
ExpireUTC = validatedToken.ValidTo, // must be UTC
TokenIdentifierValue = rawTokenValue // could also return hash of the token if too big
};
}
else
{
return null;
}
}
}
}
Register the custom validator
Add the following code to the Global.asax file:
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
Bootstrapper.Bootstrapped += Bootstrapper_Bootstrapped;
}
private void Bootstrapper_Bootstrapped(object sender, EventArgs e)
{
ObjectFactory.Container.RegisterType<ICustomAccessTokenValidator, IdentityServerTokenValidator>(new ContainerControlledLifetimeManager());
}
}