using System;
using System.Collections.Generic;
using System.Net;
using ServiceStack.Common;
using ServiceStack.Common.Web;
using ServiceStack.Configuration;
using ServiceStack.Logging;
using ServiceStack.ServiceHost;
using ServiceStack.Text;
using ServiceStack.WebHost.Endpoints.Extensions;
namespace ServiceStack.ServiceInterface.Auth
{
public abstract class AuthProvider : IAuthProvider
{
protected static readonly ILog Log = LogManager.GetLogger(typeof(AuthProvider));
public static TimeSpan DefaultSessionExpiry = TimeSpan.FromDays(7 * 2); //2 weeks
public TimeSpan? SessionExpiry { get; set; }
public string AuthRealm { get; set; }
public string Provider { get; set; }
public string CallbackUrl { get; set; }
public string RedirectUrl { get; set; }
protected AuthProvider() { }
protected AuthProvider(IResourceManager appSettings, string authRealm, string oAuthProvider)
{
// Enhancement per https://github.com/ServiceStack/ServiceStack/issues/741
this.AuthRealm = appSettings != null ? appSettings.Get("OAuthRealm", authRealm) : authRealm;
this.Provider = oAuthProvider;
if (appSettings != null)
{
this.CallbackUrl = appSettings.GetString("oauth.{0}.CallbackUrl".Fmt(oAuthProvider));
this.RedirectUrl = appSettings.GetString("oauth.{0}.RedirectUrl".Fmt(oAuthProvider));
}
this.SessionExpiry = DefaultSessionExpiry;
}
///
/// Remove the Users Session
///
///
///
///
public virtual object Logout(IServiceBase service, Auth request)
{
var session = service.GetSession();
var referrerUrl = (request != null ? request.Continue : null)
?? session.ReferrerUrl
?? service.RequestContext.GetHeader("Referer")
?? this.CallbackUrl;
session.OnLogout(service);
service.RemoveSession();
if (service.RequestContext.ResponseContentType == ContentType.Html && !String.IsNullOrEmpty(referrerUrl))
return service.Redirect(referrerUrl.AddHashParam("s", "-1"));
return new AuthResponse();
}
///
/// Saves the Auth Tokens for this request. Called in OnAuthenticated().
/// Overrideable, the default behaviour is to call IUserAuthRepository.CreateOrMergeAuthSession().
///
protected virtual void SaveUserAuth(IServiceBase authService, IAuthSession session, IUserAuthRepository authRepo, IOAuthTokens tokens)
{
if (authRepo == null) return;
if (tokens != null)
{
session.UserAuthId = authRepo.CreateOrMergeAuthSession(session, tokens);
}
authRepo.LoadUserAuth(session, tokens);
foreach (var oAuthToken in session.ProviderOAuthAccess)
{
var authProvider = AuthService.GetAuthProvider(oAuthToken.Provider);
if (authProvider == null) continue;
var userAuthProvider = authProvider as OAuthProvider;
if (userAuthProvider != null)
{
userAuthProvider.LoadUserOAuthProvider(session, oAuthToken);
}
}
authRepo.SaveUserAuth(session);
var httpRes = authService.RequestContext.Get();
if (httpRes != null)
{
httpRes.Cookies.AddPermanentCookie(HttpHeaders.XUserAuthId, session.UserAuthId);
}
OnSaveUserAuth(authService, session);
}
public virtual void OnSaveUserAuth(IServiceBase authService, IAuthSession session) { }
public virtual void OnAuthenticated(IServiceBase authService, IAuthSession session, IOAuthTokens tokens, Dictionary authInfo)
{
var userSession = session as AuthUserSession;
if (userSession != null)
{
LoadUserAuthInfo(userSession, tokens, authInfo);
}
var authRepo = authService.TryResolve();
if (authRepo != null)
{
if (tokens != null)
{
authInfo.ForEach((x, y) => tokens.Items[x] = y);
session.UserAuthId = authRepo.CreateOrMergeAuthSession(session, tokens);
}
//SaveUserAuth(authService, userSession, authRepo, tokens);
authRepo.LoadUserAuth(session, tokens);
foreach (var oAuthToken in session.ProviderOAuthAccess)
{
var authProvider = AuthService.GetAuthProvider(oAuthToken.Provider);
if (authProvider == null) continue;
var userAuthProvider = authProvider as OAuthProvider;
if (userAuthProvider != null)
{
userAuthProvider.LoadUserOAuthProvider(session, oAuthToken);
}
}
var httpRes = authService.RequestContext.Get();
if (httpRes != null)
{
httpRes.Cookies.AddPermanentCookie(HttpHeaders.XUserAuthId, session.UserAuthId);
}
}
//OnSaveUserAuth(authService, session);
authService.SaveSession(session, SessionExpiry);
session.OnAuthenticated(authService, session, tokens, authInfo);
}
protected virtual void LoadUserAuthInfo(AuthUserSession userSession, IOAuthTokens tokens, Dictionary authInfo) { }
protected static bool LoginMatchesSession(IAuthSession session, string userName)
{
if (userName == null) return false;
var isEmail = userName.Contains("@");
if (isEmail)
{
if (!userName.EqualsIgnoreCase(session.Email))
return false;
}
else
{
if (!userName.EqualsIgnoreCase(session.UserName))
return false;
}
return true;
}
public abstract bool IsAuthorized(IAuthSession session, IOAuthTokens tokens, Auth request = null);
public abstract object Authenticate(IServiceBase authService, IAuthSession session, Auth request);
public virtual void OnFailedAuthentication(IAuthSession session, IHttpRequest httpReq, IHttpResponse httpRes)
{
httpRes.StatusCode = (int)HttpStatusCode.Unauthorized;
httpRes.AddHeader(HttpHeaders.WwwAuthenticate, "{0} realm=\"{1}\"".Fmt(this.Provider, this.AuthRealm));
httpRes.EndRequest();
}
public static void HandleFailedAuth(IAuthProvider authProvider,
IAuthSession session, IHttpRequest httpReq, IHttpResponse httpRes)
{
var baseAuthProvider = authProvider as AuthProvider;
if (baseAuthProvider != null)
{
baseAuthProvider.OnFailedAuthentication(session, httpReq, httpRes);
return;
}
httpRes.StatusCode = (int)HttpStatusCode.Unauthorized;
httpRes.AddHeader(HttpHeaders.WwwAuthenticate, "{0} realm=\"{1}\""
.Fmt(authProvider.Provider, authProvider.AuthRealm));
httpRes.EndRequest();
}
}
public static class AuthConfigExtensions
{
public static bool IsAuthorizedSafe(this IAuthProvider authProvider, IAuthSession session, IOAuthTokens tokens)
{
return authProvider != null && authProvider.IsAuthorized(session, tokens);
}
}
}