[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class CustomAuthenticateAttribute : RequestFilterAttribute
{
/// <summary>
/// Initializes a new instance of the <see cref="CustomAuthenticateAttribute"/> class.
/// </summary>
/// <param name="applyTo">
/// The apply to.
/// </param>
public CustomAuthenticateAttribute(ApplyTo applyTo)
: base(applyTo)
{
this.Priority = (int)RequestFilterPriority.Authenticate;
}
/// <summary>
/// Initializes a new instance of the <see cref="CustomAuthenticateAttribute"/> class.
/// </summary>
public CustomAuthenticateAttribute()
: this(ApplyTo.All)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CustomAuthenticateAttribute"/> class.
/// </summary>
/// <param name="provider">
/// The provider.
/// </param>
public CustomAuthenticateAttribute(string provider)
: this(ApplyTo.All)
{
this.Provider = provider;
}
/// <summary>
/// Initializes a new instance of the <see cref="CustomAuthenticateAttribute"/> class.
/// </summary>
/// <param name="applyTo">
/// The apply to.
/// </param>
/// <param name="provider">
/// The provider.
/// </param>
public CustomAuthenticateAttribute(ApplyTo applyTo, string provider)
: this(applyTo)
{
this.Provider = provider;
}
/// <summary>
/// Gets or sets the name of the authentication provider used.
/// </summary>
public string Provider { get; set; }
/// <summary>
/// Gets or sets the html redirect to be used when authentication fails
/// </summary>
public string HtmlRedirect { get; set; }
/// <summary>
/// The execute.
/// </summary>
/// <param name="req">
/// The req.
/// </param>
/// <param name="res">
/// The res.
/// </param>
/// <param name="requestDto">
/// The request dto.
/// </param>
/// <exception cref="InvalidOperationException">
/// </exception>
public override void Execute(IRequest req, IResponse res, object requestDto)
{
if (AuthenticateService.AuthProviders == null)
{
throw new InvalidOperationException("The AuthService must be initialized by calling AuthService.Init to use an authenticate attribute");
}
var matchingOAuthConfigs = AuthenticateService.AuthProviders.Where(x => this.Provider.IsNullOrEmpty() || x.Provider == this.Provider).ToList();
if (matchingOAuthConfigs.Count == 0)
{
res.WriteError(req, requestDto, "No OAuth Configs found matching {0} provider".Fmt(this.Provider ?? "any"));
res.EndRequest();
return;
}
AuthenticateIfBasicAuth(req, res);
SetSessionIfSessionIdHeader(req, res);
SetSessionIfSessionIdCookie(req, res);
using (var cache = req.GetCacheClient())
{
var sessionId = req.GetSessionId();
var session = sessionId != null ? cache.Get<IAuthSession>("urn:iauthsession:" + sessionId) : null;
if (session != null && matchingOAuthConfigs.Any(x => session.IsAuthorized(x.Provider)))
{
return;
}
var htmlRedirect = this.HtmlRedirect ?? AuthenticateService.HtmlRedirect;
if (htmlRedirect != null && req.ResponseContentType.MatchesContentType("text/html"))
{
var url = htmlRedirect;
if (url.SafeSubstring(0, 2) == "~/")
{
url = req.GetBaseUrl().CombineWith(url.Substring(2));
}
url = url.AddQueryParam("redirect", req.AbsoluteUri);
res.RedirectToUrl(url);
return;
}
AuthProvider.HandleFailedAuth(matchingOAuthConfigs[0], session, req, res);
}
}
/// <summary>
/// Gets the value of the session id from the request headers.
/// </summary>
/// <param name="httpReq">
/// The http request being handled.
/// </param>
/// <returns>
/// The <see cref="string"/>.
/// </returns>
private static string SessionIdFromHeader(IRequest httpReq)
{
var sessionId = httpReq.Headers["Session-Id"];
return sessionId;
}
/// <summary>
/// Gets the value of the session id from cookies.
/// </summary>
/// <param name="httpReq">
/// The http request being handled.
/// </param>
/// <returns>
/// The <see cref="string"/>.
/// </returns>
private static string SessionIdFromCookies(IRequest httpReq)
{
return httpReq.GetCookieValue("ss-id");
}
/// <summary>
/// Sets the response values for sessions from the cookie.
/// </summary>
/// <param name="req">
/// The request being handled.
/// </param>
/// <param name="res">
/// The response being handled.
/// </param>
private static void SetSessionIfSessionIdCookie(IRequest req, IResponse res)
{
var tokenSessionId = SessionIdFromCookies(req);
if (tokenSessionId == null)
{
return;
}
req.Items[SessionFeature.SessionId] = tokenSessionId;
req.Items[SessionFeature.PermanentSessionId] = tokenSessionId;
}
/// <summary>
/// Sets the response values for sessions from the headers.
/// </summary>
/// <param name="req">
/// The request being handled.
/// </param>
/// <param name="res">
/// The response being handled.
/// </param>
private static void SetSessionIfSessionIdHeader(IRequest req, IResponse res)
{
var tokenSessionId = SessionIdFromHeader(req);
if (tokenSessionId == null)
{
return;
}
req.Items[SessionFeature.SessionId] = tokenSessionId;
req.Items[SessionFeature.PermanentSessionId] = tokenSessionId;
}
/// <summary>
/// Handles authentication if basic authentication is being used.
/// </summary>
/// <param name="req">
/// The request being handled
/// </param>
/// <param name="res">
/// The response being handled.
/// </param>
private static void AuthenticateIfBasicAuth(IRequest req, IResponse res)
{
// Need to run SessionFeature filter since its not executed before this attribute (Priority -100)
// Required to get req.GetSessionId()
SessionFeature.AddSessionIdToRequestFilter(req, res, null);
var userPass = req.GetBasicAuthUserAndPassword();
if (userPass == null)
{
return;
}
var authService = req.TryResolve<AuthenticateService>();
authService.Post(new Authenticate
{
provider = "providername",
UserName = userPass.Value.Key,
Password = userPass.Value.Value
});
}
}