From bd2054e5a460195a5f4d44d553feaed544cf15ce Mon Sep 17 00:00:00 2001 From: David Sparer Date: Sat, 28 Jan 2017 13:39:51 -0700 Subject: [PATCH] created a has-upper-case constraint --- ...asswordIncludesUpperCaseConstraintTests.cs | 51 +++++++++++++++++++ mRemoteNGTests/mRemoteNGTests.csproj | 1 + .../Resources/Language/Language.Designer.cs | 9 ++++ mRemoteV1/Resources/Language/Language.resx | 3 ++ .../PasswordIncludesUpperCaseConstraint.cs | 28 ++++++++++ mRemoteV1/mRemoteV1.csproj | 1 + 6 files changed, 93 insertions(+) create mode 100644 mRemoteNGTests/Security/PasswordCreation/PasswordIncludesUpperCaseConstraintTests.cs create mode 100644 mRemoteV1/Security/PasswordCreation/PasswordIncludesUpperCaseConstraint.cs diff --git a/mRemoteNGTests/Security/PasswordCreation/PasswordIncludesUpperCaseConstraintTests.cs b/mRemoteNGTests/Security/PasswordCreation/PasswordIncludesUpperCaseConstraintTests.cs new file mode 100644 index 00000000..1e104fe5 --- /dev/null +++ b/mRemoteNGTests/Security/PasswordCreation/PasswordIncludesUpperCaseConstraintTests.cs @@ -0,0 +1,51 @@ +using System; +using mRemoteNG.Security; +using mRemoteNG.Security.PasswordCreation; +using NUnit.Framework; + + +namespace mRemoteNGTests.Security.PasswordCreation +{ + public class PasswordIncludesUpperCaseConstraintTests + { + private PasswordIncludesUpperCaseConstraint _lowerCaseConstraint; + + [Test] + public void PasswordThatExceedsMinimumLowerCasePassesValidation() + { + var password = "HELLO".ConvertToSecureString(); + _lowerCaseConstraint = new PasswordIncludesUpperCaseConstraint(); + Assert.That(_lowerCaseConstraint.Validate(password), Is.True); + } + + [Test] + public void PasswordThatMeetsMinimumLowerCasePassesValidation() + { + var password = "HELLO".ConvertToSecureString(); + _lowerCaseConstraint = new PasswordIncludesUpperCaseConstraint(5); + Assert.That(_lowerCaseConstraint.Validate(password), Is.True); + } + + [Test] + public void PasswordWithFewerThanMinimumLowerCaseFailsValidation() + { + var password = "Hello".ConvertToSecureString(); + _lowerCaseConstraint = new PasswordIncludesUpperCaseConstraint(2); + Assert.That(_lowerCaseConstraint.Validate(password), Is.False); + } + + [Test] + public void PasswordWithoutUpperCaseFailsValidation() + { + var password = "hello".ConvertToSecureString(); + _lowerCaseConstraint = new PasswordIncludesUpperCaseConstraint(); + Assert.That(_lowerCaseConstraint.Validate(password), Is.False); + } + + [Test] + public void CountToRequireMustBeAPositiveValue() + { + Assert.Throws(() => new PasswordIncludesLowerCaseConstraint(-1)); + } + } +} \ No newline at end of file diff --git a/mRemoteNGTests/mRemoteNGTests.csproj b/mRemoteNGTests/mRemoteNGTests.csproj index 5b2bea59..5038277e 100644 --- a/mRemoteNGTests/mRemoteNGTests.csproj +++ b/mRemoteNGTests/mRemoteNGTests.csproj @@ -140,6 +140,7 @@ + diff --git a/mRemoteV1/Resources/Language/Language.Designer.cs b/mRemoteV1/Resources/Language/Language.Designer.cs index efe14e85..2c1e0293 100644 --- a/mRemoteV1/Resources/Language/Language.Designer.cs +++ b/mRemoteV1/Resources/Language/Language.Designer.cs @@ -3838,6 +3838,15 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized string similar to Password must contain at least {0} upper case character(s). + /// + internal static string strPasswordContainsUpperCaseConstraintHint { + get { + return ResourceManager.GetString("strPasswordContainsUpperCaseConstraintHint", resourceCulture); + } + } + /// /// Looks up a localized string similar to Password length must be between {0} and {1}. /// diff --git a/mRemoteV1/Resources/Language/Language.resx b/mRemoteV1/Resources/Language/Language.resx index 080e5a5a..05a6a1b7 100644 --- a/mRemoteV1/Resources/Language/Language.resx +++ b/mRemoteV1/Resources/Language/Language.resx @@ -2469,6 +2469,9 @@ mRemoteNG will now quit and begin with the installation. Password must contain at least {0} number(s) + + Password must contain at least {0} upper case character(s) + Password length must be between {0} and {1} diff --git a/mRemoteV1/Security/PasswordCreation/PasswordIncludesUpperCaseConstraint.cs b/mRemoteV1/Security/PasswordCreation/PasswordIncludesUpperCaseConstraint.cs new file mode 100644 index 00000000..bf5f60e5 --- /dev/null +++ b/mRemoteV1/Security/PasswordCreation/PasswordIncludesUpperCaseConstraint.cs @@ -0,0 +1,28 @@ +using System; +using System.Security; +using System.Text.RegularExpressions; + +namespace mRemoteNG.Security.PasswordCreation +{ + public class PasswordIncludesUpperCaseConstraint : IPasswordConstraint + { + private readonly int _minimumCount; + + public string ConstraintHint { get; } + + public PasswordIncludesUpperCaseConstraint(int minimumCount = 1) + { + if (minimumCount < 0) + throw new ArgumentException($"{nameof(minimumCount)} must be a positive value"); + + _minimumCount = minimumCount; + ConstraintHint = string.Format(Language.strPasswordContainsUpperCaseConstraintHint, _minimumCount); + } + + public bool Validate(SecureString password) + { + var regex = new Regex(@"[A-Z]"); + return regex.Matches(password.ConvertToUnsecureString()).Count >= _minimumCount; + } + } +} \ No newline at end of file diff --git a/mRemoteV1/mRemoteV1.csproj b/mRemoteV1/mRemoteV1.csproj index b05fd952..1acf3e34 100644 --- a/mRemoteV1/mRemoteV1.csproj +++ b/mRemoteV1/mRemoteV1.csproj @@ -226,6 +226,7 @@ +