diff --git a/SacsCoreWeb/Web/Components/SaController.cs b/SacsCoreWeb/Web/Components/SaController.cs
index 0adac01..2fbd838 100644
--- a/SacsCoreWeb/Web/Components/SaController.cs
+++ b/SacsCoreWeb/Web/Components/SaController.cs
@@ -135,7 +135,7 @@ namespace Sacs.Web.Components
// Serialise parameters as if in a URL query string - so that they can be deserialised in DecryptParameters() below.
// Start with a random length parameter name at start of list to obscure the encryption.
- string queryString = SacsRandomHelper.getRandomLengthNumber(4) + "&";
+ string queryString = SacsRandomHelper.GetRandomLengthNumber(4) + "&";
queryString += String.Join("&", paramKeys.Select(a => a + "=" + HttpUtility.UrlEncode(parametersToEncrypt[a])));
// Encrypt data.
@@ -286,7 +286,7 @@ namespace Sacs.Web.Components
ConfirmMessage = new ConfirmMessageData() { Title = title, Text = text, Actions = actions };
return this;
}
- public bool HasConfirmMessage { get { return ConfirmMessage != null; } }
+ public bool? HasConfirmMessage { get { return ConfirmMessage != null ? true : null; } }
}
//-------------------------------------------------------------------
diff --git a/SacsMobileMaui/SacsMobileMaui.csproj b/SacsMobileMaui/SacsMobileMaui.csproj
index 3def31e..114683f 100644
--- a/SacsMobileMaui/SacsMobileMaui.csproj
+++ b/SacsMobileMaui/SacsMobileMaui.csproj
@@ -22,7 +22,6 @@
-
diff --git a/SacsMobileXamarin/SacsMobileXamarin.csproj b/SacsMobileXamarin/SacsMobileXamarin.csproj
index a74f7c4..4189384 100644
--- a/SacsMobileXamarin/SacsMobileXamarin.csproj
+++ b/SacsMobileXamarin/SacsMobileXamarin.csproj
@@ -7,7 +7,7 @@
-
+
diff --git a/SacsStandardBase/Base/Bus/SaErrorStateItem.cs b/SacsStandardBase/Base/Bus/SaErrorStateItem.cs
index 288e7c1..539be0d 100644
--- a/SacsStandardBase/Base/Bus/SaErrorStateItem.cs
+++ b/SacsStandardBase/Base/Bus/SaErrorStateItem.cs
@@ -43,11 +43,16 @@ namespace Sarand.Net.Standard.Base.Bus
//-------------------------------------------------------------------
// Properties.
+ /// OK - No error state message.
+ public bool OK { get { return !HasErrorState(); } }
+
//-------------------------------------------------------------------
- // E r r o r S t a t e
+ // Error State.
//-------------------------------------------------------------------
+
private SacsErrorState errorState = null;
- public bool HasErrorState ()
+
+ public bool HasErrorState()
{
return errorState != null;
}
diff --git a/SacsStandardBase/Base/Bus/SysId.cs b/SacsStandardBase/Base/Bus/SysId.cs
index a09b694..c7b2c75 100644
--- a/SacsStandardBase/Base/Bus/SysId.cs
+++ b/SacsStandardBase/Base/Bus/SysId.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
+using System.Diagnostics.Contracts;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@@ -111,6 +112,12 @@ namespace Sarand.Net.Standard.Base.Bus
return (IsValid(sysId) ? sysId.id.ToString() : invalidValue);
}
+ // From String.
+ public static SysId ToSysId(String value)
+ {
+ return new SysId(StringUtil.ToLong(value));
+ }
+
//-------------------------------------------------------------------
///
/// JSON Converter to serialise/deserialise SysId to/from simple integer value.
diff --git a/SacsStandardBase/Base/Dbas/IDbDataTable.cs b/SacsStandardBase/Base/Dbas/IDbDataTable.cs
deleted file mode 100644
index eb86c35..0000000
--- a/SacsStandardBase/Base/Dbas/IDbDataTable.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace Sarand.Net.Standard.Base.Dbas
-{
- //=======================================================================
- public interface IDbDataTable
- {
- }
-
- //=======================================================================
-}
diff --git a/SacsStandardBase/Base/Dbas/ISacsDatabase.cs b/SacsStandardBase/Base/Dbas/ISacsDatabase.cs
index 45a99e0..2ebba41 100644
--- a/SacsStandardBase/Base/Dbas/ISacsDatabase.cs
+++ b/SacsStandardBase/Base/Dbas/ISacsDatabase.cs
@@ -68,27 +68,39 @@ namespace Sarand.Net.Standard.Base.Dbas
//-------------------------------------------------------------------
// Database schema.
- List GetTableNames (bool refresh = false);
- List GetTableDfns (bool refresh = false);
- DbDfnTable GetTableDfn (String name, bool refresh = false);
- bool TableExists (String tableName);
- bool ColumnExists (String tableName, String columnName);
- bool IndexExists (String tableName, String indexName);
+ List GetTableNames(bool refresh = false);
+ List GetTableDfns(bool refresh = false);
+ DbDfnTable GetTableDfn(String name, bool refresh = false);
+ bool TableExists(String tableName);
+ bool ColumnExists(String tableName, String columnName);
+ bool IndexExists(String tableName, String indexName);
// Database info - schema summary.
IDatabaseInfo CreateDbInfo();
+ //-------------------------------------------------------------------
+ // Password utilities.
+ public enum PasswordHashMethod { MsSql }
+ /// Generate password hash using the specified method.
+ String EncodePassword_Hex(String password, PasswordHashMethod method = PasswordHashMethod.MsSql);
+ /// Compare password to hashed value using the specified method.
+ bool ComparePassword_Hex(String password, String passwordHashHex, ISacsDatabase.PasswordHashMethod method = ISacsDatabase.PasswordHashMethod.MsSql);
+
//-------------------------------------------------------------------
// Query records.
- String GetSelectQueryPrefix ();
- IDbDataTable ExecuteQuery (String query);
- int ExecuteNonQuery (String query);
- int ExecuteInsert (String tableName, List columnNameValues);
- int ExecuteUpdate (String tableName, List columnNameValues, String filter);
- int ExecuteDelete (String tableName, String filter);
+ String GetSelectQueryPrefix();
+ ///
+ /// Execute query directly against database.
+ /// - NB Check for null response and error state.
+ ///
+ DbResultSet ExecuteQuery(String query);
+ int ExecuteNonQuery(String query);
+ int ExecuteInsert(String tableName, List columnNameValues);
+ int ExecuteUpdate(String tableName, List columnNameValues, String filter);
+ int ExecuteDelete(String tableName, String filter);
// Specific queries.
- long GetRowCount (String tableName, String filter);
- DataValue GetRowValue (String tableName, String columnName, String filter);
- DataValue GetRowValue (String tableName, String columnName, String filter, DbGetValueType getValueType);
+ long GetRowCount(String tableName, String filter);
+ DataValue GetRowValue(String tableName, String columnName, String filter);
+ DataValue GetRowValue(String tableName, String columnName, String filter, DbGetValueType getValueType);
//-------------------------------------------------------------------
}
diff --git a/SacsStandardBase/Base/Helpers/SacsRandomHelper.cs b/SacsStandardBase/Base/Helpers/SacsRandomHelper.cs
index 96624a9..576a83d 100644
--- a/SacsStandardBase/Base/Helpers/SacsRandomHelper.cs
+++ b/SacsStandardBase/Base/Helpers/SacsRandomHelper.cs
@@ -1,6 +1,7 @@
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
+using System.IO;
using System.Security.Cryptography;
using System.Text;
@@ -52,19 +53,27 @@ namespace Sarand.Net.Standard.Base.Helpers
}
//-------------------------------------------------------------------
- public static String getRandomLengthNumber(ushort maxLength=4)
+ public static String GetRandomLengthNumber(ushort maxLength = 4)
{
+ String fn = "getRandomLengthNumber";
String value = "";
int len = GetInt32(1, maxLength + 1);
for (int i = 0; i < len; i++)
- value += GetInt32(0,10);
- if (StringUtil.IsEmpty(value))
- throw new NotSupportedException("getRandomLengthNumber Generated blank value");
+ value += GetInt32(0, 10);
+ if (StringUtil.IsBlank(value))
+ throw new NotSupportedException($"{fn} Generated blank value");
if (value.Length > maxLength)
- throw new NotSupportedException("getRandomLengthNumber Generated excess length value");
+ throw new NotSupportedException($"{fn} Generated excess length value");
return value;
}
+ //-------------------------------------------------------------------
+ /// Returns filename in 8.3 format.
+ public static String GetRandomFileName()
+ {
+ return Path.GetRandomFileName();
+ }
+
//-------------------------------------------------------------------
}
//=======================================================================
diff --git a/SacsStandardBase/Base/Security/SaSecurityConsole.cs b/SacsStandardBase/Base/Security/SaSecurityConsole.cs
index f01368d..f2a45f5 100644
--- a/SacsStandardBase/Base/Security/SaSecurityConsole.cs
+++ b/SacsStandardBase/Base/Security/SaSecurityConsole.cs
@@ -21,6 +21,12 @@ namespace Sarand.Net.Standard.Base.Security
Group = 3,
Right = 4,
}
+ // Password storage methods - must be kept up to date with legacy application.
+ public enum PasswordMethod
+ {
+ Legacy = 0,
+ MsSql = 10,
+ }
public enum FilterAttrType
{
Code, // Partial code.
@@ -29,14 +35,6 @@ namespace Sarand.Net.Standard.Base.Security
Group_Exclude, // Item doesn't belong to group.
};
}
- // Password configuration.
- public class PasswordConfig
- {
- /// Minimum password length. < 1 = no limit.
- public int MinimumLength { get; protected set; } = 6;
- /// Maximum password length. < 1 = no limit.
- public int MaximumLength { get; protected set; } = 6;
- }
//=======================================================================
public abstract class SaSecurityConsole : SaErrorStateItem
@@ -58,8 +56,8 @@ namespace Sarand.Net.Standard.Base.Security
//-------------------------------------------------------------------
// Data members.
- protected static String GroupSuperCode = "SUPER";
- protected static String AdminUserCode = "admin";
+ public static String GroupCode_Super = "SUPER";
+ public static String UserCode_Admin = "admin";
private static List securityItemTypes = new List();
//-------------------------------------------------------------------
@@ -116,6 +114,12 @@ namespace Sarand.Net.Standard.Base.Security
return userIdDefault;
}
+ protected void ClearRegisteredSecurityRights()
+ {
+ RegisteredRights.Clear();
+ DataItemDfns.Clear();
+ }
+
//-------------------------------------------------------------------
// L o g i n
//-------------------------------------------------------------------
@@ -140,9 +144,28 @@ namespace Sarand.Net.Standard.Base.Security
/// Security Group modified event.
public abstract bool OnSecurityGroupModified(SysId userId);
+ //-------------------------------------------------------------------
+ // Password utilities.
//-------------------------------------------------------------------
// Password configuration.
- public PasswordConfig PasswordConfig { get; protected set; } = new PasswordConfig();
+ public class SaPasswordConfig
+ {
+ /// Minimum password length. < 1 = no limit.
+ public int MinimumLength { get; protected set; } = 6;
+ /// Maximum password length. < 1 = no limit.
+ public int MaximumLength { get; protected set; } = 6;
+ }
+ public SaPasswordConfig PasswordConfig { get; protected set; } = new SaPasswordConfig();
+
+ /// Store the password against against the user.
+ public abstract bool SetPassword(SaSecurityItem securityItemUser, String password);
+
+ /// Does the password match that currently defined against the user.
+ public abstract bool PasswordMatches(SaSecurityItem securityItemUser, String password);
+
+ /// Is the password currently defined against the user blank.
+ public abstract bool PasswordIsBlank(SaSecurityItem securityItemUser);
+
/// Show form to change password for currently logged in user.
/// Flag to indicate password changed
public abstract bool ShowChangePasswordForm(DbUpdateInfo dbUpdateInfo);
diff --git a/SacsStandardBase/Base/Security/SaSecurityItem.cs b/SacsStandardBase/Base/Security/SaSecurityItem.cs
index 127244f..1248b74 100644
--- a/SacsStandardBase/Base/Security/SaSecurityItem.cs
+++ b/SacsStandardBase/Base/Security/SaSecurityItem.cs
@@ -12,6 +12,11 @@ namespace Sarand.Net.Standard.Base.Security
//=======================================================================
public abstract class SaSecurityItem : SacsHierarchyItem
{
+ //-------------------------------------------------------------------
+ // Definitions.
+ // Password Salt constants - must be kept up to date with legacy application.
+ private static String PasswordSalt_MsSql = "MsSql";
+
//-------------------------------------------------------------------
// Columns.
public enum Column
@@ -67,7 +72,7 @@ namespace Sarand.Net.Standard.Base.Security
// Data members.
private readonly DataProperties data = new DataProperties();
// Construction.
- public Data ()
+ public Data()
{
Status = DefaultStatus;
}
@@ -161,7 +166,7 @@ namespace Sarand.Net.Standard.Base.Security
set { SetFlag(Flag_AuthenticatedUser, value); }
}
// Population.
- internal void PopulateFrom (Data data)
+ internal void PopulateFrom(Data data)
{
ItemType = data.ItemType;
Code = data.Code;
@@ -182,7 +187,7 @@ namespace Sarand.Net.Standard.Base.Security
InvalidLoginCount = data.InvalidLoginCount;
base.PopulateFrom(data);
}
- public Data Clone ()
+ public Data Clone()
{
Data data = new Data();
data.PopulateFrom(this);
@@ -219,7 +224,7 @@ namespace Sarand.Net.Standard.Base.Security
//-------------------------------------------------------------------
// Construction.
- public SaSecurityItem (SysId id, SaSecurity.ItemType securityItemType) :
+ public SaSecurityItem(SysId id, SaSecurity.ItemType securityItemType) :
base(id)
{
base.SetData(data);
@@ -238,7 +243,7 @@ namespace Sarand.Net.Standard.Base.Security
public static SaStatus EnabledStatus { get { return SaStatus.Enabled; } }
public static SaStatus DisabledStatus { get { return SaStatus.Disabled; } }
public static List ValidStatuses { get { return new List(securityItemStatuses); } }
- public static DataValue.TriStateType GetStatusTriState (SaStatus status)
+ public static DataValue.TriStateType GetStatusTriState(SaStatus status)
{
switch (status)
{
@@ -254,8 +259,8 @@ namespace Sarand.Net.Standard.Base.Security
//-------------------------------------------------------------------
// Data properties.
- public Data GetData () { return data.Clone(); }
- public void SetData (Data data)
+ public Data GetData() { return data.Clone(); }
+ public void SetData(Data data)
{
// Properties that cannot be changed if previously specified.
if (SysId.IsValid(Id) && SysId.ToInt(Id) != SysId.ToInt(data.Id))
@@ -359,68 +364,31 @@ namespace Sarand.Net.Standard.Base.Security
//-------------------------------------------------------------------
// Password utilities.
- private static readonly Encoding Encoding_Ansi1252 = Encoding.GetEncoding(1252);
- public bool IsPasswordBlank ()
- {
- return EncryptPassword("").Equals(PasswordEncrypted);
- }
- public bool PasswordMatches (String password)
- {
- return PasswordEncrypted.Equals(EncryptPassword(password));
- }
- public static String EncryptPassword (String password)
- {
- // We know this is not very water-tight, but it at least
- // hides the contents of the password from prying eyes.
- String toBeEncrypted = password;
- // Password length goes in as first character:
- toBeEncrypted = ByteToString((byte)(128 - password.Length)) + toBeEncrypted;
- toBeEncrypted = string.Concat(toBeEncrypted.Reverse());
- // Pad out to fixed length (minimum 16, multiples of 8):
- int fixedLength = 16;
- if (password.Length / 8 > 2) fixedLength = 8 * (int)(password.Length / 8);
- while (toBeEncrypted.Length < fixedLength)
- {
- char charToAdd = (char)(password.Length > 0 ? password[(toBeEncrypted.Length % password.Length)] : 'A' + (toBeEncrypted.Length * 13) % 23);
- if (toBeEncrypted.Length % 2 != 0)
- toBeEncrypted += charToAdd;
- else toBeEncrypted = charToAdd + toBeEncrypted;
- }
- // Now perform a simple algorythm on each character to hide its true value:
- byte[] encryptedChars = new byte[toBeEncrypted.Length];
- for (int i = 0; i < toBeEncrypted.Length; i++)
- {
- int iData = toBeEncrypted[i];
- iData += 17 + i;
- if (iData > 255) iData -= (255 + 32);
- encryptedChars[i] = (byte)iData;
- }
- String result = Encoding_Ansi1252.GetString(encryptedChars);
-#if DEBUG
- // Password: mgbgt
- // To encrypt: tbmggtgbgm{btggm
- // Encrypted: 133, 116, 128, 123, 124, 138, 126, 122, 128, 135, 150, 126, 145, 133, 134, 141
- //Logger.Info(fn + "\n\tPassword: " + password + "\n\tTo encrypt: " + toBeEncrypted + "\n\tEncrypted: " + encryptedChars.Select(i => i.ToString()).ToList().Concat(", "));
- //Logger.Debug(password + ": " + result);
-#endif
- return result;
- }
- private byte[] PasswordStringToBytes (String value)
+ /// Extract password storage method from data.
+ public SaSecurity.PasswordMethod GetPasswordMethod()
{
- byte[] values = new byte[value.Length];
- for (int idx = 0; idx < value.Length; idx++)
- {
- char c = value[idx];
- UInt32 ui = Convert.ToUInt32(c);
- SaLogger.Info(idx + ". " + ui.ToString("x8"));
- values[idx] = (byte)(c);
- }
- return values;
+ return SaSecurity.PasswordMethod.Legacy;
}
- private static String ByteToString (byte value)
+
+ public void SetEncodedPassword(SaSecurity.PasswordMethod method, String encodedPassword)
{
- return Encoding_Ansi1252.GetString(new[] { value });
+ if (method == SaSecurity.PasswordMethod.MsSql)
+ {
+#pragma warning disable CS0618 // Deprecated property
+ PasswordEncrypted = "";
+#pragma warning restore CS0618 // Deprecated property
+ PasswordSalt = PasswordSalt_MsSql;
+ PasswordHash = encodedPassword;
+ }
+ else
+ {
+#pragma warning disable CS0618 // Deprecated property
+ PasswordEncrypted = encodedPassword;
+#pragma warning restore CS0618 // Deprecated property
+ PasswordSalt = "";
+ PasswordHash = "";
+ }
}
//-------------------------------------------------------------------
@@ -455,7 +423,7 @@ namespace Sarand.Net.Standard.Base.Security
//=======================================================================
public static class SaSecurityItemList
{
- public static SaSecurityItem GetSecItemById (this List secItems, SysId secItemId)
+ public static SaSecurityItem GetSecItemById(this List secItems, SysId secItemId)
{
if (!SysId.IsValid(secItemId)) return null;
foreach (SaSecurityItem secItem in secItems)
diff --git a/SacsStandardBase/Base/Security/SaSecurityMgr.cs b/SacsStandardBase/Base/Security/SaSecurityMgr.cs
index 6eac2f6..34e91f7 100644
--- a/SacsStandardBase/Base/Security/SaSecurityMgr.cs
+++ b/SacsStandardBase/Base/Security/SaSecurityMgr.cs
@@ -31,10 +31,19 @@ namespace Sarand.Net.Standard.Base.Security
// Database properties.
public abstract bool DatabaseIsValid { get; }
public abstract bool CanUpdateDatabase { get; }
+ public abstract bool ColumnExists (SaSecurityDbDfn.ColumnIdx columnIdx);
//-------------------------------------------------------------------
- // Utilities.
- public abstract bool ColumnExists (SaSecurityDbDfn.ColumnIdx columnIdx);
+ // Password utilities.
+
+ /// Store the password against against the user.
+ public abstract bool SetPassword(SaSecurityItem securityItemUser, String password);
+
+ /// Does the password match that currently defined against the user.
+ public abstract bool PasswordMatches(SaSecurityItem securityItemUser, String password);
+
+ /// Is the password currently defined against the user blank.
+ public abstract bool PasswordIsBlank(SaSecurityItem securityItemUser);
//-------------------------------------------------------------------
}
diff --git a/SacsStandardBase/Base/Security/SaSecurityProfile.cs b/SacsStandardBase/Base/Security/SaSecurityProfile.cs
index 9d964eb..0e7701a 100644
--- a/SacsStandardBase/Base/Security/SaSecurityProfile.cs
+++ b/SacsStandardBase/Base/Security/SaSecurityProfile.cs
@@ -10,40 +10,52 @@ namespace Sarand.Net.Standard.Base.Security
public class SaSecurityProfile
{
//-------------------------------------------------------------------
+ /// Security Group definition.
public class GroupData
{
- public readonly List rights = new List();
- public GroupData (SaSecurityItem secGroup, List groupRights)
+ private readonly List rights = new List();
+ public GroupData(SaSecurityItem secGroup, List groupRights)
{
- if (secGroup.ItemType != SaSecurity.ItemType.Group) throw new NotSupportedException("SaSecurityProfile.GroupData - Invalid security item type: "+ secGroup.ItemType.ToString());
- GroupId = secGroup.Id;
- GroupCode = secGroup.Code;
- GroupDesc = secGroup.Description;
+ if (secGroup.ItemType != SaSecurity.ItemType.Group) throw new NotSupportedException("SaSecurityProfile.GroupData - Invalid security item type: " + secGroup.ItemType.ToString());
+ Id = secGroup.Id;
+ Code = secGroup.Code;
+ Desc = secGroup.Description;
rights.AddRange(groupRights);
}
- protected GroupData () { }
- public SysId GroupId { get; protected set; }
- public String GroupCode { get; protected set; }
- public String GroupDesc { get; protected set; }
+ protected GroupData() { }
+ public SysId Id { get; }
+ public String Code { get; }
+ public String Desc { get; }
+ // Security rights.
public List Rights { get { return new List(rights); } }
+ ///
+ /// Retrieve the list of data items for which the user is explicitly granted the
+ /// specified security right, or where the right is explicitly denied if the flag is false.
+ ///
+ public List GetDataItemsForRight(String rightCode, bool granted = true) { return rights.GetDataItemsForRight(rightCode, granted); }
+ /// Is the Security Right code granted access for the Data item (if specified).
+ public bool IsSecurityRightGranted(String rightCode, SysId dataItemId = null) { return rights.IsSecurityRightGranted(rightCode, dataItemId); }
+ /// Is the Security Right code denined access for the Data item (if specified).
+ public bool IsSecurityRightDenied(String rightCode, SysId dataItemId = null) { return rights.IsSecurityRightDenied(rightCode, dataItemId); }
}
+ /// Security Right definition.
public class RightData
{
- public RightData (SaSecurityItem secRight, SaSecurityLink secRightLink)
+ public RightData(SaSecurityItem secRight, SaSecurityLink secRightLink)
{
if (secRight.ItemType != SaSecurity.ItemType.Right) throw new NotSupportedException("SaSecurityProfile.RightData - Invalid security item type: " + secRight.ItemType.ToString());
- RightId = secRight.Id;
- RightCode = secRight.Code;
- RightDesc = secRight.Description;
+ Id = secRight.Id;
+ Code = secRight.Code;
+ Desc = secRight.Description;
DataItemId = secRightLink.ItemIdContext;
Granted = (secRightLink.Status == SaStatus.Granted);
}
- protected RightData () { }
- public SysId RightId { get; protected set; }
- public String RightCode { get; protected set; }
- public String RightDesc { get; protected set; }
- public SysId DataItemId { get; protected set; }
- public bool Granted { get; protected set; }
+ protected RightData() { }
+ public SysId Id { get; }
+ public String Code { get; }
+ public String Desc { get; }
+ public SysId DataItemId { get; }
+ public bool Granted { get; }
}
//-------------------------------------------------------------------
@@ -53,7 +65,7 @@ namespace Sarand.Net.Standard.Base.Security
//-------------------------------------------------------------------
// Construction.
- internal SaSecurityProfile (SaSecurityItem secItem, List profileGroups, List profileRights, bool systemAdmin)
+ internal SaSecurityProfile(SaSecurityItem secItem, List profileGroups, List profileRights, bool systemAdmin)
{
Clear();
if (secItem != null)
@@ -115,9 +127,9 @@ namespace Sarand.Net.Standard.Base.Security
//-------------------------------------------------------------------
// Utilities.
- public bool IsMemberOfSecurityGroup (SysId secGroupId)
+ public bool IsMemberOfSecurityGroup(SysId secGroupId)
{
- return securityGroups.Exists(item => item.GroupId.Equals(secGroupId));
+ return securityGroups.Exists(item => item.Id.Equals(secGroupId));
}
//-------------------------------------------------------------------
@@ -125,14 +137,14 @@ namespace Sarand.Net.Standard.Base.Security
/// Retrieve the list of data items for which the user is explicitly granted the
/// specified security right, or where the right is explicitly denied if the flag is false.
///
- public List GetDataItemsForRight (String rightCode, bool granted = true)
+ public List GetDataItemsForRight(String rightCode, bool granted = true)
{
return securityGroups.GetDataItemsForRight(rightCode, granted);
}
//-------------------------------------------------------------------
/// Is the Security Right code granted access for the Data item (if specified).
- public bool IsSecurityRightGranted (String rightCode, SysId dataItemId = null)
+ public bool IsSecurityRightGranted(String rightCode, SysId dataItemId = null)
{
if (SystemAdmin) return true;
return (securityGroups.IsSecurityRightGranted(rightCode, dataItemId) || securityRights.IsSecurityRightGranted(rightCode, dataItemId));
@@ -140,7 +152,7 @@ namespace Sarand.Net.Standard.Base.Security
//-------------------------------------------------------------------
/// Is the Security Right code denined access for the Data item (if specified).
- public bool IsSecurityRightDenied (String rightCode, SysId dataItemId = null)
+ public bool IsSecurityRightDenied(String rightCode, SysId dataItemId = null)
{
if (SystemAdmin) return false;
return (securityGroups.IsSecurityRightDenied(rightCode, dataItemId) || securityRights.IsSecurityRightDenied(rightCode, dataItemId));
@@ -156,22 +168,22 @@ namespace Sarand.Net.Standard.Base.Security
/// Retrieve the list of data items for which the user is explicitly granted the
/// specified security right, or where the right is explicitly denied if the flag is false.
///
- public static List GetDataItemsForRight (this List groups, String rightCode, bool granted = true)
+ public static List GetDataItemsForRight(this List groups, String rightCode, bool granted = true)
{
- List dataItemIds = new List();
+ HashSet dataItemIds = new HashSet();
foreach (var securityGroup in groups)
- dataItemIds.AddIds(securityGroup.rights.GetDataItemsForRight(rightCode,granted));
- return dataItemIds;
+ dataItemIds.AddIds(securityGroup.GetDataItemsForRight(rightCode, granted));
+ return new List(dataItemIds);
}
/// Is the Security Right code granted access for the Data item (if specified).
- public static bool IsSecurityRightGranted (this List groups, String rightCode, SysId dataItemId = null)
+ public static bool IsSecurityRightGranted(this List groups, String rightCode, SysId dataItemId = null)
{
- return groups.Exists(item => item.rights.IsSecurityRightGranted(rightCode, dataItemId));
+ return groups.Exists(group => group.IsSecurityRightGranted(rightCode, dataItemId));
}
/// Is the Security Right code denined access for the Data item (if specified).
- public static bool IsSecurityRightDenied (this List groups, String rightCode, SysId dataItemId = null)
+ public static bool IsSecurityRightDenied(this List groups, String rightCode, SysId dataItemId = null)
{
- return groups.Exists(item => item.rights.IsSecurityRightDenied(rightCode, dataItemId));
+ return groups.Exists(group => group.IsSecurityRightDenied(rightCode, dataItemId));
}
}
@@ -182,17 +194,17 @@ namespace Sarand.Net.Standard.Base.Security
/// Retrieve the list of data items for which the user is explicitly granted the
/// specified security right, or where the right is explicitly denied if the flag is false.
///
- public static List GetDataItemsForRight (this List rights, String rightCode, bool granted = true)
+ public static List GetDataItemsForRight(this List rights, String rightCode, bool granted = true)
{
- List dataItemIds = new List();
- foreach (var securityRight in rights.FindAll(x => x.RightCode.EqualsCI(rightCode) && x.Granted == granted))
+ HashSet dataItemIds = new HashSet();
+ foreach (var securityRight in rights.FindAll(x => x.Code.EqualsCI(rightCode) && x.Granted == granted))
dataItemIds.AddId(securityRight.DataItemId);
- return dataItemIds;
+ return new List(dataItemIds);
}
/// Is the Security Right code granted access for the Data item (if specified).
- public static bool IsSecurityRightGranted (this List rights, String rightCode, SysId dataItemId = null)
+ public static bool IsSecurityRightGranted(this List rights, String rightCode, SysId dataItemId = null)
{
- foreach (var userSecurityRight in rights.FindAll(item => item.RightCode.EqualsCI(rightCode)))
+ foreach (var userSecurityRight in rights.FindAll(item => item.Code.EqualsCI(rightCode)))
{
if (SysId.ToInt(dataItemId) != SysId.ToInt(userSecurityRight.DataItemId)) continue;
return userSecurityRight.Granted;
@@ -200,9 +212,9 @@ namespace Sarand.Net.Standard.Base.Security
return false;
}
/// Is the Security Right code denined access for the Data item (if specified).
- public static bool IsSecurityRightDenied (this List rights, String rightCode, SysId dataItemId = null)
+ public static bool IsSecurityRightDenied(this List rights, String rightCode, SysId dataItemId = null)
{
- foreach (var userSecurityRight in rights.FindAll(item => item.RightCode.EqualsCI(rightCode)))
+ foreach (var userSecurityRight in rights.FindAll(item => item.Code.EqualsCI(rightCode)))
{
if (SysId.ToInt(dataItemId) != SysId.ToInt(userSecurityRight.DataItemId)) continue;
return !userSecurityRight.Granted;
diff --git a/SacsStandardBase/Base/Utils/StringUtil.cs b/SacsStandardBase/Base/Utils/StringUtil.cs
index 60e6163..9c15cad 100644
--- a/SacsStandardBase/Base/Utils/StringUtil.cs
+++ b/SacsStandardBase/Base/Utils/StringUtil.cs
@@ -474,14 +474,16 @@ namespace Sarand.Net.Standard.Base.Utils
}
public static long ToLong(this string value, long defaultValue = 0)
{
- if (String.IsNullOrEmpty(value)) return defaultValue;
- try
+ if (!String.IsNullOrEmpty(value))
{
- Double returnValue = defaultValue;
- if (Double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out returnValue))
- return (Int64)returnValue;
+ try
+ {
+ Double returnValue = defaultValue;
+ if (Double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out returnValue))
+ return (Int64)returnValue;
+ }
+ catch (Exception) { }
}
- catch (Exception) { }
return defaultValue;
}
public static short ToShort(Object value, short defaultValue = 0)
@@ -494,22 +496,17 @@ namespace Sarand.Net.Standard.Base.Utils
}
public static long ToLong(Object value, long defaultValue = 0)
{
- if (value == null) return defaultValue;
- try
+ if (value != null)
{
- return ToLong(value.ToString());
+ try
+ {
+ return ToLong(value.ToString(), defaultValue);
+ }
+ catch (Exception) { }
}
- catch (Exception) { }
return defaultValue;
}
- //---------------------------------------------------------------------------
- // SysId.
- public static SysId ToSysId(this String value)
- {
- return new SysId(StringUtil.ToLong(value));
- }
-
//---------------------------------------------------------------------------
// Hex values to integer.
/// Convert hex character to integer value.
diff --git a/SacsStandardBase/SacsStandardBase.csproj b/SacsStandardBase/SacsStandardBase.csproj
index c283e94..c0a6bbc 100644
--- a/SacsStandardBase/SacsStandardBase.csproj
+++ b/SacsStandardBase/SacsStandardBase.csproj
@@ -7,11 +7,11 @@
-
+
-
+
diff --git a/SacsStandardDbas/Dbas/Base/SacsDatabase.cs b/SacsStandardDbas/Dbas/Base/SacsDatabase.cs
index 9f1b1ea..59620c1 100644
--- a/SacsStandardDbas/Dbas/Base/SacsDatabase.cs
+++ b/SacsStandardDbas/Dbas/Base/SacsDatabase.cs
@@ -61,6 +61,83 @@ namespace Sarand.Net.Standard.Dbas.Base
public abstract int GetNextIdFromTable(string objectName, string idColumn = "Id");
public abstract bool SetMinNextId(String objectName, SysId id, DbUpdateInfo dbUpdateInfo, bool databaseTable = true, String idColumn = "Id", bool force = false);
+ //-------------------------------------------------------------------
+ // Password utilities.
+ //-------------------------------------------------------------------
+ ///
+ /// Generate password hash using the specified method.
+ /// - Returns hex notation as a string.
+ ///
+ ///
+ /// String of hex digits corresponding to encrypted password.
+ public String EncodePassword_Hex(String password, ISacsDatabase.PasswordHashMethod method = ISacsDatabase.PasswordHashMethod.MsSql)
+ {
+ ClearErrorState();
+ if (method == ISacsDatabase.PasswordHashMethod.MsSql)
+ {
+ if (DbmsType == DbmsType.MsSql)
+ {
+ try
+ {
+ String colAlias = "DataValue";
+ String query = $"Select {colAlias}=Convert(VarChar(2000),PwdEncrypt('{DbQuery.FormatForCondition(password)}'),2);";
+ using (DbResultSet dbResultSet = DbResultSet_DataReader.ExecuteQuery(this, query))
+ {
+ if (dbResultSet.NextRecord())
+ return dbResultSet.GetRecordValues().GetValue(colAlias).ToString();
+ else if (dbResultSet.HasErrorState())
+ SetErrorState(dbResultSet.ErrorStateMessage);
+ }
+ }
+ catch (Exception exc)
+ {
+ SaLogger.Error($"{SysUtil.Fn} {ExceptionUtil.GetLogMessage(exc, "hashing password")}", true);
+ SetErrorState(exc.Message);
+ }
+ }
+ else SaLogger.Warn($"{SysUtil.Fn} Unable to encode password by method 'SQL'. Database is '{DbmsType}'.");
+ }
+ else SaLogger.Warn($"{SysUtil.Fn} Unable to encode password. Unrecognised method: '{method}'.");
+ return "";
+ }
+
+ ///
+ /// Compare the password to the encrypted hash using the specified method.
+ ///
+ ///
+ ///
+ /// True if the password matches the encrypted hash value.
+ public bool ComparePassword_Hex(String password, String passwordHashHex, ISacsDatabase.PasswordHashMethod method = ISacsDatabase.PasswordHashMethod.MsSql)
+ {
+ ClearErrorState();
+ if (method == ISacsDatabase.PasswordHashMethod.MsSql)
+ {
+ if (DbmsType == DbmsType.MsSql)
+ {
+ try
+ {
+ String colAlias = "PwdCompare";
+ String query = $"Select {colAlias}=PwdCompare('{DbQuery.FormatForCondition(password)}', Convert(VarBinary(1000),'{DbQuery.FormatForCondition(passwordHashHex)}',2));";
+ using (DbResultSet dbResultSet = DbResultSet_DataReader.ExecuteQuery(this, query))
+ {
+ if (dbResultSet.NextRecord())
+ return StringUtil.ToBool(dbResultSet.GetRecordValues().GetValue(colAlias).ToString());
+ else if (dbResultSet.HasErrorState())
+ SetErrorState(dbResultSet.ErrorStateMessage);
+ }
+ }
+ catch (Exception exc)
+ {
+ SaLogger.Error($"{SysUtil.Fn} {ExceptionUtil.GetLogMessage(exc, "comparing password")}", true);
+ SetErrorState(exc.Message);
+ }
+ }
+ else SaLogger.Warn($"{SysUtil.Fn} Unable to compare password by method 'SQL'. Database is '{DbmsType}'.");
+ }
+ else SaLogger.Warn($"{SysUtil.Fn} Unable to compare password. Unrecognised method: '{method}'.");
+ return false;
+ }
+
//-------------------------------------------------------------------
// O D B C D r i v e r s
//-------------------------------------------------------------------
@@ -184,7 +261,7 @@ namespace Sarand.Net.Standard.Dbas.Base
}
return "";
}
- public abstract IDbDataTable ExecuteQuery(String query);
+ public abstract DbResultSet ExecuteQuery(String query);
public abstract int ExecuteNonQuery(String query);
public abstract int ExecuteInsert(String tableName, List columnNameValues);
public abstract int ExecuteUpdate(String tableName, List columnNameValues, String filter);
diff --git a/SacsStandardDbas/Dbas/Base/SacsDatabaseConsole.cs b/SacsStandardDbas/Dbas/Base/SacsDatabaseConsole.cs
index f4e43ed..6e25857 100644
--- a/SacsStandardDbas/Dbas/Base/SacsDatabaseConsole.cs
+++ b/SacsStandardDbas/Dbas/Base/SacsDatabaseConsole.cs
@@ -17,9 +17,9 @@ namespace Sarand.Net.Standard.Dbas.Base
// Database configuration
public class OdbcConfig
{
- public DbmsType dbms = DbmsType.General;
- public String connectionString; // Raw connection string.
- public String location, user, pword; // Application properties.
+ public DbmsType Dbms = DbmsType.General;
+ public String ConnectionString; // Raw connection string.
+ public String Location, User, Password; // Connection properties.
/// Database name populated when connection string is generated if not done previously.
public String DatabaseName { get; set; }
}
@@ -42,9 +42,9 @@ namespace Sarand.Net.Standard.Dbas.Base
//-------------------------------------------------------------------
public static DbmsType GetDbmsType(OdbcConfig config)
{
- if (config.dbms == DbmsType.MsSql || config.location.Left(6).EqualsCI("MsSql:"))
+ if (config.Dbms == DbmsType.MsSql || config.Location.Left(6).EqualsCI("MsSql:"))
return DbmsType.MsSql;
- return config.dbms;
+ return config.Dbms;
}
public static String GenerateConnectionString(OdbcConfig config, bool dbmsSpecificConnectionString = false)
{
@@ -58,7 +58,7 @@ namespace Sarand.Net.Standard.Dbas.Base
// MsSql:Server:Port\Instance.Database
dbms = DbmsType.MsSql;
String sqlDriver = OdbcUtil.GetOdbcSqlDriverName();
- String sqlLocation = config.location.Left(6).EqualsCI("MsSql:") ? config.location.Substring(6) : config.location;
+ String sqlLocation = config.Location.Left(6).EqualsCI("MsSql:") ? config.Location.Substring(6) : config.Location;
String sqlServer = "."; /* Assume local host */
String sqlInstance = "";
String sqlPort = "";
@@ -99,17 +99,17 @@ namespace Sarand.Net.Standard.Dbas.Base
// WsId=;
// Server=[protocol:]Server[,port][\instancename];
// Database=;
- // Trusted_Connection=;
+ // Trusted_Connection=; [or Integrated Security=SSPI;]
// UseProcForPrepare=2
connectionString = "Driver={" + sqlDriver + "};";
connectionString += "Server=" + sqlServer + ";";
connectionString += "Database=" + sqlDatabase + ";";
- if (!config.user.IsEmpty())
+ if (!config.User.IsEmpty())
{
- connectionString += "UID=" + config.user + ";";
- connectionString += "PWD=" + config.pword + ";";
+ connectionString += "UID=" + config.User + ";";
+ connectionString += "PWD=" + config.Password + ";";
}
- connectionString += "Trusted_Connection=" + (config.user.IsEmpty() ? "Yes" : "No") + ";";
+ connectionString += "Trusted_Connection=" + (config.User.IsEmpty() ? "Yes" : "No") + ";";
// Mar24 Added to avoid 'The certificate chain was issued by an authority that is not trusted'.
connectionString += "TrustServerCertificate=Yes;";
// Multiple Active Result Sets.
@@ -125,23 +125,23 @@ namespace Sarand.Net.Standard.Dbas.Base
connectionString = "";
connectionString += "Server=" + sqlServer + ";";
connectionString += "Database=" + sqlDatabase + ";";
- if (!config.user.IsEmpty())
+ if (!config.User.IsEmpty())
{
- connectionString += "User Id=" + config.user + ";";
- connectionString += "Password=" + config.pword + ";";
+ connectionString += "User Id=" + config.User + ";";
+ connectionString += "Password=" + config.Password + ";";
}
- connectionString += "Trusted_Connection=" + (config.user.IsEmpty() ? "Yes" : "No") + ";";
+ connectionString += "Trusted_Connection=" + (config.User.IsEmpty() ? "Yes" : "No") + ";";
// Mar24 Added to avoid 'The certificate chain was issued by an authority that is not trusted'.
connectionString += "TrustServerCertificate=Yes;";
}
// Populate configuration values if blank.
- if (config.dbms <= 0)
- config.dbms = dbms;
+ if (config.Dbms <= 0)
+ config.Dbms = dbms;
if (StringUtil.IsEmpty(config.DatabaseName))
config.DatabaseName = sqlDatabase;
- SaLogger.Info($"{SysUtil.Fn} Driver: " + sqlDriver + ". Server: " + sqlServer + ". Database: " + sqlDatabase + ". Connection: " + connectionString);
+ //SaLogger.Debug($"{SysUtil.Fn} Driver: " + sqlDriver + ". Server: " + sqlServer + ". Database: " + sqlDatabase + ". Connection: " + connectionString);
}
return connectionString;
}
@@ -152,17 +152,17 @@ namespace Sarand.Net.Standard.Dbas.Base
public static SacsDatabase OpenOdbcDatabase(OdbcConfig config)
{
// Populate configuration.
- config.dbms = GetDbmsType(config);
+ config.Dbms = GetDbmsType(config);
// Connection strings.
- String connectionString = config.connectionString;
+ String connectionString = config.ConnectionString;
if (StringUtil.IsEmpty(connectionString))
connectionString = GenerateConnectionString(config);
String sqlConnectionString = GenerateConnectionString(config, true);
// Open database.
- DbGlobalDbms.Type = config.dbms;
- SacsDatabaseOdbc database = new SacsDatabaseOdbc(config.dbms, config.DatabaseName, connectionString);
+ DbGlobalDbms.Type = config.Dbms;
+ SacsDatabaseOdbc database = new SacsDatabaseOdbc(config.Dbms, config.DatabaseName, connectionString);
database.SelectLockMode = SelectLockMode.ReadUncommitted;
database.SqlConnectionString = sqlConnectionString;
return database;
diff --git a/SacsStandardDbas/Dbas/CodeTypes/SaCodeTypeDbDfnGenerator.cs b/SacsStandardDbas/Dbas/CodeTypes/SaCodeTypeDbDfnGenerator.cs
index 09708bd..65f669d 100644
--- a/SacsStandardDbas/Dbas/CodeTypes/SaCodeTypeDbDfnGenerator.cs
+++ b/SacsStandardDbas/Dbas/CodeTypes/SaCodeTypeDbDfnGenerator.cs
@@ -29,7 +29,7 @@ namespace Sarand.Net.Standard.Dbas.CodeType
// Open database.
// NB Must be ODBC connection - especially to retrieve index columns.
SacsDatabaseConsole.OdbcConfig config = new SacsDatabaseConsole.OdbcConfig();
- config.connectionString = connectionString;
+ config.ConnectionString = connectionString;
SacsDatabase database = SacsDatabaseConsole.OpenOdbcDatabase(config);
// Generate database definition.
diff --git a/SacsStandardDbas/Dbas/Data/DbDataTable.cs b/SacsStandardDbas/Dbas/Data/DbDataTable.cs
deleted file mode 100644
index 1900419..0000000
--- a/SacsStandardDbas/Dbas/Data/DbDataTable.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System.Data;
-using Sarand.Net.Standard.Base.Dbas;
-
-namespace Sarand.Net.Standard.Dbas.Data
-{
- //=======================================================================
- ///
- /// Wrapper for System.Data.DataTable
- ///
- public class DbDataTable : IDbDataTable
- {
- //-------------------------------------------------------------------
- // Data members.
- private DataTable dataTable;
-
- //-------------------------------------------------------------------
- // Construction.
- public DbDataTable (DataTable dataTable)
- {
- this.dataTable = dataTable;
- }
-
- //-------------------------------------------------------------------
-
- //-------------------------------------------------------------------
- }
- //=======================================================================
-}
diff --git a/SacsStandardDbas/Dbas/Data/SacsDatabaseOdbc.cs b/SacsStandardDbas/Dbas/Data/SacsDatabaseOdbc.cs
index 955fc2d..9799229 100644
--- a/SacsStandardDbas/Dbas/Data/SacsDatabaseOdbc.cs
+++ b/SacsStandardDbas/Dbas/Data/SacsDatabaseOdbc.cs
@@ -171,29 +171,20 @@ namespace Sarand.Net.Standard.Dbas.Data
// Q u e r y D a t a b a s e
//-------------------------------------------------------------------
// Query records.
- public override IDbDataTable ExecuteQuery(String query)
+ public override DbResultSet ExecuteQuery(String query)
{
ClearErrorState();
- DataTable dataTable = null;
Log(SysUtil.Fn, "Query: " + query, SaMessageLevel.Debug);
try
{
- using (DbConnection dbConnection = CreateConnection())
- using (var dbCommand = dbConnection.CreateCommand())
- {
- dbConnection.Open();
- dbCommand.CommandType = System.Data.CommandType.Text;
- dbCommand.CommandText = query;
- dataTable = new DataTable();
- dataTable.Load(dbCommand.ExecuteReader());
- }
+ return DbResultSet_DataReader.ExecuteQuery(this, query);
}
catch (Exception exc)
{
SaLogger.Error($"{SysUtil.Fn} {ExceptionUtil.GetLogMessage(exc)}\nQuery:\n\t{String.Join("\n\t", query.ReplaceAll("\n\r", "\n").Split("\n"))}", true);
SetErrorState(exc.Message);
}
- return new DbDataTable(dataTable);
+ return null;
}
//-------------------------------------------------------------------
/// Execute a non-query statement and return the row count.
diff --git a/SacsStandardDbas/Dbas/Interfaces/SaInterfaceDbDfnGenerator.cs b/SacsStandardDbas/Dbas/Interfaces/SaInterfaceDbDfnGenerator.cs
index 25e757e..5c022da 100644
--- a/SacsStandardDbas/Dbas/Interfaces/SaInterfaceDbDfnGenerator.cs
+++ b/SacsStandardDbas/Dbas/Interfaces/SaInterfaceDbDfnGenerator.cs
@@ -32,7 +32,7 @@ namespace Sarand.Net.Standard.Dbas.Interface
// Open database.
// NB Must be ODBC connection - especially to retrieve index columns.
SacsDatabaseConsole.OdbcConfig config = new SacsDatabaseConsole.OdbcConfig();
- config.connectionString = connectionString;
+ config.ConnectionString = connectionString;
SacsDatabase database = SacsDatabaseConsole.OpenOdbcDatabase(config);
// Generate database definition.
diff --git a/SacsStandardDbas/Dbas/ItemData/SaItemDataDbDfnGenerator.cs b/SacsStandardDbas/Dbas/ItemData/SaItemDataDbDfnGenerator.cs
index 7296233..20e4bd1 100644
--- a/SacsStandardDbas/Dbas/ItemData/SaItemDataDbDfnGenerator.cs
+++ b/SacsStandardDbas/Dbas/ItemData/SaItemDataDbDfnGenerator.cs
@@ -31,7 +31,7 @@ namespace Sarand.Net.Standard.Dbas.ItemData
// Open database.
// NB Must be ODBC connection - especially to retrieve index columns.
SacsDatabaseConsole.OdbcConfig config = new SacsDatabaseConsole.OdbcConfig();
- config.connectionString = connectionString;
+ config.ConnectionString = connectionString;
SacsDatabase database = SacsDatabaseConsole.OpenOdbcDatabase(config);
// Generate database definition.
diff --git a/SacsStandardDbas/Dbas/ItemDocs/SaItemDocsDbDfnGenerator.cs b/SacsStandardDbas/Dbas/ItemDocs/SaItemDocsDbDfnGenerator.cs
index 667ab36..2ad09ba 100644
--- a/SacsStandardDbas/Dbas/ItemDocs/SaItemDocsDbDfnGenerator.cs
+++ b/SacsStandardDbas/Dbas/ItemDocs/SaItemDocsDbDfnGenerator.cs
@@ -35,7 +35,7 @@ namespace Sarand.Net.Standard.Dbas.ItemDocs
// Open database.
// NB Must be ODBC connection - especially to retrieve index columns.
SacsDatabaseConsole.OdbcConfig config = new SacsDatabaseConsole.OdbcConfig();
- config.connectionString = connectionString;
+ config.ConnectionString = connectionString;
SacsDatabase database = SacsDatabaseConsole.OpenOdbcDatabase(config);
// Generate database definition.
diff --git a/SacsStandardDbas/Dbas/ItemOptions/SaItemOptionsDbDfnGenerator.cs b/SacsStandardDbas/Dbas/ItemOptions/SaItemOptionsDbDfnGenerator.cs
index 51d3a36..e5e3612 100644
--- a/SacsStandardDbas/Dbas/ItemOptions/SaItemOptionsDbDfnGenerator.cs
+++ b/SacsStandardDbas/Dbas/ItemOptions/SaItemOptionsDbDfnGenerator.cs
@@ -31,7 +31,7 @@ namespace Sarand.Net.Standard.Dbas.ItemOptions
// Open database.
// NB Must be ODBC connection - especially to retrieve index columns.
SacsDatabaseConsole.OdbcConfig config = new SacsDatabaseConsole.OdbcConfig();
- config.connectionString = connectionString;
+ config.ConnectionString = connectionString;
SacsDatabase database = SacsDatabaseConsole.OpenOdbcDatabase(config);
// Generate database definition.
diff --git a/SacsStandardDbas/Dbas/ReferenceData/SaReferenceDataDbDfnGenerator.cs b/SacsStandardDbas/Dbas/ReferenceData/SaReferenceDataDbDfnGenerator.cs
index a024e5b..ce9c93f 100644
--- a/SacsStandardDbas/Dbas/ReferenceData/SaReferenceDataDbDfnGenerator.cs
+++ b/SacsStandardDbas/Dbas/ReferenceData/SaReferenceDataDbDfnGenerator.cs
@@ -31,7 +31,7 @@ namespace Sarand.Net.Standard.Dbas.ReferenceData
// Open database.
// NB Must be ODBC connection - especially to retrieve index columns.
SacsDatabaseConsole.OdbcConfig config = new SacsDatabaseConsole.OdbcConfig();
- config.connectionString = connectionString;
+ config.ConnectionString = connectionString;
SacsDatabase database = SacsDatabaseConsole.OpenOdbcDatabase(config);
// Generate database definition.
diff --git a/SacsStandardDbas/Dbas/Security/SaSecurityConsole_Dbas.cs b/SacsStandardDbas/Dbas/Security/SaSecurityConsole_Dbas.cs
index d358b58..e25b3ae 100644
--- a/SacsStandardDbas/Dbas/Security/SaSecurityConsole_Dbas.cs
+++ b/SacsStandardDbas/Dbas/Security/SaSecurityConsole_Dbas.cs
@@ -73,6 +73,28 @@ namespace Sarand.Net.Standard.Dbas.Security
}
//-------------------------------------------------------------------
+ // Password utilities.
+ //-------------------------------------------------------------------
+
+ /// Store the password against against the user.
+ public override bool SetPassword(SaSecurityItem securityItemUser, String password)
+ {
+ return securityMgr.SetPassword(securityItemUser, password);
+ }
+
+ /// Does the password match that currently defined against the user.
+ public override bool PasswordMatches(SaSecurityItem securityItemUser, String password)
+ {
+ return securityMgr.PasswordMatches(securityItemUser, password);
+ }
+
+ /// Is the password currently defined against the user blank.
+ public override bool PasswordIsBlank(SaSecurityItem securityItemUser)
+ {
+ return securityMgr.PasswordIsBlank(securityItemUser);
+ }
+
+ /// Change Password form - desktop only.
public override bool ShowChangePasswordForm(DbUpdateInfo dbUpdateInfo)
{
ClearErrorState();
@@ -112,16 +134,16 @@ namespace Sarand.Net.Standard.Dbas.Security
if (!HasErrorState()) PopulateSuperGroup(dbUpdateInfo);
// Create the 'admin' user.
if (!HasErrorState()) PopulateAdminUser(dbUpdateInfo);
- return !HasErrorState();
+ return OK;
}
private bool PopulateSuperGroup(DbUpdateInfo dbUpdateInfo)
{
ClearErrorState();
- SaSecurityItem superGroup = securityMgr.GetSecurityItemByTypeCode(SaSecurity.ItemType.Group, GroupSuperCode);
+ SaSecurityItem superGroup = securityMgr.GetSecurityItemByTypeCode(SaSecurity.ItemType.Group, GroupCode_Super);
if (superGroup == null)
{
superGroup = securityMgr.CreateSecurityItem(SaSecurity.ItemType.Group);
- superGroup.Code = GroupSuperCode;
+ superGroup.Code = GroupCode_Super;
superGroup.Description = "Superuser";
if (!securityMgr.InsertSecurityItem(superGroup, dbUpdateInfo))
return SetErrorState(securityMgr.ErrorStateMessage);
@@ -143,29 +165,29 @@ namespace Sarand.Net.Standard.Dbas.Security
}
}
}
- return !HasErrorState();
+ return OK;
}
private bool PopulateAdminUser(DbUpdateInfo dbUpdateInfo)
{
ClearErrorState();
SaSecurityItem user = null;
- if (!securityMgr.SecurityItemExistsByTypeCode(SaSecurity.ItemType.User, AdminUserCode))
+ if (!securityMgr.SecurityItemExistsByTypeCode(SaSecurity.ItemType.User, UserCode_Admin))
{
// Create the admin user.
user = securityMgr.CreateSecurityItem(SaSecurity.ItemType.User);
- user.Code = AdminUserCode;
+ user.Code = UserCode_Admin;
user.Description = "";
user.Location = "";
- user.PasswordEncrypted = SaSecurityItem.EncryptPassword(AdminUserCode);
+ securityMgr.SetPassword(user, UserCode_Admin);
if (!securityMgr.InsertSecurityItem(user, dbUpdateInfo))
return SetErrorState(securityMgr.ErrorStateMessage);
}
// Retrieve the user (even if just created).
- user = securityMgr.GetSecurityItemByTypeCode(SaSecurity.ItemType.User, AdminUserCode);
+ user = securityMgr.GetSecurityItemByTypeCode(SaSecurity.ItemType.User, UserCode_Admin);
if (user != null)
{
// Give this user superuser rights.
- SaSecurityItem superGroup = securityMgr.GetSecurityItemByTypeCode(SaSecurity.ItemType.Group, GroupSuperCode);
+ SaSecurityItem superGroup = securityMgr.GetSecurityItemByTypeCode(SaSecurity.ItemType.Group, GroupCode_Super);
if (superGroup != null)
{
if (!securityMgr.SecurityItemHasLinksWith(user.Id, superGroup.Id))
@@ -176,7 +198,7 @@ namespace Sarand.Net.Standard.Dbas.Security
}
}
}
- return !HasErrorState();
+ return OK;
}
//-------------------------------------------------------------------
@@ -234,7 +256,7 @@ namespace Sarand.Net.Standard.Dbas.Security
}
OnLogin(secItem != null ? secItem.Id : null);
- return !HasErrorState();
+ return OK;
}
//-------------------------------------------------------------------
@@ -534,19 +556,35 @@ namespace Sarand.Net.Standard.Dbas.Security
if (!securityMgr.InsertSecurityItem(secItem, dbUpdateInfo))
return SetErrorState(securityMgr.ErrorStateMessage);
- return !HasErrorState();
+ return OK;
}
public override bool AssignUserToGroup(string userCode, string groupCode, DbUpdateInfo dbUpdateInfo)
{
ClearErrorState();
- throw new NotImplementedException();
+ // Validate environment.
+ if (securityMgr == null) return SetErrorState("security manager is not available");
+ if (!securityMgr.DatabaseIsValid) return SetErrorState("database has an invalid security profile");
+ // User security item.
+ SaSecurityItem securityItemUser = securityMgr.GetSecurityItemByTypeCode(SaSecurity.ItemType.User, userCode);
+ if (securityItemUser == null) return SetErrorState(("user does not exist"));
+ // Group security item.
+ SysId securityGroupId = GetIdForItemCode(SaSecurity.ItemType.Group, groupCode);
+ if (!SysId.IsValid(securityGroupId)) return SetErrorState(("invalid group code"));
+ if (!ItemsAreLinked(securityItemUser.Id, securityGroupId))
+ {
+ SaSecurityLink securityLinkUserGroup = securityMgr.CreateSecurityLink(securityItemUser.Id, securityGroupId, new SysId());
+ if (securityLinkUserGroup == null) return SetErrorState($"failed to create user-group ({securityMgr.ErrorStateMessage})");
+ if (!securityMgr.InsertSecurityLink(securityLinkUserGroup, dbUpdateInfo))
+ return SetErrorState($"failed to add user to group ({securityMgr.ErrorStateMessage})");
+ }
+ return OK;
}
public override bool UpdateSecurityItem(SaSecurityItem securityItem, DbUpdateInfo dbUpdateInfo)
{
ClearErrorState();
if (!securityMgr.UpdateSecurityItem(securityItem, dbUpdateInfo))
return SetErrorState(securityMgr.ErrorStateMessage);
- return !HasErrorState();
+ return OK;
}
//-------------------------------------------------------------------
diff --git a/SacsStandardDbas/Dbas/Security/SaSecurityDbDfnGenerator.cs b/SacsStandardDbas/Dbas/Security/SaSecurityDbDfnGenerator.cs
index 43603f1..e0a9b7c 100644
--- a/SacsStandardDbas/Dbas/Security/SaSecurityDbDfnGenerator.cs
+++ b/SacsStandardDbas/Dbas/Security/SaSecurityDbDfnGenerator.cs
@@ -31,7 +31,7 @@ namespace Sarand.Net.Standard.Dbas.Security
// Open database.
// NB Must be ODBC connection - especially to retrieve index columns.
SacsDatabaseConsole.OdbcConfig config = new SacsDatabaseConsole.OdbcConfig();
- config.connectionString = connectionString;
+ config.ConnectionString = connectionString;
SacsDatabase database = SacsDatabaseConsole.OpenOdbcDatabase(config);
// Generate database definition.
diff --git a/SacsStandardDbas/Dbas/Security/SaSecurityMgr_Dbas-SecurityItem.cs b/SacsStandardDbas/Dbas/Security/SaSecurityMgr_Dbas-SecurityItem.cs
index 1065248..6edb43b 100644
--- a/SacsStandardDbas/Dbas/Security/SaSecurityMgr_Dbas-SecurityItem.cs
+++ b/SacsStandardDbas/Dbas/Security/SaSecurityMgr_Dbas-SecurityItem.cs
@@ -278,7 +278,9 @@ namespace Sarand.Net.Standard.Dbas.Security
dbSecurityItem._Code = securityItem.Code;
dbSecurityItem._Description = securityItem.Description;
dbSecurityItem._Location = securityItem.Location;
+#pragma warning disable CS0618 // Deprecated property
dbSecurityItem._EncPword = securityItem.PasswordEncrypted;
+#pragma warning restore CS0618 // Deprecated property
dbSecurityItem._PwordSalt = securityItem.PasswordSalt;
dbSecurityItem._PwordHash = securityItem.PasswordHash;
dbSecurityItem._LastLogin = securityItem.LastLogin;
@@ -304,7 +306,9 @@ namespace Sarand.Net.Standard.Dbas.Security
securityItem.EmailAddress = dbSecurityItem._EmailAddress;
securityItem.Description = dbSecurityItem._Description;
securityItem.Location = dbSecurityItem._Location;
+#pragma warning disable CS0618 // Deprecated property
securityItem.PasswordEncrypted = dbSecurityItem._EncPword;
+#pragma warning restore CS0618 // Deprecated property
securityItem.PasswordSalt = dbSecurityItem._PwordSalt;
securityItem.PasswordHash = dbSecurityItem._PwordHash;
securityItem.LastLogin = dbSecurityItem._LastLogin;
diff --git a/SacsStandardDbas/Dbas/Security/SaSecurityMgr_Dbas.cs b/SacsStandardDbas/Dbas/Security/SaSecurityMgr_Dbas.cs
index a6fec1f..6ca2266 100644
--- a/SacsStandardDbas/Dbas/Security/SaSecurityMgr_Dbas.cs
+++ b/SacsStandardDbas/Dbas/Security/SaSecurityMgr_Dbas.cs
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Text;
+using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Dbas;
using Sarand.Net.Standard.Base.Security;
using Sarand.Net.Standard.Dbas.Data;
@@ -15,7 +17,7 @@ namespace Sarand.Net.Standard.Dbas.Security
//-------------------------------------------------------------------
// Construction.
- internal SaSecurityMgr_Dbas (SaSecurityConsole_Dbas securityConsole) : base()
+ internal SaSecurityMgr_Dbas(SaSecurityConsole_Dbas securityConsole) : base()
{
SecurityConsole = securityConsole;
DbInfo = new DbDataItem.DatabaseInfo(securityConsole.Database);
@@ -31,15 +33,109 @@ namespace Sarand.Net.Standard.Dbas.Security
public override bool DatabaseIsValid { get { return (Database != null && Database.GetTableNames().Contains(TableName_SecItem) && Database.GetTableNames().Contains(TableName_SecLink)); } }
public override bool CanUpdateDatabase { get { return DatabaseIsValid; } }
- //-------------------------------------------------------------------
- // Utilities.
- public override bool ColumnExists (SaSecurityDbDfn.ColumnIdx columnIdx)
+ // Database utilities.
+ public override bool ColumnExists(SaSecurityDbDfn.ColumnIdx columnIdx)
{
String tableName = SaSecurityDbDfn.GetTableName(SaSecurityDbDfn.GetTableForColumn(columnIdx), false);
String columnName = SaSecurityDbDfn.GetColumnName(columnIdx, false);
return Database.ColumnExists(tableName, columnName);
}
+ //-------------------------------------------------------------------
+ // Password utilities.
+
+ public override bool PasswordIsBlank(SaSecurityItem securityItemUser)
+ {
+ if (securityItemUser == null) return false;
+ SaSecurity.PasswordMethod method = securityItemUser.GetPasswordMethod();
+ // MsSql method.
+ if (method == SaSecurity.PasswordMethod.MsSql)
+ {
+ //...
+ }
+ // Legacy.
+#pragma warning disable CS0618 // Deprecated property
+ return EncryptPassword_Legacy("").Equals(securityItemUser.PasswordEncrypted);
+#pragma warning restore CS0618 // Deprecated property
+ }
+
+ public override bool PasswordMatches(SaSecurityItem securityItemUser, String password)
+ {
+ if (securityItemUser == null) return false;
+ SaSecurity.PasswordMethod method = securityItemUser.GetPasswordMethod();
+ // MsSql method.
+ if (method == SaSecurity.PasswordMethod.MsSql)
+ {
+ //...
+ }
+ // Legacy.
+#pragma warning disable CS0618 // Deprecated property
+ return (EncryptPassword_Legacy(password).Equals(securityItemUser.PasswordEncrypted));
+#pragma warning restore CS0618 // Deprecated property
+ }
+
+ /// Store the password against against the user.
+ public override bool SetPassword(SaSecurityItem securityItemUser, String password)
+ {
+ return false;
+ }
+
+ internal static String EncryptPassword_Legacy(String password)
+ {
+ // We know this is not very water-tight, but it at least
+ // hides the contents of the password from prying eyes.
+ String toBeEncrypted = password;
+ // Password length goes in as first character:
+ toBeEncrypted = ByteToString((byte)(128 - password.Length)) + toBeEncrypted;
+ toBeEncrypted = string.Concat(toBeEncrypted.Reverse());
+ // Pad out to fixed length (minimum 16, multiples of 8):
+ int fixedLength = 16;
+ if (password.Length / 8 > 2) fixedLength = 8 * (int)(password.Length / 8);
+ while (toBeEncrypted.Length < fixedLength)
+ {
+ char charToAdd = (char)(password.Length > 0 ? password[(toBeEncrypted.Length % password.Length)] : 'A' + (toBeEncrypted.Length * 13) % 23);
+ if (toBeEncrypted.Length % 2 != 0)
+ toBeEncrypted += charToAdd;
+ else toBeEncrypted = charToAdd + toBeEncrypted;
+ }
+
+ // Now perform a simple algorythm on each character to hide its true value:
+ byte[] encryptedChars = new byte[toBeEncrypted.Length];
+ for (int i = 0; i < toBeEncrypted.Length; i++)
+ {
+ int iData = toBeEncrypted[i];
+ iData += 17 + i;
+ if (iData > 255) iData -= (255 + 32);
+ encryptedChars[i] = (byte)iData;
+ }
+ String result = Encoding_Ansi1252.GetString(encryptedChars);
+#if DEBUG
+ // Password: mgbgt
+ // To encrypt: tbmggtgbgm{btggm
+ // Encrypted: 133, 116, 128, 123, 124, 138, 126, 122, 128, 135, 150, 126, 145, 133, 134, 141
+ //Logger.Info(fn + "\n\tPassword: " + password + "\n\tTo encrypt: " + toBeEncrypted + "\n\tEncrypted: " + encryptedChars.Select(i => i.ToString()).ToList().Concat(", "));
+ //Logger.Debug(password + ": " + result);
+#endif
+ return result;
+ }
+ private static byte[] PasswordStringToBytes(String value)
+ {
+ byte[] values = new byte[value.Length];
+ for (int idx = 0; idx < value.Length; idx++)
+ {
+ char c = value[idx];
+ UInt32 ui = Convert.ToUInt32(c);
+ SaLogger.Info(idx + ". " + ui.ToString("x8"));
+ values[idx] = (byte)(c);
+ }
+ return values;
+ }
+ private static readonly Encoding Encoding_Ansi1252 = Encoding.GetEncoding(1252);
+ private static String ByteToString(byte value)
+ {
+ return Encoding_Ansi1252.GetString(new[] { value });
+ }
+
//-------------------------------------------------------------------
}
//=======================================================================
diff --git a/SacsStandardDbas/Dbas/UpdateLog/SaUpdateLogDbDfnGenerator.cs b/SacsStandardDbas/Dbas/UpdateLog/SaUpdateLogDbDfnGenerator.cs
index 63c436f..f5c83f9 100644
--- a/SacsStandardDbas/Dbas/UpdateLog/SaUpdateLogDbDfnGenerator.cs
+++ b/SacsStandardDbas/Dbas/UpdateLog/SaUpdateLogDbDfnGenerator.cs
@@ -31,7 +31,7 @@ namespace Sarand.Net.Standard.Dbas.UpdateLog
// Open database.
// NB Must be ODBC connection - especially to retrieve index columns.
SacsDatabaseConsole.OdbcConfig config = new SacsDatabaseConsole.OdbcConfig();
- config.connectionString = connectionString;
+ config.ConnectionString = connectionString;
SacsDatabase database = SacsDatabaseConsole.OpenOdbcDatabase(config);
// Generate database definition.
diff --git a/SacsStandardProc/SacsStandardProc.csproj b/SacsStandardProc/SacsStandardProc.csproj
index 252978d..c3edb22 100644
--- a/SacsStandardProc/SacsStandardProc.csproj
+++ b/SacsStandardProc/SacsStandardProc.csproj
@@ -10,7 +10,7 @@
-
+