Skip to content

Instantly share code, notes, and snippets.

@timw255
Created July 17, 2019 13:54
Show Gist options
  • Save timw255/0e3a79fdfa4e1daead3714f03bc9da84 to your computer and use it in GitHub Desktop.
Save timw255/0e3a79fdfa4e1daead3714f03bc9da84 to your computer and use it in GitHub Desktop.
A sample Sitefinity membership provider (and models) for Kinvey
using System;
using System.Configuration;
using System.Linq;
using Telerik.Sitefinity.Abstractions;
using Telerik.Sitefinity.Configuration;
using Telerik.Sitefinity.Localization;
using Telerik.Sitefinity.Modules.GenericContent.Configuration;
using Telerik.Sitefinity.Web.Configuration;
namespace SitefinityWebApp.Custom.Configuration
{
[ObjectInfo(Title = "Kinvey", Description = "Configuration for Kinvey")]
public class KinveyConfig : ConfigSection
{
[ObjectInfo(Title = "Host URL", Description = "Application Key")]
[ConfigurationProperty("hostUrl", DefaultValue = "https://baas.kinvey.com")]
public string HostURL
{
get
{
return (string)this["hostUrl"];
}
set
{
this["hostUrl"] = value;
}
}
[ObjectInfo(Title = "App Key", Description = "Application Key")]
[ConfigurationProperty("appKey")]
public string AppKey
{
get
{
return (string)this["appKey"];
}
set
{
this["appKey"] = value;
}
}
[ObjectInfo(Title = "App Secret", Description = "Application Secret")]
[ConfigurationProperty("appSecret")]
public string AppSecret
{
get
{
return (string)this["appSecret"];
}
set
{
this["appSecret"] = value;
}
}
[ObjectInfo(Title = "Master Secret", Description = "Master Secret")]
[ConfigurationProperty("masterSecret")]
public string MasterSecret
{
get
{
return (string)this["masterSecret"];
}
set
{
this["masterSecret"] = value;
}
}
}
}
using Newtonsoft.Json;
using RestSharp;
using SitefinityWebApp.Custom.Configuration;
using SitefinityWebApp.Custom.Models;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration.Provider;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using System.Web.Security;
using Telerik.Sitefinity.Configuration;
using Telerik.Sitefinity.Data;
using Telerik.Sitefinity.Model;
using Telerik.Sitefinity.Security;
using Telerik.Sitefinity.Security.Data;
using Telerik.Sitefinity.Security.Model;
namespace SitefinityWebApp.Custom.Security
{
public class KinveyMembershipProvider : MembershipDataProvider
{
#region Privates variables
private ManagerInfo _managerInfo;
private string _providerName = "KinveyMembershipProvider";
// it's a better idea to store the appkey and secrets in a custom config... I just didn't do it here.
//private KinveyConfig _kConfig = Config.Get<KinveyConfig>();
private KinveyConfig _kConfig = new KinveyConfig()
{
HostURL = "https://baas.kinvey.com",
AppKey = "<your appkey>",
AppSecret = "<your appsecret>",
MasterSecret = "<your mastersecret>",
};
private string _authHeader;
private string _appSecretAuthHeader;
#endregion
#region Public variables
public const string ServiceEndpointKey = "serviceEndpoint";
#endregion
#region Properties
public string ProviderName
{
get { return _providerName; }
set { _providerName = value; }
}
public override string ApplicationName
{
get
{
return "/KinveyMembershipProvider";
}
}
private ManagerInfo ManagerInfo
{
get
{
return _managerInfo ?? (_managerInfo = new ManagerInfo()
{
ProviderName = ProviderName,
ManagerType = "Telerik.Sitefinity.Security.UserManager",
ApplicationName = ApplicationName
});
}
}
public override ProviderAbilities Abilities
{
get
{
var abilities = new ProviderAbilities { ProviderName = Name, ProviderType = GetType().FullName };
abilities.AddAbility("GetUser", true, true);
//abilities.AddAbility("AddUser", true, true);
//abilities.AddAbility("DeleteUser", true, true);
//abilities.AddAbility("UpdateUser", true, true);
abilities.AddAbility("ValidateUser", true, true);
//abilities.AddAbility("ResetPassword", true, true);
//abilities.AddAbility("GetPassword", true, true);
return abilities;
}
}
#endregion
#region Methods
public KinveyMembershipProvider()
{
var plainTextBytes = Encoding.UTF8.GetBytes(_kConfig.AppKey + ":" + _kConfig.MasterSecret);
_authHeader = "Basic " + Convert.ToBase64String(plainTextBytes);
var plainTextBytes2 = Encoding.UTF8.GetBytes(_kConfig.AppKey + ":" + _kConfig.AppSecret);
_appSecretAuthHeader = "Basic " + Convert.ToBase64String(plainTextBytes);
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
}
public override void CommitTransaction()
{
}
private bool CheckValidPassword(User user, string password)
{
if (user == null || !user.IsApproved || string.IsNullOrWhiteSpace(user.Password))
return false;
var client = new RestClient(_kConfig.HostURL);
var request = new RestRequest("user/{appKey}/login", Method.POST);
request.AddUrlSegment("appKey", _kConfig.AppKey);
request.AddHeader("Accept", "application/json");
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Authorization", _authHeader);
var body = new KinveyLoginRequest()
{
Username = user.UserName,
Password = password
};
string json = JsonConvert.SerializeObject(body);
request.AddParameter("application/json", json, ParameterType.RequestBody);
request.AddHeader("Authorization", _authHeader);
Console.WriteLine(client.BuildUri(request));
IRestResponse response = client.Execute(request);
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
var kUser = JsonConvert.DeserializeObject<KinveyUser>(response.Content);
// add roles
UserManager userManager = UserManager.GetManager();
RoleManager roleManager = RoleManager.GetManager("Kinvey");
roleManager.Provider.SuppressSecurityChecks = true;
foreach (var roleGrant in kUser.KinveyMetadata.Roles)
{
var role = roleManager.GetRole(roleGrant.Id);
if (role != null)
{
roleManager.AddUserToRole(user, role);
}
}
roleManager.SaveChanges();
roleManager.Provider.SuppressSecurityChecks = false;
// end add roles
return true;
}
return false;
}
public override bool EmailExists(string email)
{
var client = new RestClient(_kConfig.HostURL);
var request = new RestRequest("user/{appKey}?query={\"email\":\"{email}\"}", Method.GET);
request.AddUrlSegment("appKey", _kConfig.AppKey);
request.AddUrlSegment("email", email);
request.AddHeader("Accept", "application/json");
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Authorization", _authHeader);
Console.WriteLine(client.BuildUri(request));
IRestResponse<KinveyUser> response = client.Execute<KinveyUser>(request);
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
return true;
}
return false;
}
public override bool UserExists(string username)
{
var client = new RestClient(_kConfig.HostURL);
var request = new RestRequest("rpc/{appKey}/check-username-exists", Method.POST);
request.AddUrlSegment("appKey", _kConfig.AppKey);
request.AddHeader("Accept", "application/json");
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Authorization", _authHeader);
var body = new KinveyUsernameCheck()
{
Username = username
};
string json = JsonConvert.SerializeObject(body);
request.AddParameter("application/json", json, ParameterType.RequestBody);
Console.WriteLine(client.BuildUri(request));
IRestResponse<KinveyUsernameCheck> response = client.Execute<KinveyUsernameCheck>(request);
if (response.StatusCode == System.Net.HttpStatusCode.OK && response.Data.UsernameExists)
{
return true;
}
return false;
}
private User GetSitefinityUser(KinveyUser kUser)
{
var user = new User();
user.ApplicationName = ApplicationName;
user.IsBackendUser = false;
user.Id = Helpers.KinveyIdToGuid(kUser.Id);
string userEmail;
if (String.IsNullOrWhiteSpace(kUser.Email) && kUser.SocialIdentity != null)
{
userEmail = kUser.SocialIdentity.KinveyAuth.UniqueName;
}
else
{
userEmail = kUser.Email;
}
user.Email = userEmail;
user.FirstName = kUser.FirstName;
user.LastName = kUser.LastName;
user.LastActivityDate = DateTime.UtcNow.AddDays(-1);
user.LastModified = DateTime.MinValue;
user.LastLoginDate = DateTime.MinValue;
user.FailedPasswordAnswerAttemptWindowStart = DateTime.MinValue;
user.FailedPasswordAttemptWindowStart = DateTime.MinValue;
user.Password = Guid.NewGuid().ToString();
user.ManagerInfo = ManagerInfo;
user.IsApproved = true; // Convert.ToBoolean(mUser.Confirmed);
user.PasswordFormat = 1;
user.SetUserName(kUser.Username);
user.SetCreationDate(DateTime.Now);
user.SetIsLockedOut(false);
user.SetLastLockoutDate(DateTime.Now);
user.SetLastPasswordChangedDate(DateTime.Now);
user.SetPasswordQuestion("question");
return user;
}
protected override void Initialize(string providerName, NameValueCollection config, Type managerType)
{
base.Initialize(providerName, config, managerType);
}
public override IQueryable<User> GetUsers()
{
var client = new RestClient(_kConfig.HostURL);
var request = new RestRequest("user/{appKey}", Method.GET);
request.AddUrlSegment("appKey", _kConfig.AppKey);
request.AddHeader("Accept", "application/json");
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Authorization", _authHeader);
var fullUrl = client.BuildUri(request);
IRestResponse<List<KinveyUser>> response = client.Execute<List<KinveyUser>>(request);
var users = new List<User>();
if (response.Data != null)
{
var kUsers = response.Data;
foreach (var kUser in kUsers)
{
var user = GetSitefinityUser(kUser);
users.Add(user);
}
}
return users.AsQueryable();
}
public override User GetUser(Guid id)
{
var client = new RestClient(_kConfig.HostURL);
var request = new RestRequest("user/{appKey}/{id}", Method.GET);
request.AddUrlSegment("appKey", _kConfig.AppKey);
request.AddHeader("Accept", "application/json");
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Authorization", _authHeader);
request.AddUrlSegment("id", Helpers.GuidToKinveyId(id));
Console.WriteLine(client.BuildUri(request));
IRestResponse<KinveyUser> response = client.Execute<KinveyUser>(request);
return response.StatusCode != System.Net.HttpStatusCode.OK ? null : GetSitefinityUser(response.Data);
}
public override User GetUserByEmail(string email)
{
var client = new RestClient(_kConfig.HostURL);
var request = new RestRequest("user/{appKey}?query={\"email\":\"{email}\"}", Method.GET);
request.AddUrlSegment("appKey", _kConfig.AppKey);
request.AddUrlSegment("email", email);
request.AddHeader("Accept", "application/json");
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Authorization", _authHeader);
Console.WriteLine(client.BuildUri(request));
IRestResponse<KinveyUser> response = client.Execute<KinveyUser>(request);
return response.StatusCode != System.Net.HttpStatusCode.OK ? null : GetSitefinityUser(response.Data);
}
public override User GetUser(string username)
{
var client = new RestClient(_kConfig.HostURL);
var request = new RestRequest("user/{appKey}?query={\"username\":\"{username}\"}", Method.GET);
request.AddUrlSegment("appKey", _kConfig.AppKey);
request.AddUrlSegment("username", username);
request.AddHeader("Accept", "application/json");
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Authorization", _authHeader);
Console.WriteLine(client.BuildUri(request));
IRestResponse<KinveyUser> response = client.Execute<KinveyUser>(request);
return response.StatusCode != System.Net.HttpStatusCode.OK ? null : GetSitefinityUser(response.Data);
}
public override User CreateUser(string userName)
{
return CreateUser(Guid.NewGuid(), userName);
}
public override User CreateUser(Guid id, string userName)
{
if (id == Guid.Empty) throw new ArgumentNullException("id");
if (!string.IsNullOrEmpty(userName))
{
LoginUtils.CheckParameter(userName, true, true, true, 256, "userName");
if (this.UserExists(userName))
{
throw new ProviderException("Username already exists.");
}
}
var user = new User { ApplicationName = ApplicationName, Id = id };
user.SetUserName(userName);
((IDataItem)user).Provider = this;
user.ManagerInfo = ManagerInfo;
return user;
}
public override bool ValidateUser(string userName, string password)
{
return ValidateUser(GetUser(userName), password);
}
public override bool ValidateUser(User user, string password)
{
if (user == null) return false;
var flag = CheckValidPassword(user, password);
if (flag)
{
user.LastLoginDate = DateTime.UtcNow;
user.FailedPasswordAttemptWindowStart = DateTime.UtcNow;
user.FailedPasswordAttemptCount = 0;
}
else
{
UpdateFailureCount(user, "password");
}
return flag;
}
#endregion
#region Not Supported
public override User CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
{
throw new NotImplementedException();
}
public override string GetPassword(User user, string answer)
{
throw new NotSupportedException();
}
public override string GetPassword(string userName, string answer)
{
throw new NotSupportedException();
}
public override string GetPassword(Guid userId, string answer)
{
throw new NotSupportedException();
}
public override void Delete(User item)
{
throw new NotSupportedException();
}
public override string ResetPassword(User user, string answer)
{
throw new NotSupportedException();
}
public override string ResetPassword(string userName, string answer)
{
throw new NotSupportedException();
}
public override string ResetPassword(Guid userId, string answer)
{
throw new NotSupportedException();
}
public override bool ChangePassword(Guid userId, string oldPassword, string newPassword)
{
throw new NotSupportedException();
}
public override bool ChangePassword(string userName, string oldPassword, string newPassword)
{
throw new NotSupportedException();
}
public override bool ChangePassword(User user, string oldPassword, string newPassword)
{
throw new NotSupportedException();
}
public override bool ChangePasswordQuestionAndAnswer(User user, string password, string newPasswordQuestion, string newPasswordAnswer)
{
throw new NotSupportedException();
}
public override bool ChangePasswordQuestionAndAnswer(Guid id, string password, string newPasswordQuestion, string newPasswordAnswer)
{
throw new NotSupportedException();
}
public override bool ChangePasswordQuestionAndAnswer(string userName, string password, string newPasswordQuestion, string newPasswordAnswer)
{
throw new NotSupportedException();
}
public override System.Collections.IEnumerable GetItems(Type itemType, string filterExpression, string orderExpression, int skip, int take, ref int? totalCount)
{
throw new NotSupportedException();
}
public override bool UnlockUser(Guid userId)
{
throw new NotSupportedException();
}
public override bool UnlockUser(string userName)
{
throw new NotSupportedException();
}
public override bool UnlockUser(User user)
{
throw new NotSupportedException();
}
#endregion
}
}
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace SitefinityWebApp.Custom.Models
{
public class KinveyUser
{
[JsonProperty(PropertyName = "_id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "_kmd")]
public KinveyMetadata KinveyMetadata { get; set; }
[JsonProperty(PropertyName = "username")]
public string Username { get; set; }
[JsonProperty(PropertyName = "password")]
public string Password { get; set; }
[JsonProperty(PropertyName = "firstName")]
public string FirstName { get; set; }
[JsonProperty(PropertyName = "lastName")]
public string LastName { get; set; }
[JsonProperty(PropertyName = "email")]
public string Email { get; set; }
[JsonProperty(PropertyName = "_socialIdentity")]
public SocialIdentity SocialIdentity { get; set; }
}
}
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace SitefinityWebApp.Custom.Models
{
public class KinveyUsernameCheck
{
[JsonProperty(PropertyName = "username")]
public string Username { get; set; }
[JsonProperty(PropertyName = "usernameExists")]
public bool UsernameExists { get; set; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment