Created
July 17, 2019 13:54
-
-
Save timw255/0e3a79fdfa4e1daead3714f03bc9da84 to your computer and use it in GitHub Desktop.
A sample Sitefinity membership provider (and models) for Kinvey
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; } | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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