[3932] | 1 | using System;
|
---|
[3958] | 2 | using System.Collections.Specialized;
|
---|
| 3 | using System.Configuration;
|
---|
[3957] | 4 | using System.Configuration.Provider;
|
---|
[3932] | 5 | using System.Linq;
|
---|
[3957] | 6 | using System.Security.Cryptography;
|
---|
| 7 | using System.Text;
|
---|
| 8 | using System.Web.Configuration;
|
---|
[3932] | 9 | using System.Web.Security;
|
---|
[3943] | 10 | using Persistence;
|
---|
[3932] | 11 |
|
---|
[3939] | 12 | namespace Service.Provider {
|
---|
| 13 | class HeuristicLabMembershipProvider : MembershipProvider {
|
---|
[3957] | 14 |
|
---|
[3958] | 15 | private string pApplicationName;
|
---|
| 16 | private bool pEnablePasswordReset;
|
---|
| 17 | private bool pEnablePasswordRetrieval;
|
---|
| 18 | private bool pRequiresQuestionAndAnswer;
|
---|
| 19 | private bool pRequiresUniqueEmail;
|
---|
| 20 | private int pMaxInvalidPasswordAttempts;
|
---|
| 21 | private int pPasswordAttemptWindow;
|
---|
| 22 | private int pMinRequiredPasswordLength;
|
---|
[3961] | 23 | private MembershipPasswordFormat pPasswordFormat = MembershipPasswordFormat.Clear;
|
---|
[3958] | 24 | private MachineKeySection machineKey;
|
---|
[3957] | 25 |
|
---|
[3958] | 26 |
|
---|
| 27 | public override void Initialize(string name, NameValueCollection config) {
|
---|
| 28 | //
|
---|
| 29 | // Initialize values from web.config.
|
---|
| 30 | //
|
---|
| 31 |
|
---|
| 32 | if (config == null)
|
---|
| 33 | throw new ArgumentNullException("config");
|
---|
| 34 |
|
---|
[3961] | 35 | if (string.IsNullOrEmpty(name) || name.Length == 0)
|
---|
[3958] | 36 | name = "HeuristicLabMembershipProvider";
|
---|
| 37 |
|
---|
| 38 | if (String.IsNullOrEmpty(config["description"])) {
|
---|
| 39 | config.Remove("description");
|
---|
| 40 | config.Add("description", "Heuristic Lab Membership provider");
|
---|
[3939] | 41 | }
|
---|
[3958] | 42 |
|
---|
| 43 | // Initialize the abstract base class.
|
---|
| 44 | base.Initialize(name, config);
|
---|
| 45 |
|
---|
| 46 | pApplicationName = GetConfigValue(config["applicationName"], System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath);
|
---|
| 47 | pMaxInvalidPasswordAttempts = Convert.ToInt32(GetConfigValue(config["maxInvalidPasswordAttempts"], "5"));
|
---|
| 48 | pPasswordAttemptWindow = Convert.ToInt32(GetConfigValue(config["passwordAttemptWindow"], "10"));
|
---|
| 49 | pMinRequiredPasswordLength = Convert.ToInt32(GetConfigValue(config["minRequiredPasswordLength"], "7"));
|
---|
| 50 | pEnablePasswordReset = Convert.ToBoolean(GetConfigValue(config["enablePasswordReset"], "true"));
|
---|
| 51 | pEnablePasswordRetrieval = Convert.ToBoolean(GetConfigValue(config["enablePasswordRetrieval"], "true"));
|
---|
| 52 | pRequiresQuestionAndAnswer = Convert.ToBoolean(GetConfigValue(config["requiresQuestionAndAnswer"], "false"));
|
---|
| 53 | pRequiresUniqueEmail = Convert.ToBoolean(GetConfigValue(config["requiresUniqueEmail"], "true"));
|
---|
| 54 |
|
---|
| 55 | string tempFormat = config["passwordFormat"];
|
---|
| 56 | if (tempFormat == null) {
|
---|
[3961] | 57 | tempFormat = "Clear";
|
---|
[3939] | 58 | }
|
---|
[3958] | 59 |
|
---|
| 60 | switch (tempFormat) {
|
---|
| 61 | case "Hashed":
|
---|
| 62 | pPasswordFormat = MembershipPasswordFormat.Hashed;
|
---|
| 63 | break;
|
---|
| 64 | case "Encrypted":
|
---|
| 65 | pPasswordFormat = MembershipPasswordFormat.Encrypted;
|
---|
| 66 | break;
|
---|
| 67 | case "Clear":
|
---|
| 68 | pPasswordFormat = MembershipPasswordFormat.Clear;
|
---|
| 69 | break;
|
---|
| 70 | default:
|
---|
| 71 | throw new ProviderException("Password format not supported.");
|
---|
| 72 | }
|
---|
| 73 |
|
---|
| 74 | // Get encryption and decryption key information from the configuration.
|
---|
| 75 | Configuration cfg =
|
---|
| 76 | WebConfigurationManager.OpenWebConfiguration(System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath);
|
---|
| 77 | machineKey = (MachineKeySection)cfg.GetSection("system.web/machineKey");
|
---|
| 78 |
|
---|
| 79 | if (machineKey.ValidationKey.Contains("AutoGenerate"))
|
---|
| 80 | if (PasswordFormat != MembershipPasswordFormat.Clear)
|
---|
| 81 | throw new ProviderException("Hashed or Encrypted passwords " +
|
---|
| 82 | "are not supported with auto-generated keys.");
|
---|
[3939] | 83 | }
|
---|
[3932] | 84 |
|
---|
[3958] | 85 | public override string ApplicationName {
|
---|
| 86 | get { return pApplicationName; }
|
---|
| 87 | set { pApplicationName = value; }
|
---|
| 88 | }
|
---|
| 89 |
|
---|
[3939] | 90 | public override bool ChangePassword(string username, string oldPassword, string newPassword) {
|
---|
[3956] | 91 | using (DataClassesDataContext db = DatabaseUtil.createDataClassesDataContext()) {
|
---|
| 92 | // check database connection
|
---|
| 93 | if (db == null) {
|
---|
[3943] | 94 | return false;
|
---|
| 95 | }
|
---|
[3956] | 96 | try {
|
---|
| 97 | // try to get user
|
---|
| 98 | HeuristicLabUser u = db.HeuristicLabUsers.Single(x => x.UserName == username);
|
---|
| 99 | if (u.ChangePassword(oldPassword, newPassword)) {
|
---|
| 100 | // save user to database only if needed
|
---|
| 101 | db.SubmitChanges();
|
---|
| 102 | return true;
|
---|
| 103 | } else {
|
---|
| 104 | return false;
|
---|
| 105 | }
|
---|
| 106 | }
|
---|
| 107 | catch (Exception) {
|
---|
| 108 | return false;
|
---|
| 109 | }
|
---|
[3943] | 110 | }
|
---|
[3939] | 111 | }
|
---|
[3932] | 112 |
|
---|
[3939] | 113 | public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer) {
|
---|
[3956] | 114 | using (DataClassesDataContext db = DatabaseUtil.createDataClassesDataContext()) {
|
---|
| 115 | // check database connection
|
---|
| 116 | if (db == null) {
|
---|
[3948] | 117 | return false;
|
---|
| 118 | }
|
---|
[3956] | 119 | try {
|
---|
| 120 | // try to get user
|
---|
| 121 | HeuristicLabUser u = db.HeuristicLabUsers.Single(x => x.UserName == username);
|
---|
| 122 | if (u.ChangePasswordQuestionAndAnswer(password, newPasswordQuestion, newPasswordAnswer)) {
|
---|
| 123 | // save user to database only if needed
|
---|
| 124 | db.SubmitChanges();
|
---|
| 125 | return true;
|
---|
| 126 | } else {
|
---|
| 127 | return false;
|
---|
| 128 | }
|
---|
| 129 | }
|
---|
| 130 | catch (Exception) {
|
---|
| 131 | return false;
|
---|
| 132 | }
|
---|
[3948] | 133 | }
|
---|
[3939] | 134 | }
|
---|
[3932] | 135 |
|
---|
[3939] | 136 | public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status) {
|
---|
[3956] | 137 | using (DataClassesDataContext db = DatabaseUtil.createDataClassesDataContext()) {
|
---|
| 138 | // check database connection
|
---|
| 139 | if (db == null) {
|
---|
| 140 | status = MembershipCreateStatus.ProviderError;
|
---|
| 141 | return null;
|
---|
| 142 | }
|
---|
| 143 | try {
|
---|
| 144 | // check for duplicate entries
|
---|
| 145 | if (db.HeuristicLabUsers.Count(x => x.UserName == username) > 0) {
|
---|
| 146 | status = MembershipCreateStatus.DuplicateUserName;
|
---|
| 147 | return null;
|
---|
| 148 | }
|
---|
| 149 | if (db.HeuristicLabUsers.Count(x => x.Email == email) > 0) {
|
---|
| 150 | status = MembershipCreateStatus.DuplicateEmail;
|
---|
| 151 | return null;
|
---|
| 152 | }
|
---|
| 153 |
|
---|
| 154 | // create new user
|
---|
| 155 | HeuristicLabUser u = new HeuristicLabUser(username, email, passwordQuestion, "");
|
---|
| 156 | u.ChangePassword("INIT", password);
|
---|
| 157 | u.ChangePasswordQuestionAndAnswer(password, passwordQuestion, passwordAnswer);
|
---|
| 158 | // save user into database
|
---|
| 159 | db.HeuristicLabUsers.InsertOnSubmit(u);
|
---|
| 160 | db.SubmitChanges();
|
---|
| 161 |
|
---|
| 162 | // success
|
---|
| 163 | status = MembershipCreateStatus.Success;
|
---|
| 164 | return u;
|
---|
| 165 | }
|
---|
| 166 | catch (Exception) {
|
---|
| 167 | // error
|
---|
| 168 | status = MembershipCreateStatus.ProviderError;
|
---|
| 169 | return null;
|
---|
| 170 | }
|
---|
| 171 | }
|
---|
[3939] | 172 | }
|
---|
[3932] | 173 |
|
---|
[3939] | 174 | public override bool DeleteUser(string username, bool deleteAllRelatedData) {
|
---|
[3956] | 175 | using (DataClassesDataContext db = DatabaseUtil.createDataClassesDataContext()) {
|
---|
| 176 | // check database connection
|
---|
| 177 | if (db == null) {
|
---|
| 178 | return false;
|
---|
| 179 | }
|
---|
| 180 | try {
|
---|
| 181 | // try to get user
|
---|
[3958] | 182 | HeuristicLabUser u =
|
---|
[3956] | 183 | db.HeuristicLabUsers.Single<HeuristicLabUser>(x => x.UserName == username);
|
---|
| 184 |
|
---|
| 185 | // optionally delete related data
|
---|
| 186 | if (deleteAllRelatedData) {
|
---|
[3962] | 187 | db.HeuristicLabUserRole.DeleteAllOnSubmit<HeuristicLabUserRole>(u.HeuristicLabUserRoles);
|
---|
[3956] | 188 | }
|
---|
[3958] | 189 |
|
---|
[3956] | 190 | // delete user
|
---|
| 191 | db.HeuristicLabUsers.DeleteOnSubmit(u);
|
---|
| 192 | db.SubmitChanges();
|
---|
| 193 | return true;
|
---|
| 194 | }
|
---|
| 195 | catch (Exception) {
|
---|
| 196 | return false;
|
---|
| 197 | }
|
---|
| 198 | }
|
---|
[3939] | 199 | }
|
---|
[3932] | 200 |
|
---|
[3939] | 201 | public override bool EnablePasswordReset {
|
---|
| 202 | get { throw new NotImplementedException(); }
|
---|
| 203 | }
|
---|
[3932] | 204 |
|
---|
[3939] | 205 | public override bool EnablePasswordRetrieval {
|
---|
| 206 | get { throw new NotImplementedException(); }
|
---|
| 207 | }
|
---|
[3932] | 208 |
|
---|
[3939] | 209 | public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords) {
|
---|
| 210 | throw new NotImplementedException();
|
---|
| 211 | }
|
---|
[3932] | 212 |
|
---|
[3939] | 213 | public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords) {
|
---|
| 214 | throw new NotImplementedException();
|
---|
| 215 | }
|
---|
[3932] | 216 |
|
---|
[3939] | 217 | public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords) {
|
---|
| 218 | throw new NotImplementedException();
|
---|
| 219 | }
|
---|
[3932] | 220 |
|
---|
[3939] | 221 | public override int GetNumberOfUsersOnline() {
|
---|
| 222 | throw new NotImplementedException();
|
---|
| 223 | }
|
---|
[3932] | 224 |
|
---|
[3939] | 225 | public override string GetPassword(string username, string answer) {
|
---|
[3956] | 226 |
|
---|
[3939] | 227 | throw new NotImplementedException();
|
---|
| 228 | }
|
---|
[3932] | 229 |
|
---|
[3939] | 230 | public override MembershipUser GetUser(string username, bool userIsOnline) {
|
---|
| 231 | throw new NotImplementedException();
|
---|
| 232 | }
|
---|
[3932] | 233 |
|
---|
[3939] | 234 | public override MembershipUser GetUser(object providerUserKey, bool userIsOnline) {
|
---|
| 235 | throw new NotImplementedException();
|
---|
| 236 | }
|
---|
[3932] | 237 |
|
---|
[3939] | 238 | public override string GetUserNameByEmail(string email) {
|
---|
| 239 | throw new NotImplementedException();
|
---|
| 240 | }
|
---|
[3932] | 241 |
|
---|
[3939] | 242 | public override int MaxInvalidPasswordAttempts {
|
---|
| 243 | get { throw new NotImplementedException(); }
|
---|
| 244 | }
|
---|
[3932] | 245 |
|
---|
[3939] | 246 | public override int MinRequiredNonAlphanumericCharacters {
|
---|
| 247 | get { throw new NotImplementedException(); }
|
---|
| 248 | }
|
---|
[3932] | 249 |
|
---|
[3939] | 250 | public override int MinRequiredPasswordLength {
|
---|
| 251 | get { throw new NotImplementedException(); }
|
---|
| 252 | }
|
---|
[3932] | 253 |
|
---|
[3939] | 254 | public override int PasswordAttemptWindow {
|
---|
| 255 | get { throw new NotImplementedException(); }
|
---|
| 256 | }
|
---|
[3932] | 257 |
|
---|
[3939] | 258 | public override MembershipPasswordFormat PasswordFormat {
|
---|
[3961] | 259 | get { return pPasswordFormat; }
|
---|
[3939] | 260 | }
|
---|
[3932] | 261 |
|
---|
[3939] | 262 | public override string PasswordStrengthRegularExpression {
|
---|
| 263 | get { throw new NotImplementedException(); }
|
---|
| 264 | }
|
---|
[3932] | 265 |
|
---|
[3939] | 266 | public override bool RequiresQuestionAndAnswer {
|
---|
| 267 | get { throw new NotImplementedException(); }
|
---|
| 268 | }
|
---|
[3932] | 269 |
|
---|
[3939] | 270 | public override bool RequiresUniqueEmail {
|
---|
| 271 | get { throw new NotImplementedException(); }
|
---|
| 272 | }
|
---|
[3932] | 273 |
|
---|
[3939] | 274 | public override string ResetPassword(string username, string answer) {
|
---|
| 275 | throw new NotImplementedException();
|
---|
| 276 | }
|
---|
[3932] | 277 |
|
---|
[3939] | 278 | public override bool UnlockUser(string userName) {
|
---|
| 279 | throw new NotImplementedException();
|
---|
| 280 | }
|
---|
[3932] | 281 |
|
---|
[3939] | 282 | public override void UpdateUser(MembershipUser user) {
|
---|
| 283 | throw new NotImplementedException();
|
---|
| 284 | }
|
---|
[3957] | 285 | /// <summary>
|
---|
| 286 | /// Validates a user
|
---|
| 287 | /// </summary>
|
---|
| 288 | /// <param name="username"></param>
|
---|
| 289 | /// <param name="password"></param>
|
---|
| 290 | /// <returns></returns>
|
---|
[3958] | 291 | public override bool ValidateUser(string username, string password) {
|
---|
| 292 | bool isValid = false;
|
---|
| 293 | using (DataClassesDataContext db = DatabaseUtil.createDataClassesDataContext()) {
|
---|
| 294 | if (db == null) {
|
---|
| 295 | return false;
|
---|
[3957] | 296 | }
|
---|
[3958] | 297 | HeuristicLabUser u = db.HeuristicLabUsers.Single(x => x.UserName == username);
|
---|
| 298 | isValid = CheckPassword(password, u.GetPassword());
|
---|
| 299 | }
|
---|
| 300 | return isValid;
|
---|
[3957] | 301 | }
|
---|
[3958] | 302 |
|
---|
[3957] | 303 | /// <summary>
|
---|
| 304 | /// compaiers to passwords
|
---|
| 305 | /// </summary>
|
---|
| 306 | /// <param name="password"></param>
|
---|
| 307 | /// <param name="dbpassword"></param>
|
---|
| 308 | /// <returns></returns>
|
---|
[3958] | 309 | private bool CheckPassword(string password, string dbpassword) {
|
---|
| 310 | string pass1 = password;
|
---|
| 311 | string pass2 = dbpassword;
|
---|
[3932] | 312 |
|
---|
[3958] | 313 | switch (PasswordFormat) {
|
---|
| 314 | case MembershipPasswordFormat.Encrypted:
|
---|
| 315 | pass2 = DecodePassword(dbpassword);
|
---|
| 316 | break;
|
---|
| 317 | case MembershipPasswordFormat.Hashed:
|
---|
| 318 | pass1 = EncodePassword(password);
|
---|
| 319 | break;
|
---|
| 320 | default:
|
---|
| 321 | break;
|
---|
| 322 | }
|
---|
[3957] | 323 |
|
---|
[3958] | 324 | if (pass1 == pass2) {
|
---|
| 325 | return true;
|
---|
| 326 | }
|
---|
[3957] | 327 |
|
---|
[3958] | 328 | return false;
|
---|
[3932] | 329 | }
|
---|
[3957] | 330 |
|
---|
| 331 |
|
---|
[3958] | 332 | /// <summary>
|
---|
| 333 | /// Encodes a password
|
---|
| 334 | /// </summary>
|
---|
| 335 | /// <param name="password"></param>
|
---|
| 336 | /// <returns></returns>
|
---|
| 337 | private string EncodePassword(string password) {
|
---|
| 338 | string encodedPassword = password;
|
---|
[3957] | 339 |
|
---|
[3958] | 340 | switch (PasswordFormat) {
|
---|
| 341 | case MembershipPasswordFormat.Clear:
|
---|
| 342 | break;
|
---|
| 343 | case MembershipPasswordFormat.Encrypted:
|
---|
| 344 | encodedPassword =
|
---|
| 345 | Convert.ToBase64String(EncryptPassword(Encoding.Unicode.GetBytes(password)));
|
---|
| 346 | break;
|
---|
| 347 | case MembershipPasswordFormat.Hashed:
|
---|
| 348 | HMACSHA1 hash = new HMACSHA1();
|
---|
| 349 | hash.Key = HexToByte(machineKey.ValidationKey);
|
---|
| 350 | encodedPassword =
|
---|
| 351 | Convert.ToBase64String(hash.ComputeHash(Encoding.Unicode.GetBytes(password)));
|
---|
| 352 | break;
|
---|
| 353 | default:
|
---|
| 354 | throw new ProviderException("Unsupported password format.");
|
---|
| 355 | }
|
---|
[3957] | 356 |
|
---|
[3958] | 357 | return encodedPassword;
|
---|
[3957] | 358 | }
|
---|
| 359 |
|
---|
| 360 |
|
---|
| 361 | /// <summary>
|
---|
| 362 | /// Decodes a encoded Password
|
---|
| 363 | /// </summary>
|
---|
| 364 | /// <param name="encodedPassword"></param>
|
---|
| 365 | /// <returns></returns>
|
---|
[3958] | 366 | private string DecodePassword(string encodedPassword) {
|
---|
| 367 | string password = encodedPassword;
|
---|
[3957] | 368 |
|
---|
[3958] | 369 | switch (PasswordFormat) {
|
---|
| 370 | case MembershipPasswordFormat.Clear:
|
---|
| 371 | break;
|
---|
| 372 | case MembershipPasswordFormat.Encrypted:
|
---|
| 373 | password =
|
---|
| 374 | Encoding.Unicode.GetString(DecryptPassword(Convert.FromBase64String(password)));
|
---|
| 375 | break;
|
---|
| 376 | case MembershipPasswordFormat.Hashed:
|
---|
| 377 | throw new ProviderException("Cannot unencode a hashed password.");
|
---|
| 378 | default:
|
---|
| 379 | throw new ProviderException("Unsupported password format.");
|
---|
| 380 | }
|
---|
[3957] | 381 |
|
---|
[3958] | 382 | return password;
|
---|
[3957] | 383 | }
|
---|
| 384 |
|
---|
| 385 | /// <summary>
|
---|
| 386 | /// returns byte array of an HexString
|
---|
| 387 | /// </summary>
|
---|
| 388 | /// <param name="hexString"></param>
|
---|
| 389 | /// <returns></returns>
|
---|
[3958] | 390 | private static byte[] HexToByte(string hexString) {
|
---|
| 391 | byte[] returnBytes = new byte[hexString.Length / 2];
|
---|
| 392 | for (int i = 0; i < returnBytes.Length; i++)
|
---|
| 393 | returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
|
---|
| 394 | return returnBytes;
|
---|
[3957] | 395 | }
|
---|
[3958] | 396 |
|
---|
| 397 | /// <summary>
|
---|
| 398 | /// returns the configuration string, if the value is null or empty the default value is returned
|
---|
| 399 | /// </summary>
|
---|
| 400 | /// <param name="configValue"></param>
|
---|
| 401 | /// <param name="defaultValue"></param>
|
---|
| 402 | /// <returns></returns>
|
---|
| 403 | private string GetConfigValue(string configValue, string defaultValue) {
|
---|
| 404 | if (String.IsNullOrEmpty(configValue))
|
---|
| 405 | return defaultValue;
|
---|
| 406 |
|
---|
| 407 | return configValue;
|
---|
| 408 | }
|
---|
[3939] | 409 | }
|
---|
[3932] | 410 | }
|
---|