MoK: Passwort ändern ist jetzt möglich und testbereit.

This commit is contained in:
2023-07-13 13:39:41 +02:00
parent 78b73474f1
commit 691ff79d7f
11 changed files with 426 additions and 113 deletions

View File

@@ -47,107 +47,107 @@ namespace BeWo.PasswortSecurity
*/
#region Passwort Stärke Ermitteln und Anzeigen
public static Label ShowPasswordStrengthLabel(string passwordToValidate, Label passwordStrengthLabel)
{
var passwordStrength = CalculatePasswordStrength(passwordToValidate);
//public static Label ShowPasswordStrengthLabel(string passwordToValidate, Label passwordStrengthLabel)
//{
// var passwordStrength = CalculatePasswordStrength(passwordToValidate);
var visibility = Visibility.Visible;
var content = "Passwortstärke: ";
var foreground = new SolidColorBrush(Colors.Black);
// var visibility = Visibility.Visible;
// var content = "Passwortstärke: ";
// var foreground = new SolidColorBrush(Colors.Black);
switch(passwordStrength)
{
case 0:
content += "sehr schwach";
foreground = new SolidColorBrush(Colors.Red);
break;
case 1:
content += "schwach";
foreground = new SolidColorBrush(Colors.OrangeRed);
break;
case 2:
content += "mittel";
foreground = new SolidColorBrush(Colors.Yellow);
break;
case 3:
content += "stark";
foreground = new SolidColorBrush(Colors.Green);
break;
case 4:
content += "sehr stark";
foreground = new SolidColorBrush(Colors.Green);
break;
default:
visibility = Visibility.Hidden;
content = string.Empty;
break;
}
// switch(passwordStrength)
// {
// case 0:
// content += "sehr schwach";
// foreground = new SolidColorBrush(Colors.Red);
// break;
// case 1:
// content += "schwach";
// foreground = new SolidColorBrush(Colors.OrangeRed);
// break;
// case 2:
// content += "mittel";
// foreground = new SolidColorBrush(Colors.Yellow);
// break;
// case 3:
// content += "stark";
// foreground = new SolidColorBrush(Colors.Green);
// break;
// case 4:
// content += "sehr stark";
// foreground = new SolidColorBrush(Colors.Green);
// break;
// default:
// visibility = Visibility.Hidden;
// content = string.Empty;
// break;
// }
passwordStrengthLabel.Visibility = visibility;
passwordStrengthLabel.Foreground = foreground;
passwordStrengthLabel.Content = content;
// passwordStrengthLabel.Visibility = visibility;
// passwordStrengthLabel.Foreground = foreground;
// passwordStrengthLabel.Content = content;
return passwordStrengthLabel;
}
// return passwordStrengthLabel;
//}
private static int CalculatePasswordStrength(string passwordToValidate)
{
var length = passwordToValidate?.Length ?? 0;
if(string.IsNullOrEmpty(passwordToValidate) || length < 6)
{
return -1;
}
//private static int CalculatePasswordStrength(string passwordToValidate)
//{
// var length = passwordToValidate?.Length ?? 0;
// if(string.IsNullOrEmpty(passwordToValidate) || length < 6)
// {
// return -1;
// }
var score = 0;
// var score = 0;
if(length < 9)
{
score += 1;
}
else if(length < 12)
{
score += 2;
}
else if(length < 18)
{
score += 3;
}
else
{
score += 4;
}
// if(length < 9)
// {
// score += 1;
// }
// else if(length < 12)
// {
// score += 2;
// }
// else if(length < 18)
// {
// score += 3;
// }
// else
// {
// score += 4;
// }
var numberCount = passwordToValidate.Count(c => Numbers.Contains(c));
var lowercaseLetterCount = passwordToValidate.Count(c => LowercaseLetters.Contains(c));
var uppercaseLetterCount = passwordToValidate.Count(c => UppercaseLetters.Contains(c));
var lowercaseUmlautsCount = passwordToValidate.Count(c => LowercaseUmlauts.Contains(c));
var uppercaseUmlautsCount = passwordToValidate.Count(c => UppercaseUmlauts.Contains(c));
var specialCharacterCount = passwordToValidate.Count(c => SpecialCharacters.Contains(c));
// var numberCount = passwordToValidate.Count(c => Numbers.Contains(c));
// var lowercaseLetterCount = passwordToValidate.Count(c => LowercaseLetters.Contains(c));
// var uppercaseLetterCount = passwordToValidate.Count(c => UppercaseLetters.Contains(c));
// var lowercaseUmlautsCount = passwordToValidate.Count(c => LowercaseUmlauts.Contains(c));
// var uppercaseUmlautsCount = passwordToValidate.Count(c => UppercaseUmlauts.Contains(c));
// var specialCharacterCount = passwordToValidate.Count(c => SpecialCharacters.Contains(c));
score += numberCount * 3;
score += lowercaseLetterCount * 2;
score += uppercaseLetterCount * 3;
score += lowercaseUmlautsCount * 2;
score += uppercaseUmlautsCount * 2;
score += specialCharacterCount * 4;
// score += numberCount * 3;
// score += lowercaseLetterCount * 2;
// score += uppercaseLetterCount * 3;
// score += lowercaseUmlautsCount * 2;
// score += uppercaseUmlautsCount * 2;
// score += specialCharacterCount * 4;
if(score < 16)
{
return 0;
}
// if(score < 16)
// {
// return 0;
// }
if(score < 56)
{
return 1;
}
// if(score < 56)
// {
// return 1;
// }
if(score < 116)
{
return 2;
}
// if(score < 116)
// {
// return 2;
// }
return score < 156 ? 3 : 4;
}
// return score < 156 ? 3 : 4;
//}
// Score, PreivousValue, Schalter, und LetzteWerte werden im Objekt gepeichert.
public Label ErmittleUndZeigePasswortStaerke(string passwordToValidate, Label passwordLabel)

View File

@@ -296,6 +296,7 @@
<Compile Include="Util\JsonOrganisation.cs" />
<Compile Include="Util\MobileUserSettingsUtils.cs" />
<Compile Include="Util\NullableDateTimeSpan.cs" />
<Compile Include="Util\PasswordUtils.cs" />
<Compile Include="Util\QuittierungsbelegItem.cs" />
<Compile Include="Util\QuittierungsbelegResult.cs" />
<Compile Include="Util\RecurrenceInformation.cs" />

View File

@@ -8,7 +8,7 @@
<IISExpressWindowsAuthentication />
<IISExpressUseClassicPipelineMode />
<UseGlobalApplicationHostFile />
<LastActiveSolutionConfig>Release|Any CPU</LastActiveSolutionConfig>
<LastActiveSolutionConfig>Debug|Any CPU</LastActiveSolutionConfig>
<ProjectView>ShowAllFiles</ProjectView>
<WebStackScaffolding_ViewDialogWidth>600</WebStackScaffolding_ViewDialogWidth>
<Controller_SelectedScaffolderID>MvcControllerEmptyScaffolder</Controller_SelectedScaffolderID>

View File

@@ -6,6 +6,7 @@ using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Windows.Forms;
using BeWo.Data.Entities;
using BeWo.Service.Plugins;
using BeWo.Service.ServiceImplementations;
using BeWo.View.Navigation.Filter;
@@ -26,6 +27,8 @@ using DevExpress.XtraScheduler.Compatibility;
using Newtonsoft.Json;
using static BS.Shared.ServiceRecordValidationResult;
using FormCollection = System.Web.Mvc.FormCollection;
using GoalRating = BeWoPlanerMobil.Util.GoalRating;
using Image = System.Drawing.Image;
using ServiceRecordDC = BS.Shared.DataContracts.ServiceRecordDC;
namespace BeWoPlanerMobil.Controllers
@@ -101,6 +104,28 @@ namespace BeWoPlanerMobil.Controllers
var mokSessionTimeout = UserSettingsUtils.GetSettingValueAsInteger(Model.Mandator.Settings, SettingsKeys.MoKSessionTimeout, 20);
Session.Timeout = mokSessionTimeout;
Model.IsPasswordSecurityEnabled = UserSettingsUtils.GetSettingValueAsBool(Model.Mandator.Settings, SettingsKeys.IsPasswordSecurityActiv);
if(Model.IsPasswordSecurityEnabled)
{
var tempDataValue = string.Empty;
switch(MobileSessionFacade.PasswordStrength)
{
case 0:
tempDataValue = "Sie benutzen ein sehr schwaches Passwort.<br/><br/>Bitte &auml;ndern Sie Ihr Passwort, indem Sie im Men&uuml; auf 'Password &auml;ndern' klicken.";
break;
case 1:
tempDataValue = "Sie benutzen ein schwaches Passwort.<br/><br/>Bitte &auml;ndern Sie Ihr Passwort, indem Sie im Men&uuml; auf 'Password &auml;ndern' klicken.";
break;
}
if(!string.IsNullOrEmpty(tempDataValue))
{
TempData["show_pw_change_popup"] = tempDataValue;
}
}
}
var mandatorSettings = Model.Mandator.Settings;
@@ -3807,14 +3832,23 @@ namespace BeWoPlanerMobil.Controllers
return RedirectToActionPermanent("Main");
}
var passwordUtils = new PasswordUtils();
if(passwordUtils.EvaluatePasswordStrength(newPassword) < 2)
{
var checkResult = UserService.CheckPassword(MobileSessionFacade.LoggedInUser.Oid.Value, oldPassword, newPassword);
if(!(checkResult is null))
{
TempData["passwd-change-error"] = checkResult;
return RedirectToActionPermanent("Main");
}
}
var userName = MobileSessionFacade.LoggedInUserDC.LoginName;
var userVersion = MobileSessionFacade.LoggedInUserDC.UserVersion.Value;
// ToDo: Testen! falsches oldPassword, kein oldPassword, newPassword stimmt nicht mit confirmationPassword überein, kein confirmationPassword, kein newPassword
UserService.ChangePassword(userName, userVersion, oldPassword, newPassword);
// ToDo: Regeln beachten, welche Passwortstärke mindestens erreicht werden muss.
return RedirectToActionPermanent("Main");
}
}

View File

@@ -671,7 +671,6 @@ namespace BeWoPlanerMobil.Models
public bool IsOnlyYearMonthVisible { get; set; }
#region Mehrfachbuchung
private bool _IsInMultiBookingMode;
@@ -725,9 +724,11 @@ namespace BeWoPlanerMobil.Models
}
}
#endregion
public MandatorDC Mandator { get; set; }
#endregion
public bool IsPasswordSecurityEnabled { get; set; }
}
public class CustomSelectListItem

View File

@@ -82,22 +82,22 @@ function submitForm(submitButton) {
submitButton.form.submit();
}
function showMessagePopupWithHtml(title, html) {
$("#popupTitle").text(title);
//function showMessagePopupWithHtml(title, html) {
// $("#popupTitle").text(title);
if(html !== null) {
$("#modal-body").html("<p id=\"popupMessage\"></p>");
}
// if(html !== null) {
// $("#modal-body").html("<p id=\"popupMessage\"></p>");
// }
$("#popupMessage").html(html);
// $("#popupMessage").html(html);
$("#messagePopup").modal(
{
backdrop: "static",
keyboard: false
}
);
}
// $("#messagePopup").modal(
// {
// backdrop: "static",
// keyboard: false
// }
// );
//}
function hasEmptyRequiredFields(form) {
var count = 0;

View File

@@ -10,7 +10,7 @@ using System.Web;
using BeWo.Data.Access;
using BeWo.Data.Entities;
using BeWo.Service.ServiceImplementations;
using BeWoPlanerMobil.Util;
using BS.Shared;
using BS.Shared.Core;
using log4net;
@@ -184,6 +184,7 @@ namespace BeWoPlanerMobil.Service
return false;
}
MobileSessionFacade.PasswordStrength = new PasswordUtils().EvaluatePasswordStrength(password);
MobileSessionFacade.LoggedInUser = user;
}

View File

@@ -84,5 +84,7 @@ namespace BeWoPlanerMobil.Service
}
public static string CookieName => "tenantKeks";
public static int PasswordStrength;
}
}

View File

@@ -0,0 +1,231 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using BeWo.Data.Access;
using BS.Shared.DataContracts;
namespace BeWoPlanerMobil.Util
{
internal class PasswordUtils
{
private const string Numbers = "0123456789";
private const string LowercaseLetters = "abcdefghijklmnopqrstuvwxyz";
private const string UppercaseLetters = "ABDEFGHIJKLMNOPQRSTUVWXYZ";
private const string LowercaseUmlauts = "äöüß";
private const string UppercaseUmlauts = "ÄÖÜ";
private const string SpecialCharacters1 = "\\\"\'µ@€!";
private const string SpecialCharacters2 = "&/()=?+#*";
private const string SpecialCharacters3 = ",.-;:_><|";
private const string SpecialCharacters4 = "§$%'{[]}´";
private const string SpecialCharacters5 = "`^°~²³";
private string _PartialPassword = string.Empty;
private bool _IsPartial;
private int _PasswordLengthDifference;
private int _Score;
private int _PreviousValue;
private bool _Schalter;
private List<int> _PreviousValues = new List<int>();
public int EvaluatePasswordStrength(string passwordToEvaluate)
{
var passwordStrength = 0;
_PreviousValue = 0;
if(string.IsNullOrWhiteSpace(passwordToEvaluate))
{
return 0;
}
if(_IsPartial)
{
if(_PasswordLengthDifference == 1)
{
_Score -= _PreviousValues.Last();
_PreviousValues.RemoveAt(_PreviousValues.Count - 1);
}
else
{
for(var i = 0; i < _PasswordLengthDifference; i++)
{
_Score += _PreviousValues.Last();
_PreviousValues.RemoveAt(_PreviousValues.Count - 1);
}
}
_IsPartial = false;
}
else
{
var passwordLength = passwordToEvaluate.Length;
if(passwordLength > 5 && passwordLength < 9)
{
AddLengthScore(1);
}
if(passwordLength > 8 && passwordLength < 12)
{
AddLengthScore(2);
}
if(passwordLength > 11 && passwordLength < 18)
{
AddLengthScore(3);
}
if(passwordLength > 17)
{
AddLengthScore(4);
}
// Ziffern
if(passwordToEvaluate.Any(character => Numbers.Contains(character)))
{
AddTokenScore(3);
}
// Großbuchstaben
if(passwordToEvaluate.Any(character => UppercaseLetters.Contains(character)))
{
AddTokenScore(3);
}
// Großumlaute
if(passwordToEvaluate.Any(character => UppercaseUmlauts.Contains(character)))
{
AddTokenScore(2);
}
// Kleinbuchstaben
if(passwordToEvaluate.Any(character => LowercaseLetters.Contains(character)))
{
AddTokenScore(2);
}
// Kleinumlaute
if(passwordToEvaluate.Any(character => LowercaseUmlauts.Contains(character)))
{
AddTokenScore(2);
}
// Sonderzeichen
if(passwordToEvaluate.Any(character => SpecialCharacters1.Contains(character)))
{
AddTokenScore(4);
}
if(passwordToEvaluate.Any(character => SpecialCharacters2.Contains(character)))
{
AddTokenScore(4);
}
if(passwordToEvaluate.Any(character => SpecialCharacters3.Contains(character)))
{
AddTokenScore(4);
}
if(passwordToEvaluate.Any(character => SpecialCharacters4.Contains(character)))
{
AddTokenScore(4);
}
if(passwordToEvaluate.Any(character => SpecialCharacters5.Contains(character)))
{
AddTokenScore(4);
}
_PreviousValues.Add(_PreviousValue);
}
if(_Score < 16)
{
passwordStrength = 0;
}
if(_Score > 15 && _Score < 56)
{
passwordStrength = 1;
}
if(_Score > 55 && _Score < 116)
{
passwordStrength = 2;
}
if(_Score > 115 && _Score < 156)
{
passwordStrength = 3;
}
if(_Score > 155)
{
passwordStrength = 4;
}
return passwordStrength;
}
private void AddLengthScore(int valueToAdd)
{
_Score += valueToAdd;
_PreviousValue = valueToAdd;
_Schalter = true;
}
private void AddTokenScore(int valueToAdd)
{
_Score += valueToAdd;
if(_Schalter)
{
_PreviousValue += valueToAdd;
}
else
{
_PreviousValue = valueToAdd;
}
}
public string CheckPassword(string newPassword)
{
if(string.IsNullOrEmpty(newPassword))
{
return "Das Passwort muss mindestens 8 Zeichen lang sein!";
}
var passwordLength = newPassword.Length;
if(passwordLength < 8)
{
return "Das Passwort muss mindestens 8 Zeichen lang sein!";
}
var richtliniencount = 0;
if(newPassword.Any(character => Numbers.Contains(character)))
{
richtliniencount++;
}
if(newPassword.Any(character => LowercaseLetters.Contains(character) || LowercaseUmlauts.Contains(character)))
{
richtliniencount++;
}
if(newPassword.Any(character => UppercaseLetters.Contains(character) || UppercaseUmlauts.Contains(character)))
{
richtliniencount++;
}
if(newPassword.Any(character => SpecialCharacters1.Contains(character) || SpecialCharacters2.Contains(character) || SpecialCharacters3.Contains(character) || SpecialCharacters4.Contains(character) || SpecialCharacters5.Contains(character)))
{
richtliniencount++;
}
return richtliniencount < 3 ? "Das Passwort muss mindestens drei Zeichen aus der Gruppe Sonderzeichen, Zahlen, Groß- und Kleinbuchstaben enthalten." : null;
}
}
}

View File

@@ -29,7 +29,34 @@
function submitChangePasswordForm() {
try {
showSpinner();
$('#change-password-form').submit();
var form = $('#change-password-form');
var isValid = true;
// ToDo: Hier weitermachen
//$.each($(".pw-chng-inv-fdb"),
$.each($(".pw-ch-in-container"),
function (index, item) {
var input = $(item).find("input");
var feedback = $(item).find(".pw-chng-inv-fdb");
logInfo3(input.val());
if (isEmptyOrSpaces(input.val())) {
feedback.addClass("d-block");
isValid = false;
} else {
feedback.removeClass("was-validated");
feedback.removeClass("d-block");
}
feedback.addClass("was-validated");
});
if (true === isValid) {
form.submit();
} else {
hideSpinner();
}
} catch (error) {
showErrorPopup(error);
}
@@ -245,6 +272,13 @@
initializeSignatureImagePopup();
@if(TempData["show_pw_change_popup"] is string passwordWarning && !string.IsNullOrEmpty(passwordWarning))
{
<text>
showMessagePopupWithHtml("Achtung!", "@Html.Raw(passwordWarning)");
</text>
}
@if (Model != null && Model.IsInEditingMode)
{
<text>
@@ -826,31 +860,40 @@
</div>
<div class="row">
<div class="col">
<div class="input-group mb-3">
<div class="input-group mb-3 pw-ch-in-container">
<div class="input-group-prepend">
<div class="input-group-text pw-prepend">Altes Passwort</div>
</div>
<input type="password" class="form-control" name="old-password" required />
<div class="invalid-feedback pw-chng-inv-fdb">
Dieses Feld darf nicht leer sein.
</div>
</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="input-group mb-3">
<div class="input-group mb-3 pw-ch-in-container">
<div class="input-group-prepend">
<div class="input-group-text pw-prepend">Neues Passwort</div>
</div>
<input type="password" class="form-control" name="new-password" id="new-password" onkeyup="validatePasswordStrength()" required />
<div class="invalid-feedback pw-chng-inv-fdb">
Dieses Feld darf nicht leer sein.
</div>
</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="input-group mb-3">
<div class="input-group mb-3 pw-ch-in-container">
<div class="input-group-prepend">
<span class="input-group-text pw-prepend">Passwort bestätigen</span>
</div>
<input type="password" class="form-control" name="confirm-new-password" id="confirm-new-password" required />
<div class="invalid-feedback pw-chng-inv-fdb">
Dieses Feld darf nicht leer sein.
</div>
</div>
</div>
</div>

View File

@@ -3,7 +3,7 @@
<PropertyGroup>
<NameOfLastUsedPublishProfile>BeWo2.0</NameOfLastUsedPublishProfile>
<UseIISExpress>true</UseIISExpress>
<LastActiveSolutionConfig>Release|Any CPU</LastActiveSolutionConfig>
<LastActiveSolutionConfig>Debug|Any CPU</LastActiveSolutionConfig>
<Use64BitIISExpress>false</Use64BitIISExpress>
<IISExpressSSLPort />
<IISExpressAnonymousAuthentication />