Initial project state: .NET reference, design, Rust port (M0+M1), evidence
rust / build / test / clippy / fmt (push) Has been cancelled

Layout:
- src/                    .NET 10 x64 reference: MxNativeCodec, MxNativeClient,
                          MxAsbClient, probes, tests, harnesses. Executable spec.
- design/                 Architectural plan for the Rust port (M0–M6), error
                          model, protocol invariants, risks (R1–R16), adversarial
                          review log (review.md).
- rust/                   Rust workspace. M0 skeleton + M1 codec parity.
                          mxaccess-codec: 215 unit tests + 2 cross-implementation
                          parity tests (byte-identical against .NET reference).
                          Other crates are M0 stubs awaiting M2+.
- captures/               Frida + netsh + pcap evidence per CLAUDE.md
                          ("captures are evidence, not throwaway logs").
- analysis/               Decompiled C# (frida/proxy/decompiled-*),
                          Ghidra exports for native DLLs (`exports/` only —
                          working state at `projects/` and AVEVA's input
                          binaries at `input/` are gitignored).
- docs/                   Reverse-engineering reference docs.
- tools/                  Setup-LiveProbeEnv.ps1 (Infisical credential fetcher),
                          Compute-Crc.ps1 (.NET parity helper).
- .github/workflows/      Rust CI: fmt + build + test + clippy on Windows.
- LICENSE                 MIT (Joseph Doherty, 2026).

Verified:
- cargo test --workspace → 217 passed (215 unit + 2 .NET parity), 0 failed
- cargo clippy --workspace -- -D warnings → clean
- cargo fmt --all -- --check → clean
- cargo publish --dry-run -p mxaccess-codec → packages cleanly

Excluded from history (see .gitignore):
- **/bin, **/obj, **/target — build artifacts
- analysis/ghidra/projects/ — Ghidra working state (regenerable)
- analysis/ghidra/input/ — AVEVA proprietary DLLs (vendor IP)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-05-05 06:21:00 -04:00
parent 43733699b0
commit fe2a6db786
3849 changed files with 352975 additions and 0 deletions
@@ -0,0 +1,117 @@
using System;
using System.CodeDom.Compiler;
using System.ComponentModel;
using System.Diagnostics;
using System.Xml.Serialization;
namespace ArchestrAServices.ASBContract;
[Serializable]
[GeneratedCode("System.Xml", "4.0.30319.233")]
[DebuggerStepThrough]
[DesignerCategory("code")]
[XmlType(Namespace = "http://asb.contracts.data/20111111")]
public class ASBArchestrAResult
{
private bool successField;
private int resultCodeField;
private string locationField;
private string[] successMessagesField;
private string[] informationMessagesField;
private string[] errorMessagesField;
private NamedValue[] extensionsField;
public bool Success
{
get
{
return successField;
}
set
{
successField = value;
}
}
public int ResultCode
{
get
{
return resultCodeField;
}
set
{
resultCodeField = value;
}
}
public string Location
{
get
{
return locationField;
}
set
{
locationField = value;
}
}
[XmlElement("SuccessMessages")]
public string[] SuccessMessages
{
get
{
return successMessagesField;
}
set
{
successMessagesField = value;
}
}
[XmlElement("InformationMessages")]
public string[] InformationMessages
{
get
{
return informationMessagesField;
}
set
{
informationMessagesField = value;
}
}
[XmlElement("ErrorMessages")]
public string[] ErrorMessages
{
get
{
return errorMessagesField;
}
set
{
errorMessagesField = value;
}
}
[XmlElement("Extensions")]
public NamedValue[] Extensions
{
get
{
return extensionsField;
}
set
{
extensionsField = value;
}
}
}
@@ -0,0 +1,41 @@
namespace ArchestrAServices.ASBContract;
public enum ArchestrAError : ushort
{
Success = 0,
InvalidConnectionId = 1,
ApplicationAuthenticationError = 2,
UserAuthenticationError = 3,
UserAuthorizationError = 4,
NotSupportedOperation = 5,
MonitoredItemsNotFound = 6,
InvalidSubscriptionID = 7,
ItemAlreadyRegistered = 8,
ItemAlreadyDeletedOrDoesNotExist = 9,
InvalidMonitoredItems = 10,
OperationFailed = 11,
SpecificError = 12,
BadNoCommunication = 13,
Bad_NothingToDo = 14,
Bad_TooManyOperations = 15,
Bad_NodeIdInvalid = 16,
BrowseFailed = 17,
WriteFailed_BadOutOfRange = 18,
WriteFailed_BadTypeMismatch = 19,
WriteFailed_BadDimensionMismatch = 20,
WriteFailed_AccessDenied = 21,
WriteFailed_SecuredWrite = 22,
WriteFailed_VerifiedWrite = 23,
IndexOutOfRange = 24,
RequestTimedOut = 25,
DataTypeConversionNotSupported = 26,
ItemCannotBeRegistered_NoName = 27,
ItemCannotBeRegistered_NoId = 28,
ItemAlreadyBeingMonitored = 29,
SubscriptionIDAlreadyExist = 30,
OperationWouldBlock = 31,
PublishComplete = 32,
WriteFailed_UserNotHavingAccessRights = 33,
WriteFailed_VerifierNotHavingVerifyRights = 34,
Unknown = ushort.MaxValue
}
@@ -0,0 +1,155 @@
using System;
using System.CodeDom.Compiler;
using System.Diagnostics;
using System.Xml.Serialization;
namespace ArchestrAServices.ASBContract;
[Serializable]
[GeneratedCode("System.Xml", "4.0.30319.233")]
[DebuggerStepThrough]
[XmlType(Namespace = "http://asb.contracts.data/20111111")]
public struct ArchestrAResult
{
private bool successField;
private int resultCodeField;
private uint specificErrorCodeField;
private uint statusCodeField;
private string locationField;
private string[] successMessagesField;
private string[] informationMessagesField;
private string[] errorMessagesField;
private NamedValue[] extensionsField;
public bool Success
{
get
{
return successField;
}
set
{
successField = value;
}
}
public int ResultCode
{
get
{
return resultCodeField;
}
set
{
resultCodeField = value;
}
}
public int ErrorCode
{
get
{
return resultCodeField;
}
set
{
resultCodeField = value;
}
}
public uint SpecificErrorCode
{
get
{
return specificErrorCodeField;
}
set
{
specificErrorCodeField = value;
}
}
public uint Status
{
get
{
return statusCodeField;
}
set
{
statusCodeField = value;
}
}
public string Location
{
get
{
return locationField;
}
set
{
locationField = value;
}
}
[XmlElement("SuccessMessages")]
public string[] SuccessMessages
{
get
{
return successMessagesField;
}
set
{
successMessagesField = value;
}
}
[XmlElement("InformationMessages")]
public string[] InformationMessages
{
get
{
return informationMessagesField;
}
set
{
informationMessagesField = value;
}
}
[XmlElement("ErrorMessages")]
public string[] ErrorMessages
{
get
{
return errorMessagesField;
}
set
{
errorMessagesField = value;
}
}
[XmlElement("Extensions")]
public NamedValue[] Extensions
{
get
{
return extensionsField;
}
set
{
extensionsField = value;
}
}
}
@@ -0,0 +1,25 @@
using System.CodeDom.Compiler;
using System.ComponentModel;
using System.Diagnostics;
using System.ServiceModel;
namespace ArchestrAServices.ASBContract;
[DebuggerStepThrough]
[GeneratedCode("System.ServiceModel", "4.0.0.0")]
[EditorBrowsable(EditorBrowsableState.Advanced)]
[MessageContract(WrapperName = "AuthenticateMeRequest", WrapperNamespace = "http://asb.contracts.messages/20111111", IsWrapped = true)]
public class AuthenticateMe : ConnectedRequest
{
[MessageBodyMember(Namespace = "http://asb.contracts.messages/20111111", Order = 0)]
public AuthenticationData ConsumerAuthenticationData;
public AuthenticateMe()
{
}
public AuthenticateMe(AuthenticationData ConsumerAuthenticationData)
{
this.ConsumerAuthenticationData = ConsumerAuthenticationData;
}
}
@@ -0,0 +1,45 @@
using System;
using System.CodeDom.Compiler;
using System.ComponentModel;
using System.Diagnostics;
using System.Xml.Serialization;
namespace ArchestrAServices.ASBContract;
[Serializable]
[GeneratedCode("System.Xml", "4.0.30319.233")]
[DebuggerStepThrough]
[DesignerCategory("code")]
[XmlType(Namespace = "http://asb.contracts.data/20111111")]
public class AuthenticationData
{
private byte[] dataField;
private byte[] initializationVectorField;
[XmlElement(DataType = "base64Binary")]
public byte[] Data
{
get
{
return dataField;
}
set
{
dataField = value;
}
}
[XmlElement(DataType = "base64Binary")]
public byte[] InitializationVector
{
get
{
return initializationVectorField;
}
set
{
initializationVectorField = value;
}
}
}
@@ -0,0 +1,44 @@
namespace ArchestrAServices.ASBContract;
public static class AuthenticationDataExtensions
{
public static bool AreEqual(this AuthenticationData value, AuthenticationData other)
{
try
{
if (value != null && value.Data != null && other != null && other.Data != null)
{
return value.AreEqual(other.Data);
}
}
catch
{
}
return false;
}
public static bool AreEqual(this AuthenticationData value, byte[] expected)
{
bool result = false;
try
{
if (value != null && value.Data != null && expected != null && value.Data.Length == expected.Length)
{
result = true;
for (int i = 0; i < value.Data.Length; i++)
{
if (value.Data[i] != expected[i])
{
result = false;
break;
}
}
}
}
catch
{
result = false;
}
return result;
}
}
@@ -0,0 +1,30 @@
using System;
using System.CodeDom.Compiler;
using System.ComponentModel;
using System.Diagnostics;
using System.ServiceModel;
namespace ArchestrAServices.ASBContract;
[DebuggerStepThrough]
[GeneratedCode("System.ServiceModel", "4.0.0.0")]
[EditorBrowsable(EditorBrowsableState.Advanced)]
[MessageContract(WrapperName = "ConnectRequest", WrapperNamespace = "http://asb.contracts.messages/20111111", IsWrapped = true)]
public class ConnectRequest : ServiceMessage
{
[MessageBodyMember(Namespace = "http://asb.contracts.messages/20111111", Order = 0)]
public Guid ConnectionId;
[MessageBodyMember(Namespace = "http://asb.contracts.messages/20111111", Order = 1)]
public PublicKey ConsumerPublicKey;
public ConnectRequest()
{
}
public ConnectRequest(Guid ConnectionId, PublicKey ConsumerPublicKey)
{
this.ConnectionId = ConnectionId;
this.ConsumerPublicKey = ConsumerPublicKey;
}
}
@@ -0,0 +1,35 @@
using System.CodeDom.Compiler;
using System.ComponentModel;
using System.Diagnostics;
using System.ServiceModel;
using System.Xml.Serialization;
namespace ArchestrAServices.ASBContract;
[DebuggerStepThrough]
[GeneratedCode("System.ServiceModel", "4.0.0.0")]
[EditorBrowsable(EditorBrowsableState.Advanced)]
[MessageContract(WrapperName = "ConnectResponse", WrapperNamespace = "http://asb.contracts.messages/20111111", IsWrapped = true)]
public class ConnectResponse : ConnectedResponse
{
[MessageBodyMember(Namespace = "http://asb.contracts.messages/20111111", Order = 0)]
public PublicKey ServicePublicKey;
[MessageBodyMember(Namespace = "http://asb.contracts.messages/20111111", Order = 1)]
public AuthenticationData ServiceAuthenticationData;
[MessageBodyMember(Namespace = "http://asb.contracts.messages/20111111", Order = 2)]
[XmlElement(DataType = "duration")]
public string ConnectionLifetime;
public ConnectResponse()
{
}
public ConnectResponse(PublicKey ServicePublicKey, AuthenticationData ServiceAuthenticationData, string ConnectionLifetime)
{
this.ServicePublicKey = ServicePublicKey;
this.ServiceAuthenticationData = ServiceAuthenticationData;
this.ConnectionLifetime = ConnectionLifetime;
}
}
@@ -0,0 +1,21 @@
using System.CodeDom.Compiler;
using System.ComponentModel;
using System.Diagnostics;
using System.ServiceModel;
namespace ArchestrAServices.ASBContract;
[DebuggerStepThrough]
[GeneratedCode("System.ServiceModel", "4.0.0.0")]
[EditorBrowsable(EditorBrowsableState.Advanced)]
[MessageContract]
public class ConnectedRequest : ServiceMessage
{
[MessageHeader(Namespace = "http://asb.contracts.headers/20111111")]
public ConnectionValidator ConnectionValidator;
public ConnectedRequest()
{
ConnectionValidator = new ConnectionValidator();
}
}
@@ -0,0 +1,25 @@
using System.CodeDom.Compiler;
using System.ComponentModel;
using System.Diagnostics;
using System.ServiceModel;
namespace ArchestrAServices.ASBContract;
[DebuggerStepThrough]
[GeneratedCode("System.ServiceModel", "4.0.0.0")]
[EditorBrowsable(EditorBrowsableState.Advanced)]
[MessageContract]
public class ConnectedResponse : ConnectedRequest
{
[MessageBodyMember(Namespace = "http://asb.contracts.messages/20111111")]
public ArchestrAResult Result;
public ConnectedResponse()
{
}
public ConnectedResponse(ArchestrAResult result)
{
Result = result;
}
}
@@ -0,0 +1,73 @@
using System;
using System.CodeDom.Compiler;
using System.ComponentModel;
using System.Diagnostics;
using System.Xml.Serialization;
namespace ArchestrAServices.ASBContract;
[Serializable]
[GeneratedCode("System.Xml", "4.0.30319.233")]
[DebuggerStepThrough]
[DesignerCategory("code")]
[XmlType(Namespace = "http://asb.contracts.data/20111111")]
public class ConnectionValidator
{
private Guid connectionIdField;
private ulong messageNumberField;
private byte[] messageAuthenticationCodeField;
private byte[] signatureInitializationVectorField;
public Guid ConnectionId
{
get
{
return connectionIdField;
}
set
{
connectionIdField = value;
}
}
public ulong MessageNumber
{
get
{
return messageNumberField;
}
set
{
messageNumberField = value;
}
}
[XmlElement(DataType = "base64Binary")]
public byte[] MessageAuthenticationCode
{
get
{
return messageAuthenticationCodeField;
}
set
{
messageAuthenticationCodeField = value;
}
}
[XmlElement(DataType = "base64Binary")]
public byte[] SignatureInitializationVector
{
get
{
return signatureInitializationVectorField;
}
set
{
signatureInitializationVectorField = value;
}
}
}
@@ -0,0 +1,9 @@
namespace ArchestrAServices.ASBContract;
public enum CredentialType : ushort
{
UsernamePassword = 0,
X509Certificate = 1,
SamlToken = 2,
Other = ushort.MaxValue
}
@@ -0,0 +1,10 @@
namespace ArchestrAServices.ASBContract;
public enum CredentialValidity : ushort
{
UserIdentityValid = 0,
UserIdentityInvalid_BadPassword = 1,
UserIdentityInvalid_NoUser = 2,
UserIdentityInvalid_CannotAuthenticate = 3,
UesrIdentityValidityUnknown = ushort.MaxValue
}
@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
namespace ArchestrAServices.ASBContract;
public static class DataConversionUtilities
{
public static string ToBase64(this string value)
{
string result = string.Empty;
if (value != null)
{
result = Encoding.UTF8.GetBytes(value).ToBase64();
}
return result;
}
public static string FromBase64(this string value)
{
string result = string.Empty;
if (value != null)
{
byte[] bytes = value.FromBase64ToByteArray();
result = Encoding.UTF8.GetString(bytes);
}
return result;
}
public static string ToBase64(this byte[] value)
{
string result = string.Empty;
try
{
result = Convert.ToBase64String(value);
}
catch
{
}
return result;
}
public static string ToHex(this byte[] value)
{
StringBuilder stringBuilder = new StringBuilder();
if (value != null)
{
foreach (byte b in value)
{
stringBuilder.Append(b.ToString("X2", CultureInfo.CurrentCulture));
}
}
return stringBuilder.ToString();
}
public static byte[] FromBase64ToByteArray(this string value)
{
byte[] result = null;
if (value != null)
{
try
{
result = Convert.FromBase64String(value);
}
catch
{
}
}
return result;
}
public static byte[] FromHexToByteArray(this string value)
{
List<byte> list = new List<byte>();
if (value != null)
{
string text = value.Replace(" ", string.Empty);
text = text.Replace("\r", string.Empty);
text = text.Replace("\n", string.Empty);
if (text.Length % 2 == 0)
{
for (int i = 0; i < text.Length; i += 2)
{
if (byte.TryParse(text.Substring(i, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result))
{
list.Add(result);
}
}
}
}
return list.ToArray();
}
}
@@ -0,0 +1,25 @@
using System.CodeDom.Compiler;
using System.ComponentModel;
using System.Diagnostics;
using System.ServiceModel;
namespace ArchestrAServices.ASBContract;
[DebuggerStepThrough]
[GeneratedCode("System.ServiceModel", "4.0.0.0")]
[EditorBrowsable(EditorBrowsableState.Advanced)]
[MessageContract(WrapperName = "DisconnectRequest", WrapperNamespace = "http://asb.contracts.messages/20111111", IsWrapped = true)]
public class Disconnect : ConnectedRequest
{
[MessageBodyMember(Namespace = "http://asb.contracts.messages/20111111", Order = 0)]
public AuthenticationData ConsumerAuthenticationData;
public Disconnect()
{
}
public Disconnect(AuthenticationData ConsumerAuthenticationData)
{
this.ConsumerAuthenticationData = ConsumerAuthenticationData;
}
}
@@ -0,0 +1,6 @@
namespace ArchestrAServices.ASBContract;
public enum EncryptionType : ushort
{
None
}
@@ -0,0 +1,74 @@
using System;
namespace ArchestrAServices.ASBContract;
public static class EnumASBFactory
{
public static ArchestrAError IntToArchestrAError(ushort iValue)
{
try
{
return (ArchestrAError)iValue;
}
catch (Exception)
{
return ArchestrAError.Unknown;
}
}
public static ushort ArchestrAErrorToInt(ArchestrAError eValue)
{
return (ushort)eValue;
}
public static CredentialType IntToCredentialType(ushort iValue)
{
try
{
return (CredentialType)iValue;
}
catch (Exception)
{
return CredentialType.Other;
}
}
public static ushort CredentialTypeToInt(CredentialType eValue)
{
return (ushort)eValue;
}
public static EncryptionType IntToEncryptionType(ushort iValue)
{
try
{
return (EncryptionType)iValue;
}
catch (Exception)
{
return EncryptionType.None;
}
}
public static ushort EncryptionTypeToInt(EncryptionType eValue)
{
return (ushort)eValue;
}
public static CredentialValidity IntToCredentialValidity(ushort iValue)
{
try
{
return (CredentialValidity)iValue;
}
catch (Exception)
{
return CredentialValidity.UesrIdentityValidityUnknown;
}
}
public static ushort CredentialValidityToInt(CredentialValidity eValue)
{
return (ushort)eValue;
}
}
@@ -0,0 +1,33 @@
using System.CodeDom.Compiler;
using System.ServiceModel;
namespace ArchestrAServices.ASBContract;
[GeneratedCode("System.ServiceModel", "4.0.0.0")]
[ServiceContract(Namespace = "http://asb.contracts/20111111", ConfigurationName = "IAuthenticateASB")]
public interface IAuthenticateASB
{
[OperationContract(Action = "http://asb.contracts/20111111:connectIn", ReplyAction = "*")]
[XmlSerializerFormat(SupportFaults = true)]
ConnectResponse Connect(ConnectRequest request);
[OperationContract(Action = "http://asb.contracts/20111111:renewIn", ReplyAction = "*")]
[XmlSerializerFormat(SupportFaults = true)]
RenewResponse Renew(RenewRequest request);
[OperationContract(IsOneWay = true, Action = "http://asb.contracts/20111111:authenticateMeIn")]
[XmlSerializerFormat(SupportFaults = true)]
void AuthenticateMe(AuthenticateMe request);
[OperationContract(IsOneWay = true, Action = "http://asb.contracts/20111111:updateSystemAuthenticationConfigurationIn")]
[XmlSerializerFormat(SupportFaults = true)]
void UpdateSystemAuthenticationConfiguration(UpdateSystemAuthenticationConfiguration request);
[OperationContract(IsOneWay = true, Action = "http://asb.contracts/20111111:disconnectIn")]
[XmlSerializerFormat(SupportFaults = true)]
void Disconnect(Disconnect request);
[OperationContract(IsOneWay = true, Action = "http://asb.contracts/20111111:keepAliveIn")]
[XmlSerializerFormat(SupportFaults = true)]
void KeepAlive(KeepAlive request);
}
@@ -0,0 +1,33 @@
using System;
using System.CodeDom.Compiler;
using System.Xml.Serialization;
namespace ArchestrAServices.ASBContract;
[Serializable]
[GeneratedCode("System.Xml", "4.0.30319.233")]
[XmlType(Namespace = "http://asb.contracts.data/20111111", IncludeInSchema = false)]
public enum ItemChoiceType
{
Blob,
Boolean,
Byte,
Date,
DateTime,
Decimal,
Double,
Duration,
Float,
Guid,
Hex,
Int,
Integer,
Long,
Short,
String,
Time,
UnsignedByte,
UnsignedInt,
UnsignedLong,
UnsignedShort
}
@@ -0,0 +1,25 @@
using System.CodeDom.Compiler;
using System.ComponentModel;
using System.Diagnostics;
using System.ServiceModel;
namespace ArchestrAServices.ASBContract;
[DebuggerStepThrough]
[GeneratedCode("System.ServiceModel", "4.0.0.0")]
[EditorBrowsable(EditorBrowsableState.Advanced)]
[MessageContract(WrapperName = "KeepAliveRequest", WrapperNamespace = "http://asb.contracts.messages/20111111", IsWrapped = true)]
public class KeepAlive : ConnectedRequest
{
[MessageBodyMember(Namespace = "http://asb.contracts.messages/20111111", Order = 0)]
public AuthenticationData ConsumerAuthenticationData;
public KeepAlive()
{
}
public KeepAlive(AuthenticationData ConsumerAuthenticationData)
{
this.ConsumerAuthenticationData = ConsumerAuthenticationData;
}
}
@@ -0,0 +1,3 @@
namespace ArchestrAServices.ASBContract;
public delegate ConnectResponse MakeCallToAuthenticationConnect(ConnectRequest request);
@@ -0,0 +1,3 @@
namespace ArchestrAServices.ASBContract;
public delegate void MakeCallToServiceDisconnect(Disconnect request);
@@ -0,0 +1,3 @@
namespace ArchestrAServices.ASBContract;
public delegate void MakeCalltoAuthenticateMe(AuthenticateMe request);
@@ -0,0 +1,43 @@
using System;
using System.CodeDom.Compiler;
using System.ComponentModel;
using System.Diagnostics;
using System.Xml.Serialization;
namespace ArchestrAServices.ASBContract;
[Serializable]
[GeneratedCode("System.Xml", "4.0.30319.233")]
[DebuggerStepThrough]
[DesignerCategory("code")]
[XmlType(Namespace = "http://asb.contracts.data/20111111")]
public class NamedValue
{
private string nameField;
private ResultVariant valueField;
public string Name
{
get
{
return nameField;
}
set
{
nameField = value;
}
}
public ResultVariant Value
{
get
{
return valueField;
}
set
{
valueField = value;
}
}
}
@@ -0,0 +1,30 @@
using System;
using System.CodeDom.Compiler;
using System.ComponentModel;
using System.Diagnostics;
using System.Xml.Serialization;
namespace ArchestrAServices.ASBContract;
[Serializable]
[GeneratedCode("System.Xml", "4.0.30319.233")]
[DebuggerStepThrough]
[DesignerCategory("code")]
[XmlType(Namespace = "http://asb.contracts.data/20111111")]
public class PublicKey
{
private byte[] dataField;
[XmlElement(DataType = "base64Binary")]
public byte[] Data
{
get
{
return dataField;
}
set
{
dataField = value;
}
}
}
@@ -0,0 +1,34 @@
using System;
using System.CodeDom.Compiler;
using System.ComponentModel;
using System.Diagnostics;
using System.ServiceModel;
namespace ArchestrAServices.ASBContract;
[DebuggerStepThrough]
[GeneratedCode("System.ServiceModel", "4.0.0.0")]
[EditorBrowsable(EditorBrowsableState.Advanced)]
[MessageContract(WrapperName = "RenewRequest", WrapperNamespace = "http://asb.contracts.messages/20111111", IsWrapped = true)]
public class RenewRequest : ConnectedRequest
{
[MessageBodyMember(Namespace = "http://asb.contracts.messages/20111111", Order = 0)]
public AuthenticationData ConsumerAuthenticationData;
[MessageBodyMember(Namespace = "http://asb.contracts.messages/20111111", Order = 1)]
public Guid NewConnectionId;
[MessageBodyMember(Namespace = "http://asb.contracts.messages/20111111", Order = 2)]
public PublicKey NewConsumerPublicKey;
public RenewRequest()
{
}
public RenewRequest(AuthenticationData ConsumerAuthenticationData, Guid NewConnectionId, PublicKey NewConsumerPublicKey)
{
this.ConsumerAuthenticationData = ConsumerAuthenticationData;
this.NewConnectionId = NewConnectionId;
this.NewConsumerPublicKey = NewConsumerPublicKey;
}
}
@@ -0,0 +1,40 @@
using System;
using System.CodeDom.Compiler;
using System.ComponentModel;
using System.Diagnostics;
using System.ServiceModel;
using System.Xml.Serialization;
namespace ArchestrAServices.ASBContract;
[DebuggerStepThrough]
[GeneratedCode("System.ServiceModel", "4.0.0.0")]
[EditorBrowsable(EditorBrowsableState.Advanced)]
[MessageContract(WrapperName = "RenewResponse", WrapperNamespace = "http://asb.contracts.messages/20111111", IsWrapped = true)]
public class RenewResponse : ConnectedResponse
{
[MessageBodyMember(Namespace = "http://asb.contracts.messages/20111111", Order = 0)]
public Guid NewConnectionId;
[MessageBodyMember(Namespace = "http://asb.contracts.messages/20111111", Order = 1)]
[XmlElement(DataType = "duration")]
public string NewConnectionLifetime;
[MessageBodyMember(Namespace = "http://asb.contracts.messages/20111111", Order = 2)]
public PublicKey NewServicePublicKey;
[MessageBodyMember(Namespace = "http://asb.contracts.messages/20111111", Order = 3)]
public AuthenticationData NewServiceAuthenticationData;
public RenewResponse()
{
}
public RenewResponse(Guid NewConnectionId, string NewConnectionLifetime, PublicKey NewServicePublicKey, AuthenticationData NewServiceAuthenticationData)
{
this.NewConnectionId = NewConnectionId;
this.NewConnectionLifetime = NewConnectionLifetime;
this.NewServicePublicKey = NewServicePublicKey;
this.NewServiceAuthenticationData = NewServiceAuthenticationData;
}
}
@@ -0,0 +1,84 @@
using ArchestrAServices.Contract;
namespace ArchestrAServices.ASBContract;
public static class ResultFactory
{
public static ArchestrAResult MakeGoodResult()
{
return new ArchestrAResult
{
ErrorCode = EnumASBFactory.ArchestrAErrorToInt(ArchestrAError.Success),
Status = 0u,
SpecificErrorCode = 0u,
Success = true
};
}
public static ArchestrAResult MakeResult(ArchestrAError error, ushort status)
{
return new ArchestrAResult
{
ErrorCode = EnumASBFactory.ArchestrAErrorToInt(error),
Status = status,
Success = (error == ArchestrAError.Success)
};
}
public static ArchestrAResult MakeResult(ArchestrAError error, ushort status, uint specificError)
{
return new ArchestrAResult
{
ResultCode = EnumASBFactory.ArchestrAErrorToInt(error),
Status = status,
SpecificErrorCode = specificError,
Success = (error == ArchestrAError.Success)
};
}
public static void AddExtension(this ArchestrAResult Result, string Name, object Value, ItemChoiceType ValueType)
{
NamedValue[] array = null;
array = ((Result.Extensions != null) ? Result.Extensions : new NamedValue[0]);
Result.Extensions = new NamedValue[array.Length + 1];
for (int i = 0; i < array.Length; i++)
{
Result.Extensions[i] = array[i];
}
NamedValue namedValue = new NamedValue();
namedValue.Name = Name;
namedValue.Value = new ResultVariant();
namedValue.Value.Item = Value;
namedValue.Value.ItemElementName = ValueType;
Result.Extensions[Result.Extensions.Length - 1] = namedValue;
}
public static ArchestrAResult MakeResult(int Error)
{
return new ArchestrAResult
{
ResultCode = Error,
Success = (Error == 0)
};
}
public static ArchestrAResult MakeResult(int Error, string Location)
{
return new ArchestrAResult
{
Location = Location,
ResultCode = Error,
Success = (Error == 0)
};
}
public static ArchestrAResult MakeResult(ArchestrAServices.Contract.ArchestrAResult result)
{
ArchestrAResult result2 = default(ArchestrAResult);
result2.ResultCode = result.ErrorCode;
result2.Status = result.Status;
result2.SpecificErrorCode = result.SpecificErrorCode;
result2.Success = result2.ResultCode == 0;
return result2;
}
}
@@ -0,0 +1,66 @@
using System;
using System.CodeDom.Compiler;
using System.ComponentModel;
using System.Diagnostics;
using System.Xml.Serialization;
namespace ArchestrAServices.ASBContract;
[Serializable]
[GeneratedCode("System.Xml", "4.0.30319.233")]
[DebuggerStepThrough]
[DesignerCategory("code")]
[XmlType(Namespace = "http://asb.contracts.data/20111111")]
public class ResultVariant
{
private object itemField;
private ItemChoiceType itemElementNameField;
[XmlElement("Blob", typeof(byte[]), DataType = "base64Binary")]
[XmlElement("Boolean", typeof(bool))]
[XmlElement("Byte", typeof(sbyte))]
[XmlElement("Date", typeof(DateTime), DataType = "date")]
[XmlElement("DateTime", typeof(DateTime))]
[XmlElement("Decimal", typeof(decimal))]
[XmlElement("Double", typeof(double))]
[XmlElement("Duration", typeof(string), DataType = "duration")]
[XmlElement("Float", typeof(float))]
[XmlElement("Guid", typeof(Guid))]
[XmlElement("Hex", typeof(byte[]), DataType = "hexBinary")]
[XmlElement("Int", typeof(int))]
[XmlElement("Integer", typeof(string), DataType = "integer")]
[XmlElement("Long", typeof(long))]
[XmlElement("Short", typeof(short))]
[XmlElement("String", typeof(string))]
[XmlElement("Time", typeof(DateTime), DataType = "time")]
[XmlElement("UnsignedByte", typeof(byte))]
[XmlElement("UnsignedInt", typeof(uint))]
[XmlElement("UnsignedLong", typeof(ulong))]
[XmlElement("UnsignedShort", typeof(ushort))]
[XmlChoiceIdentifier("ItemElementName")]
public object Item
{
get
{
return itemField;
}
set
{
itemField = value;
}
}
[XmlIgnore]
public ItemChoiceType ItemElementName
{
get
{
return itemElementNameField;
}
set
{
itemElementNameField = value;
}
}
}
@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Xml.Linq;
using System.Xml.Serialization;
namespace ArchestrAServices.ASBContract;
public static class SerializationExtensions
{
private static readonly Dictionary<Type, XmlSerializer> xmlSerializers = new Dictionary<Type, XmlSerializer>();
private static readonly object serializersLock = new object();
public static XmlSerializer GetTypeSerializer(Type objectType)
{
if (objectType == null)
{
return null;
}
XmlSerializer xmlSerializer;
lock (serializersLock)
{
if (!xmlSerializers.ContainsKey(objectType))
{
string defaultNamespace = "urn:invensys.schemas";
object[] customAttributes = objectType.GetCustomAttributes(inherit: true);
if (customAttributes.Length != 0)
{
object[] array = customAttributes;
for (int i = 0; i < array.Length; i++)
{
if (array[i] is XmlRootAttribute xmlRootAttribute)
{
defaultNamespace = xmlRootAttribute.Namespace;
break;
}
}
}
xmlSerializer = new XmlSerializer(objectType, defaultNamespace);
xmlSerializers.Add(objectType, xmlSerializer);
}
else
{
xmlSerializer = xmlSerializers[objectType];
}
}
return xmlSerializer;
}
public static string ToXml(this object value)
{
string text = string.Empty;
if (value != null)
{
try
{
using TextWriter textWriter = new StringWriter(CultureInfo.CurrentCulture);
lock (serializersLock)
{
XmlSerializer typeSerializer = GetTypeSerializer(value.GetType());
if (typeSerializer != null)
{
typeSerializer.Serialize(textWriter, value);
text = textWriter.ToString();
}
}
}
catch
{
}
}
if (Environment.Is64BitProcess)
{
using TextReader textReader = new StringReader(text);
using IEnumerator<XElement> enumerator = XDocument.Load(textReader).Elements().GetEnumerator();
if (enumerator.MoveNext())
{
XElement current = enumerator.Current;
XAttribute xAttribute = current.Attribute(XNamespace.Xmlns + "xsd");
XAttribute xAttribute2 = current.Attribute(XNamespace.Xmlns + "xsi");
if (xAttribute != null && xAttribute2 != null)
{
current.ReplaceAttributes(xAttribute2, xAttribute);
}
using TextWriter textWriter2 = new StringWriter(CultureInfo.CurrentCulture);
current.Save(textWriter2);
text = textWriter2.ToString();
}
}
return text;
}
}
@@ -0,0 +1,14 @@
using System.CodeDom.Compiler;
using System.ComponentModel;
using System.Diagnostics;
using System.ServiceModel;
namespace ArchestrAServices.ASBContract;
[DebuggerStepThrough]
[GeneratedCode("System.ServiceModel", "4.0.0.0")]
[EditorBrowsable(EditorBrowsableState.Advanced)]
[MessageContract]
public class ServiceMessage
{
}
@@ -0,0 +1,7 @@
namespace ArchestrAServices.ASBContract;
public enum SigningMethod
{
Baktun,
Apollo
}
@@ -0,0 +1,204 @@
#define TRACE
using System;
using System.Diagnostics;
using System.Globalization;
using System.Numerics;
using System.Security.Cryptography;
using System.Text;
using ArchestrAServices.Common;
namespace ArchestrAServices.ASBContract;
public class SysAuthClientAuthentication : SysAuthConnectionBase
{
private RNGCryptoServiceProvider m_Random = new RNGCryptoServiceProvider();
private readonly WeakReference owner;
public uint Timeout { get; set; }
public BigInteger ClientPrivateKey { get; private set; }
public BigInteger ClientPublicKey { get; private set; }
public BigInteger ServicePublicKey { get; private set; }
public bool IsOwnerAlive
{
get
{
if (owner != null)
{
return owner.IsAlive;
}
return true;
}
}
[Obsolete("Please use the constructor that takes the owner as well.")]
public SysAuthClientAuthentication(string ASBSolution)
: this(ASBSolution, null)
{
}
public SysAuthClientAuthentication(string ASBSolution, WeakReference owner)
: base(ASBSolution)
{
Reset();
base.ReasonSecureSessionNotEstablished = "Constructed";
this.owner = owner;
}
public static bool EstablishSecureSession(string application, string domain, string host, string asbSolution, WeakReference owner, MakeCallToAuthenticationConnect connectDelegate, MakeCalltoAuthenticateMe authenticateMeDelegate, out Guid connectionId)
{
string ReasonSecureSessionNotEstablished;
return EstablishSecureSession(application, domain, host, asbSolution, owner, connectDelegate, authenticateMeDelegate, out connectionId, out ReasonSecureSessionNotEstablished);
}
[Obsolete("Please use the method that requires the owner as well.")]
public static bool EstablishSecureSession(string application, string domain, string host, string asbSolution, MakeCallToAuthenticationConnect connectDelegate, MakeCalltoAuthenticateMe authenticateMeDelegate, out Guid connectionId)
{
return EstablishSecureSession(application, domain, host, asbSolution, null, connectDelegate, authenticateMeDelegate, out connectionId);
}
[CLSCompliant(false)]
[Obsolete("Please use the method that requires the owner as well.")]
public static bool EstablishSecureSession(string application, string domain, string host, string asbSolution, MakeCallToAuthenticationConnect connectDelegate, MakeCalltoAuthenticateMe authenticateMeDelegate, out Guid connectionId, out string ReasonSecureSessionNotEstablished)
{
return EstablishSecureSession(application, domain, host, asbSolution, null, connectDelegate, authenticateMeDelegate, out connectionId, out ReasonSecureSessionNotEstablished);
}
[CLSCompliant(false)]
public static bool EstablishSecureSession(string application, string domain, string host, string asbSolution, WeakReference owner, MakeCallToAuthenticationConnect connectDelegate, MakeCalltoAuthenticateMe authenticateMeDelegate, out Guid connectionId, out string ReasonSecureSessionNotEstablished)
{
SysAuthClientAuthentication sysAuthClientAuthentication = new SysAuthClientAuthentication(asbSolution, owner);
ReasonSecureSessionNotEstablished = string.Empty;
SysAuthenticatorClientCache.AddClientAuthenticator(sysAuthClientAuthentication);
connectionId = sysAuthClientAuthentication.connectionID;
PublicKey publicKey = new PublicKey();
publicKey.Data = sysAuthClientAuthentication.m_LocalPublicKey;
ConnectRequest request = new ConnectRequest(connectionId, publicKey);
ConnectResponse connectResponse = null;
try
{
connectResponse = connectDelegate(request);
}
catch (Exception ex)
{
string text = string.Format(CultureInfo.CurrentCulture, "Exception connecting to service during EstablishSecureSession: {0}", new object[1] { ex.Message });
SvcTrace.DiagControl.TraceEvent(TraceEventType.Warning, 0, text);
if (string.IsNullOrEmpty(ReasonSecureSessionNotEstablished))
{
ReasonSecureSessionNotEstablished = text;
}
}
if (connectResponse != null)
{
if (connectResponse.Result.Success)
{
sysAuthClientAuthentication.m_RemotePublicKey = connectResponse.ServicePublicKey.Data;
sysAuthClientAuthentication.SignatureMethod = SigningMethod.Baktun;
sysAuthClientAuthentication.ReasonSecureSessionNotEstablished = string.Empty;
if (sysAuthClientAuthentication.ValidResponse(connectResponse, ForceHmac: true))
{
sysAuthClientAuthentication.m_Authenticated = true;
if (connectResponse.ConnectionLifetime.Contains(":" + SysAuthConnectionBase.ASBAuthenticationVersion))
{
sysAuthClientAuthentication.SignatureMethod = SigningMethod.Apollo;
}
SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 100, "SysClientAuth: Connect() response validated, signing set to {0}", (sysAuthClientAuthentication.SignatureMethod == SigningMethod.Baktun) ? "System Platform 2012R2 Comptibility" : "System Platform 2014 Compatibility");
byte[] initializationVector;
AuthenticateMe request2 = new AuthenticateMe(new AuthenticationData
{
Data = sysAuthClientAuthentication.CalculateAuthenticationData(sysAuthClientAuthentication.m_LocalPublicKey, sysAuthClientAuthentication.m_RemotePublicKey, out initializationVector),
InitializationVector = initializationVector
});
sysAuthClientAuthentication.Sign(request2, ForceHmac: true);
authenticateMeDelegate(request2);
}
else
{
if (string.IsNullOrEmpty(ReasonSecureSessionNotEstablished))
{
if (!string.IsNullOrEmpty(sysAuthClientAuthentication.ReasonSecureSessionNotEstablished))
{
ReasonSecureSessionNotEstablished = "Service returned response to Connect method, but validation failed: " + sysAuthClientAuthentication.ReasonSecureSessionNotEstablished;
}
else
{
ReasonSecureSessionNotEstablished = "Service returned response to Connect method, but validation data was not valid, cannot establish secure session";
}
}
SysAuthenticatorClientCache.RemoveClientAuthenticator(connectionId);
connectionId = Guid.Empty;
}
}
else
{
if (string.IsNullOrEmpty(ReasonSecureSessionNotEstablished))
{
string text2 = string.Empty;
if (connectResponse.Result.ErrorMessages != null && connectResponse.Result.ErrorMessages.Length != 0)
{
string[] errorMessages = connectResponse.Result.ErrorMessages;
foreach (string text3 in errorMessages)
{
text2 = text2 + text3 + "| ";
}
}
if (string.IsNullOrEmpty(text2))
{
ReasonSecureSessionNotEstablished = string.Format(CultureInfo.CurrentCulture, "Service returned error {0} in response to Connect method, cannot establish secure connection.", new object[1] { connectResponse.Result.ErrorCode });
}
else
{
ReasonSecureSessionNotEstablished = string.Format(CultureInfo.CurrentCulture, "Service returned error {0} in response to Connect method, cannot establish secure connection. Additional information: {1}", new object[2]
{
connectResponse.Result.ErrorCode,
text2
});
}
}
SysAuthenticatorClientCache.RemoveClientAuthenticator(connectionId);
connectionId = Guid.Empty;
}
}
else
{
SysAuthenticatorClientCache.RemoveClientAuthenticator(connectionId);
connectionId = Guid.Empty;
}
return sysAuthClientAuthentication.SecureSessionEstablished;
}
public void AbortSession()
{
SysAuthenticatorClientCache.RemoveClientAuthenticator(connectionID);
Reset();
base.ReasonSecureSessionNotEstablished = "Session Aborted";
}
[CLSCompliant(false)]
public static void DisconnectSecureSession(Guid connectionId, MakeCallToServiceDisconnect DisconnectDelegate)
{
SysAuthClientAuthentication clientAuthenticator = SysAuthenticatorClientCache.GetClientAuthenticator(connectionId);
if (clientAuthenticator != null)
{
byte[] initializationVector;
Disconnect request = new Disconnect(new AuthenticationData
{
Data = clientAuthenticator.Encypher(Encoding.UTF8.GetBytes(clientAuthenticator.connectionID.ToString()), out initializationVector),
InitializationVector = initializationVector
});
clientAuthenticator.Sign(request);
DisconnectDelegate?.Invoke(request);
SysAuthenticatorClientCache.RemoveClientAuthenticator(connectionId);
}
}
private new void Reset()
{
base.Reset();
Timeout = 10000u;
}
}
@@ -0,0 +1,701 @@
#define TRACE
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Numerics;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using ArchestrAServices.Common;
using Invensys.Compression;
namespace ArchestrAServices.ASBContract;
public class SysAuthConnectionBase
{
private static RandomNumberGenerator mRANDOM = RandomNumberGenerator.Create();
private static readonly byte[] PASSWORDSALT = Encoding.ASCII.GetBytes("ArchestrAService");
protected static string ASBAuthenticationVersion = "V2";
protected static readonly object MessageNumberLock = new object();
protected SysAuthParameters m_SolutionParameters;
public Guid connectionID = Guid.Empty;
protected byte[] m_PrivateKey;
protected byte[] m_LocalPublicKey;
protected byte[] m_RemotePublicKey;
protected bool m_Authenticated;
protected ulong m_NextMessageNumber = 1uL;
private ulong m_HighestMessageNumberReceived;
private List<ulong> m_OutOfSyncMessageNumbers = new List<ulong>();
private byte[] SolutionPassphrase
{
get
{
byte[] result = null;
if (m_SolutionParameters.ASBSolutionValid)
{
if (m_SolutionParameters.DH_passphrase != null && m_SolutionParameters.DH_passphrase.Length > 0)
{
result = Encoding.UTF8.GetBytes(m_SolutionParameters.DH_passphrase);
}
if (m_SolutionParameters.DH_certificate != null && m_SolutionParameters.DH_certificate.Length != 0)
{
result = new X509Certificate(m_SolutionParameters.DH_certificate).GetPublicKey();
}
}
return result;
}
}
private byte[] CryptoKey
{
get
{
List<byte> list = new List<byte>();
list.AddRange(CalculateConnectionKey(m_RemotePublicKey, m_PrivateKey));
byte[] solutionPassphrase = SolutionPassphrase;
if (solutionPassphrase != null)
{
list.AddRange(solutionPassphrase);
}
return list.ToArray();
}
}
public ConnectionValidator m_ConnectionValidator { get; protected set; }
public bool SecureSessionEstablished
{
get
{
return m_Authenticated;
}
protected set
{
m_Authenticated = value;
}
}
public string ReasonSecureSessionNotEstablished { get; protected set; }
public string DH_passphrase
{
get
{
return m_SolutionParameters.DH_passphrase;
}
set
{
m_SolutionParameters.DH_passphrase = value;
}
}
public string DH_hashAlgorithm => m_SolutionParameters.hashAlgorithm;
public string DH_asbSolutionName => m_SolutionParameters.ASBSolutionName;
public SigningMethod SignatureMethod { get; set; }
public SysAuthConnectionBase(string asbSolutionName = null)
{
m_SolutionParameters = new SysAuthParameters(asbSolutionName);
ReasonSecureSessionNotEstablished = "Constructed";
Reset();
}
protected void Reset()
{
SecureSessionEstablished = false;
ReasonSecureSessionNotEstablished = "Reset";
SignatureMethod = SigningMethod.Baktun;
connectionID = Guid.NewGuid();
m_PrivateKey = GetPrivateKey(m_SolutionParameters.KeySize);
m_LocalPublicKey = CalculatePublicKey(m_PrivateKey);
m_Authenticated = false;
}
private byte[] GetPrivateKey(int length)
{
byte[] array = null;
if (length > 0)
{
BigInteger bigInteger = m_SolutionParameters.DH_p - new BigInteger(1);
BigInteger bigInteger2 = new BigInteger(0);
while (bigInteger2 >= bigInteger || bigInteger2 <= 0L)
{
array = new byte[length / 8];
mRANDOM.GetBytes(array);
bigInteger2 = new BigInteger(array);
}
}
return array;
}
protected byte[] CalculatePublicKey(byte[] privateKey)
{
BigInteger exponent = new BigInteger(privateKey);
BigInteger dH_g = m_SolutionParameters.DH_g;
BigInteger dH_p = m_SolutionParameters.DH_p;
return BigInteger.ModPow(dH_g, exponent, dH_p).ToByteArray();
}
protected byte[] CalculateConnectionKey(byte[] remotePublicKey, byte[] localPrivateKey)
{
BigInteger value = new BigInteger(remotePublicKey);
BigInteger exponent = new BigInteger(localPrivateKey);
BigInteger dH_p = m_SolutionParameters.DH_p;
return BigInteger.ModPow(value, exponent, dH_p).ToByteArray();
}
private HMAC NewSolutionHmac(bool ForceHMAC = false)
{
HMAC result;
switch (DH_hashAlgorithm.ToLower())
{
case "md5":
SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 0, "Solution HMAC is MD5");
result = new HMACMD5(CryptoKey);
break;
case "sha1":
SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 0, "Solution HMAC is SHA1");
result = new HMACSHA1(CryptoKey);
break;
case "sha512":
SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 0, "Solution HMAC is SHA512");
result = new HMACSHA512(CryptoKey);
break;
default:
SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 0, "Solution HMAC is NONE");
result = null;
if (ForceHMAC)
{
result = new HMACSHA1(CryptoKey);
}
break;
}
return result;
}
public bool ValidRequest(ConnectedRequest request, bool ForceHmac = false)
{
bool flag = false;
if (request != null && request.ConnectionValidator != null)
{
ConnectionValidator connectionValidator = request.ConnectionValidator;
byte[] messageAuthenticationCode = connectionValidator.MessageAuthenticationCode;
byte[] signatureInitializationVector = connectionValidator.SignatureInitializationVector;
byte[] array = null;
using (HMAC hMAC = NewSolutionHmac(ForceHmac))
{
if (hMAC != null)
{
connectionValidator.MessageAuthenticationCode = new byte[0];
connectionValidator.SignatureInitializationVector = new byte[0];
byte[] bytes = Encoding.UTF8.GetBytes(request.ToXml());
connectionValidator.MessageAuthenticationCode = messageAuthenticationCode;
connectionValidator.SignatureInitializationVector = signatureInitializationVector;
if (SignatureMethod == SigningMethod.Baktun)
{
array = EncypherBaktun(hMAC.ComputeHash(bytes), signatureInitializationVector);
}
else
{
byte[] array2 = hMAC.ComputeHash(bytes);
byte[] array3 = DecypherApollo(messageAuthenticationCode, signatureInitializationVector);
bool flag2 = false;
if (array2 != null && array3 != null && array2.Length == array3.Length)
{
flag2 = true;
for (int i = 0; i < array2.Length; i++)
{
if (array2[i] != array3[i])
{
flag2 = false;
break;
}
}
}
array = ((!flag2) ? new byte[0] : messageAuthenticationCode);
}
}
}
if (array != null)
{
if (messageAuthenticationCode != null && array.Length == messageAuthenticationCode.Length)
{
flag = true;
for (int j = 0; j < messageAuthenticationCode.Length; j++)
{
if (messageAuthenticationCode[j] != array[j])
{
if (string.IsNullOrEmpty(ReasonSecureSessionNotEstablished))
{
ReasonSecureSessionNotEstablished = string.Format(CultureInfo.CurrentCulture, "ValidRequest: Received message hmac correct length {0} but differs at byte {1}, cannot validate", new object[2] { messageAuthenticationCode.Length, j });
}
flag = false;
break;
}
}
}
else if (messageAuthenticationCode == null)
{
if (string.IsNullOrEmpty(ReasonSecureSessionNotEstablished))
{
ReasonSecureSessionNotEstablished = "ValidRequest: Received message has null hmac, cannot validate";
}
}
else if (string.IsNullOrEmpty(ReasonSecureSessionNotEstablished))
{
ReasonSecureSessionNotEstablished = string.Format(CultureInfo.CurrentCulture, "ValidRequest: Received message hmac wrong length, cannot validate (received {0}, computed {1})", new object[2] { messageAuthenticationCode.Length, array.Length });
}
}
else
{
flag = true;
}
if (flag)
{
lock (this)
{
if (connectionValidator.MessageNumber <= m_HighestMessageNumberReceived)
{
ReasonSecureSessionNotEstablished = string.Format(CultureInfo.CurrentCulture, "ValidRequest: Received message out of sequence, cannot validate (current {0}, highest {1})", new object[2] { connectionValidator.MessageNumber, m_HighestMessageNumberReceived });
flag = false;
}
else if (m_OutOfSyncMessageNumbers.Contains(connectionValidator.MessageNumber))
{
ReasonSecureSessionNotEstablished = string.Format(CultureInfo.CurrentCulture, "ValidRequest: Received message received late, cannot validate (current {0})", new object[1] { connectionValidator.MessageNumber });
flag = false;
}
else if (connectionValidator.MessageNumber == m_HighestMessageNumberReceived + 1)
{
m_HighestMessageNumberReceived = connectionValidator.MessageNumber;
}
else
{
m_OutOfSyncMessageNumbers.Add(connectionValidator.MessageNumber);
}
m_OutOfSyncMessageNumbers.Sort();
foreach (ulong outOfSyncMessageNumber in m_OutOfSyncMessageNumbers)
{
if (outOfSyncMessageNumber == m_HighestMessageNumberReceived + 1)
{
m_HighestMessageNumberReceived = outOfSyncMessageNumber;
}
}
List<ulong> list = new List<ulong>();
foreach (ulong outOfSyncMessageNumber2 in m_OutOfSyncMessageNumbers)
{
if (outOfSyncMessageNumber2 <= m_HighestMessageNumberReceived)
{
list.Add(outOfSyncMessageNumber2);
}
}
foreach (ulong item in list)
{
m_OutOfSyncMessageNumbers.Remove(item);
}
}
}
}
else
{
ReasonSecureSessionNotEstablished = "ValidRequest: Either the message or its ConnectionValidator field is null, cannot validate";
}
return flag;
}
public bool ValidResponse(ConnectedResponse response, bool ForceHmac = false)
{
if (response != null && response.Result.Success)
{
return ValidRequest(response, ForceHmac);
}
return false;
}
protected byte[] ReCalculateAuthenticationData(byte[] leftPart, byte[] rightPart, byte[] initializationVector)
{
List<byte> list = new List<byte>();
if (leftPart != null)
{
list.AddRange(leftPart);
}
if (rightPart != null)
{
list.AddRange(rightPart);
}
return ReEncypher(list.ToArray(), initializationVector);
}
protected byte[] CalculateAuthenticationData(byte[] leftPart, byte[] rightPart, out byte[] initializationVector)
{
List<byte> list = new List<byte>();
initializationVector = null;
if (leftPart != null)
{
list.AddRange(leftPart);
}
if (rightPart != null)
{
list.AddRange(rightPart);
}
return Encypher(list.ToArray(), out initializationVector);
}
public ConnectionValidator MakeConnectionValidator()
{
lock (MessageNumberLock)
{
return new ConnectionValidator
{
ConnectionId = connectionID,
MessageNumber = m_NextMessageNumber++,
MessageAuthenticationCode = new byte[0],
SignatureInitializationVector = new byte[0]
};
}
}
public void Sign(ConnectedRequest request, bool ForceHmac = false)
{
if (request == null)
{
return;
}
lock (MessageNumberLock)
{
ConnectionValidator connectionValidator = new ConnectionValidator();
connectionValidator.ConnectionId = connectionID;
connectionValidator.MessageNumber = m_NextMessageNumber++;
connectionValidator.MessageAuthenticationCode = new byte[0];
connectionValidator.SignatureInitializationVector = new byte[0];
request.ConnectionValidator = connectionValidator;
using HMAC hMAC = NewSolutionHmac(ForceHmac);
if (hMAC != null)
{
byte[] bytes = Encoding.UTF8.GetBytes(request.ToXml());
connectionValidator.MessageAuthenticationCode = Encypher(hMAC.ComputeHash(bytes), out var initializationVector);
connectionValidator.SignatureInitializationVector = initializationVector;
}
}
}
public byte[] EncypherBaktun(byte[] clearData, byte[] initializationVector)
{
byte[] result = null;
if (clearData != null)
{
using AesManaged aesManaged = new AesManaged();
using Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(CryptoKey.ToBase64(), PASSWORDSALT);
aesManaged.Key = rfc2898DeriveBytes.GetBytes(16);
aesManaged.IV = initializationVector;
using ICryptoTransform transform = aesManaged.CreateEncryptor();
using MemoryStream memoryStream = new MemoryStream();
using (CryptoStream stream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))
{
using AADeflateStream aADeflateStream = new AADeflateStream(stream, CompressionMode.Compress);
aADeflateStream.Write(clearData, 0, clearData.Length);
aADeflateStream.Close();
}
result = memoryStream.ToArray();
}
return result;
}
public byte[] EncypherBaktun(byte[] clearData, out byte[] initializationVector)
{
byte[] result = null;
initializationVector = null;
if (clearData != null)
{
using AesManaged aesManaged = new AesManaged();
using Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(CryptoKey.ToBase64(), PASSWORDSALT);
aesManaged.Key = rfc2898DeriveBytes.GetBytes(16);
initializationVector = aesManaged.IV;
using ICryptoTransform transform = aesManaged.CreateEncryptor();
using MemoryStream memoryStream = new MemoryStream();
using (CryptoStream stream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))
{
using AADeflateStream aADeflateStream = new AADeflateStream(stream, CompressionMode.Compress);
aADeflateStream.Write(clearData, 0, clearData.Length);
aADeflateStream.Close();
}
result = memoryStream.ToArray();
}
return result;
}
public string EncypherBaktun(string clearText, out byte[] initializationVector)
{
string result = string.Empty;
initializationVector = null;
if (!string.IsNullOrEmpty(clearText))
{
byte[] bytes = Encoding.UTF8.GetBytes(clearText);
result = EncypherBaktun(bytes, out initializationVector).ToBase64();
}
return result;
}
public byte[] ReEncypherBaktun(byte[] clearData, byte[] initializationVector)
{
byte[] result = null;
if (clearData != null)
{
using AesManaged aesManaged = new AesManaged();
using Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(CryptoKey.ToBase64(), PASSWORDSALT);
aesManaged.Key = rfc2898DeriveBytes.GetBytes(16);
aesManaged.IV = initializationVector;
using ICryptoTransform transform = aesManaged.CreateEncryptor();
using MemoryStream memoryStream = new MemoryStream();
using (CryptoStream stream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))
{
using AADeflateStream aADeflateStream = new AADeflateStream(stream, CompressionMode.Compress);
aADeflateStream.Write(clearData, 0, clearData.Length);
aADeflateStream.Close();
}
result = memoryStream.ToArray();
}
return result;
}
public string ReEncypherBaktun(string clearText, byte[] initializationVector)
{
string result = string.Empty;
if (!string.IsNullOrEmpty(clearText))
{
byte[] bytes = Encoding.UTF8.GetBytes(clearText);
result = ReEncypherBaktun(bytes, initializationVector).ToBase64();
}
return result;
}
public byte[] DecypherBaktun(byte[] cypherData, byte[] initializationVector)
{
byte[] result = null;
if (cypherData != null)
{
using AesManaged aesManaged = new AesManaged();
using Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(CryptoKey.ToBase64(), PASSWORDSALT);
aesManaged.Key = rfc2898DeriveBytes.GetBytes(16);
aesManaged.IV = initializationVector;
using ICryptoTransform transform = aesManaged.CreateDecryptor();
using MemoryStream stream = new MemoryStream(cypherData);
using CryptoStream stream2 = new CryptoStream(stream, transform, CryptoStreamMode.Read);
using AADeflateStream aADeflateStream = new AADeflateStream(stream2, CompressionMode.Decompress);
using MemoryStream memoryStream = new MemoryStream();
aADeflateStream.CopyTo(memoryStream);
result = memoryStream.ToArray();
}
return result;
}
public string DecypherBaktun(string cypherText, byte[] initializationVector)
{
string result = string.Empty;
if (!string.IsNullOrEmpty(cypherText))
{
byte[] cypherData = cypherText.FromBase64ToByteArray();
byte[] bytes = DecypherBaktun(cypherData, initializationVector);
result = Encoding.UTF8.GetString(bytes);
}
return result;
}
public byte[] EncypherApollo(byte[] clearData, byte[] initializationVector)
{
byte[] result = null;
if (clearData != null)
{
using AesManaged aesManaged = new AesManaged();
using Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(CryptoKey.ToBase64(), PASSWORDSALT);
aesManaged.Key = rfc2898DeriveBytes.GetBytes(16);
aesManaged.IV = initializationVector;
using ICryptoTransform transform = aesManaged.CreateEncryptor();
using MemoryStream memoryStream = new MemoryStream();
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))
{
cryptoStream.Write(clearData, 0, clearData.Length);
cryptoStream.Close();
}
result = memoryStream.ToArray();
}
return result;
}
public byte[] EncypherApollo(byte[] clearData, out byte[] initializationVector)
{
byte[] result = null;
initializationVector = null;
if (clearData != null)
{
using AesManaged aesManaged = new AesManaged();
using Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(CryptoKey.ToBase64(), PASSWORDSALT);
aesManaged.Key = rfc2898DeriveBytes.GetBytes(16);
initializationVector = aesManaged.IV;
using ICryptoTransform transform = aesManaged.CreateEncryptor();
using MemoryStream memoryStream = new MemoryStream();
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))
{
cryptoStream.Write(clearData, 0, clearData.Length);
cryptoStream.Close();
}
result = memoryStream.ToArray();
}
return result;
}
public string EncypherApollo(string clearText, out byte[] initializationVector)
{
string result = string.Empty;
initializationVector = null;
if (!string.IsNullOrEmpty(clearText))
{
byte[] bytes = Encoding.UTF8.GetBytes(clearText);
result = EncypherApollo(bytes, out initializationVector).ToBase64();
}
return result;
}
public byte[] ReEncypherApollo(byte[] clearData, byte[] initializationVector)
{
byte[] result = null;
if (clearData != null)
{
using AesManaged aesManaged = new AesManaged();
using Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(CryptoKey.ToBase64(), PASSWORDSALT);
aesManaged.Key = rfc2898DeriveBytes.GetBytes(16);
aesManaged.IV = initializationVector;
using ICryptoTransform transform = aesManaged.CreateEncryptor();
using MemoryStream memoryStream = new MemoryStream();
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))
{
cryptoStream.Write(clearData, 0, clearData.Length);
cryptoStream.Close();
}
result = memoryStream.ToArray();
}
return result;
}
public string ReEncypherApollo(string clearText, byte[] initializationVector)
{
string result = string.Empty;
if (!string.IsNullOrEmpty(clearText))
{
byte[] bytes = Encoding.UTF8.GetBytes(clearText);
result = ReEncypherApollo(bytes, initializationVector).ToBase64();
}
return result;
}
public byte[] DecypherApollo(byte[] cypherData, byte[] initializationVector)
{
byte[] result = null;
if (cypherData != null)
{
using AesManaged aesManaged = new AesManaged();
using Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(CryptoKey.ToBase64(), PASSWORDSALT);
aesManaged.Key = rfc2898DeriveBytes.GetBytes(16);
aesManaged.IV = initializationVector;
using ICryptoTransform transform = aesManaged.CreateDecryptor();
using MemoryStream stream = new MemoryStream(cypherData);
using CryptoStream cryptoStream = new CryptoStream(stream, transform, CryptoStreamMode.Read);
using MemoryStream memoryStream = new MemoryStream();
cryptoStream.CopyTo(memoryStream);
result = memoryStream.ToArray();
}
return result;
}
public string DecypherApollo(string cypherText, byte[] initializationVector)
{
string result = string.Empty;
if (!string.IsNullOrEmpty(cypherText))
{
byte[] cypherData = cypherText.FromBase64ToByteArray();
byte[] bytes = DecypherApollo(cypherData, initializationVector);
result = Encoding.UTF8.GetString(bytes);
}
return result;
}
public byte[] Encypher(byte[] clearData, byte[] initializationVector)
{
if (SignatureMethod == SigningMethod.Baktun)
{
return EncypherBaktun(clearData, initializationVector);
}
return EncypherApollo(clearData, initializationVector);
}
public byte[] Encypher(byte[] clearData, out byte[] initializationVector)
{
if (SignatureMethod == SigningMethod.Baktun)
{
return EncypherBaktun(clearData, out initializationVector);
}
return EncypherApollo(clearData, out initializationVector);
}
public string Encypher(string clearText, out byte[] initializationVector)
{
if (SignatureMethod == SigningMethod.Baktun)
{
return EncypherBaktun(clearText, out initializationVector);
}
return EncypherApollo(clearText, out initializationVector);
}
public byte[] ReEncypher(byte[] clearData, byte[] initializationVector)
{
if (SignatureMethod == SigningMethod.Baktun)
{
return ReEncypherBaktun(clearData, initializationVector);
}
return ReEncypherApollo(clearData, initializationVector);
}
public string ReEncypher(string clearText, byte[] initializationVector)
{
if (SignatureMethod == SigningMethod.Baktun)
{
return ReEncypherBaktun(clearText, initializationVector);
}
return ReEncypherApollo(clearText, initializationVector);
}
public byte[] Decypher(byte[] cypherData, byte[] initializationVector)
{
if (SignatureMethod == SigningMethod.Baktun)
{
return DecypherBaktun(cypherData, initializationVector);
}
return DecypherApollo(cypherData, initializationVector);
}
public string Decypher(string cypherText, byte[] initializationVector)
{
if (SignatureMethod == SigningMethod.Baktun)
{
return DecypherBaktun(cypherText, initializationVector);
}
return DecypherApollo(cypherText, initializationVector);
}
}
@@ -0,0 +1,249 @@
#define TRACE
using System;
using System.Diagnostics;
using System.Numerics;
using System.Security.Cryptography;
using System.Text;
using ArchestrAServices.Common;
namespace ArchestrAServices.ASBContract;
public class SysAuthParameters
{
public string ASBSolutionName;
public bool ASBSolutionValid;
public int DH_KeySize;
public int DH_SecretSize;
public BigInteger DH_p;
public BigInteger DH_g;
private string m_SysAuthPassphrase;
private byte[] m_SysAuthCertificate;
public uint ConnectionLifetime;
public string SaltValue;
public string hashAlgorithm;
public int PasswordIterations;
public string InitialVector;
public int KeySize;
private static string RegKeyRelativePath = string.Empty;
public static int DH_KeySize_Dft = 1024;
public static int DH_SecretSize_Dft = 160;
public static string DH_passphrase_Dft = Environment.MachineName;
public static uint ConnectionLifetime_Dft = 60000u;
public static string SaltValue_Dft = "s@1tValue";
public static string hashAlgorithm_Dft = CngAlgorithm.MD5.ToString();
public static int PasswordIterations_Dft = 1;
public static string InitialVector_Dft = "ba172e9941be138b";
public static int KeySize_Dft = 256;
private static string s_DECIMAL768 = "1552518092300708935130918131258481755631334049434514313202351194902966239949102107258669453876591642442910007680288864229150803718918046342632727613031282983744380820890196288509170691316593175367469551763119843371637221007210577919";
private static byte[] s_OAKLEY768 = new byte[96]
{
255, 255, 255, 255, 255, 255, 255, 255, 201, 15,
218, 162, 33, 104, 194, 52, 196, 198, 98, 139,
128, 220, 28, 209, 41, 2, 78, 8, 138, 103,
204, 116, 2, 11, 190, 166, 59, 19, 155, 34,
81, 74, 8, 121, 142, 52, 4, 221, 239, 149,
25, 179, 205, 58, 67, 27, 48, 43, 10, 109,
242, 95, 20, 55, 79, 225, 53, 109, 109, 81,
194, 69, 228, 133, 181, 118, 98, 94, 126, 198,
244, 76, 66, 233, 166, 58, 54, 32, 255, 255,
255, 255, 255, 255, 255, 255
};
private static string s_DECIMAL1024 = "179769313486231590770839156793787453197860296048756011706444423684197180216158519368947833795864925541502180565485980503646440548199239100050792877003355816639229553136239076508735759914822574862575007425302077447712589550957937778424442426617334727629299387668709205606050270810842907692932019128194";
private static byte[] s_OAKLEY1024 = new byte[128]
{
255, 255, 255, 255, 255, 255, 255, 255, 201, 15,
218, 162, 33, 104, 194, 52, 196, 198, 98, 139,
128, 220, 28, 209, 41, 2, 78, 8, 138, 103,
204, 116, 2, 11, 190, 166, 59, 19, 155, 34,
81, 74, 8, 121, 142, 52, 4, 221, 239, 149,
25, 179, 205, 58, 67, 27, 48, 43, 10, 109,
242, 95, 20, 55, 79, 225, 53, 109, 109, 81,
194, 69, 228, 133, 181, 118, 98, 94, 126, 198,
244, 76, 66, 233, 166, 55, 237, 107, 11, 255,
92, 182, 244, 6, 183, 237, 238, 56, 107, 251,
90, 137, 159, 165, 174, 159, 36, 17, 124, 75,
31, 230, 73, 40, 102, 81, 236, 230, 83, 129,
255, 255, 255, 255, 255, 255, 255, 255
};
private static string s_DECIMAL1536 = "2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919";
private static byte[] s_OAKLEY1536 = new byte[192]
{
255, 255, 255, 255, 255, 255, 255, 255, 201, 15,
218, 162, 33, 104, 194, 52, 196, 198, 98, 139,
128, 220, 28, 209, 41, 2, 78, 8, 138, 103,
204, 116, 2, 11, 190, 166, 59, 19, 155, 34,
81, 74, 8, 121, 142, 52, 4, 221, 239, 149,
25, 179, 205, 58, 67, 27, 48, 43, 10, 109,
242, 95, 20, 55, 79, 225, 53, 109, 109, 81,
194, 69, 228, 133, 181, 118, 98, 94, 126, 198,
244, 76, 66, 233, 166, 55, 237, 107, 11, 255,
92, 182, 244, 6, 183, 237, 238, 56, 107, 251,
90, 137, 159, 165, 174, 159, 36, 17, 124, 75,
31, 230, 73, 40, 102, 81, 236, 228, 91, 61,
194, 0, 124, 184, 161, 99, 191, 5, 152, 218,
72, 54, 28, 85, 211, 154, 105, 22, 63, 168,
253, 36, 207, 95, 131, 101, 93, 35, 220, 163,
173, 150, 28, 98, 243, 86, 32, 133, 82, 187,
158, 213, 41, 7, 112, 150, 150, 109, 103, 12,
53, 78, 74, 188, 152, 4, 241, 116, 108, 8,
202, 35, 115, 39, 255, 255, 255, 255, 255, 255,
255, 255
};
public string DH_passphrase
{
get
{
return m_SysAuthPassphrase;
}
set
{
ResetToDefaults();
m_SysAuthPassphrase = value;
ASBSolutionValid = true;
}
}
public byte[] DH_certificate => m_SysAuthCertificate;
public SysAuthParameters(string asbSolutionName = null)
{
SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 0, "SysAuthParameters constructor with asbSolutionName = {0}", string.IsNullOrEmpty(asbSolutionName) ? "<null>" : asbSolutionName);
ASBSolutionName = asbSolutionName;
ASBSolutionValid = false;
ResetToDefaults();
LoadASBSolution();
}
public void ResetToDefaults()
{
ASBSolutionValid = false;
DH_KeySize = DH_KeySize_Dft;
DH_SecretSize = DH_SecretSize_Dft;
m_SysAuthPassphrase = DH_passphrase_Dft;
m_SysAuthCertificate = null;
ConnectionLifetime = ConnectionLifetime_Dft;
SaltValue = SaltValue_Dft;
hashAlgorithm = hashAlgorithm_Dft;
PasswordIterations = PasswordIterations_Dft;
InitialVector = InitialVector_Dft;
KeySize = KeySize_Dft;
GenerateKey();
}
private void LoadASBSolution()
{
SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 0, "LoadASBSolution entry");
try
{
if (string.IsNullOrEmpty(ASBSolutionName))
{
ASBSolutionName = SvcUtilities.ReadKeyValue(string.Empty, "DefaultASBSolution");
if (string.IsNullOrEmpty(ASBSolutionName))
{
SvcTrace.DiagException.TraceEvent(TraceEventType.Error, 0, "LoadASBSolution: Unable to get default ASB solution name");
ASBSolutionValid = false;
}
SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 0, "LoadASBSolution created with empty solution name, resetting to default '{0}'", string.IsNullOrEmpty(ASBSolutionName) ? "<null>" : ASBSolutionName);
}
ASBSolutionValid = false;
if (!string.IsNullOrEmpty(ASBSolutionName))
{
SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 0, "LoadASBSolution: Using solution {0}", ASBSolutionName);
if (string.IsNullOrEmpty(RegistryHandler.GetSolutionPassphrase(ASBSolutionName, out var passphrase)) && !string.IsNullOrEmpty(passphrase))
{
DH_passphrase = passphrase;
}
if ((passphrase = SvcUtilities.ReadKeyValue(RegKeyRelativePath + ASBSolutionName, "Certificate")) != null)
{
m_SysAuthCertificate = Encoding.UTF8.GetBytes(passphrase);
}
if ((passphrase = SvcUtilities.ReadKeyValue(RegKeyRelativePath + ASBSolutionName, "saltValue")) != null)
{
SaltValue = passphrase;
}
if ((passphrase = SvcUtilities.ReadKeyValue(RegKeyRelativePath + ASBSolutionName, "HashAlgorthim")) != null)
{
hashAlgorithm = passphrase;
}
SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 0, "LoadASBSolution: Using hashAlgorithm {0}", hashAlgorithm);
if ((passphrase = SvcUtilities.ReadKeyValue(RegKeyRelativePath + ASBSolutionName, "passowordIterations")) != null)
{
PasswordIterations = int.Parse(passphrase);
}
if ((passphrase = SvcUtilities.ReadKeyValue(RegKeyRelativePath + ASBSolutionName, "initailizationVector")) != null)
{
InitialVector = passphrase;
}
if ((passphrase = SvcUtilities.ReadKeyValue(RegKeyRelativePath + ASBSolutionName, "keySize")) != null)
{
int.TryParse(passphrase, out KeySize);
}
if ((passphrase = SvcUtilities.ReadKeyValue(RegKeyRelativePath + ASBSolutionName, "Prime")) != null)
{
BigInteger.TryParse(passphrase, out DH_p);
}
if ((passphrase = SvcUtilities.ReadKeyValue(RegKeyRelativePath + ASBSolutionName, "Generator")) != null)
{
BigInteger.TryParse(passphrase, out DH_g);
}
ASBSolutionValid = true;
}
}
catch (Exception ex)
{
SvcTrace.DiagException.TraceEvent(TraceEventType.Error, 0, "LoadASBSolution: Exception caught: {0}", ex.Message);
ASBSolutionValid = false;
}
}
private void GenerateKey()
{
if (DH_KeySize == 768)
{
BigInteger.TryParse(s_DECIMAL768, out DH_p);
}
else if (DH_KeySize == 1024)
{
BigInteger.TryParse(s_DECIMAL1024, out DH_p);
}
else
{
if (DH_KeySize != 1536)
{
throw new ArgumentException("Invalid bit size.");
}
BigInteger.TryParse(s_DECIMAL1536, out DH_p);
}
DH_g = new BigInteger(22);
}
}
@@ -0,0 +1,120 @@
#define TRACE
using System;
using System.Diagnostics;
using System.Numerics;
using System.Security.Cryptography;
using System.Text;
using ArchestrAServices.Common;
namespace ArchestrAServices.ASBContract;
public class SysAuthServiceAuthentication : SysAuthConnectionBase
{
private RNGCryptoServiceProvider m_Random = new RNGCryptoServiceProvider();
public BigInteger ClientPublicKey { get; private set; }
public BigInteger ServicePrivateKey { get; private set; }
public BigInteger ServicePublicKey { get; private set; }
public ulong Lifetime { get; private set; }
public SysAuthServiceAuthentication()
{
Reset();
Lifetime = 18000000uL;
}
[CLSCompliant(false)]
public static ConnectResponse ProcessClientConnection(ConnectRequest request)
{
SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 100, "SysSvcAuth: Processing client Connect() call '{0}'", request.ConnectionId.ToString());
ConnectResponse connectResponse = null;
if (request != null && request.ConsumerPublicKey != null && request.ConsumerPublicKey.Data != null)
{
SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 100, "SysSvcAuth: Validated request message, processing");
SysAuthServiceAuthentication sysAuthServiceAuthentication = new SysAuthServiceAuthentication();
sysAuthServiceAuthentication.connectionID = request.ConnectionId;
sysAuthServiceAuthentication.m_RemotePublicKey = request.ConsumerPublicKey.Data;
SysAuthenticatorServiceCache.AddServiceAuthenticator(sysAuthServiceAuthentication);
SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 100, "SysSvcAuth: Added authenticator for connection, captured client public key");
PublicKey servicePublicKey = new PublicKey
{
Data = sysAuthServiceAuthentication.m_LocalPublicKey
};
SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 100, "SysSvcAuth: Established service public key to return");
byte[] initializationVector;
AuthenticationData serviceAuthenticationData = new AuthenticationData
{
Data = sysAuthServiceAuthentication.CalculateAuthenticationData(sysAuthServiceAuthentication.m_LocalPublicKey, sysAuthServiceAuthentication.m_RemotePublicKey, out initializationVector),
InitializationVector = initializationVector
};
SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 100, "SysSvcAuth: Calculated authentication data to return");
ArchestrAResult result = ResultFactory.MakeGoodResult();
sysAuthServiceAuthentication.Lifetime = sysAuthServiceAuthentication.m_SolutionParameters.ConnectionLifetime;
connectResponse = new ConnectResponse(servicePublicKey, serviceAuthenticationData, sysAuthServiceAuthentication.Lifetime + ":" + SysAuthConnectionBase.ASBAuthenticationVersion);
connectResponse.Result = result;
sysAuthServiceAuthentication.SignatureMethod = SigningMethod.Baktun;
sysAuthServiceAuthentication.Sign(connectResponse, ForceHmac: true);
sysAuthServiceAuthentication.SignatureMethod = SigningMethod.Apollo;
sysAuthServiceAuthentication.ReasonSecureSessionNotEstablished = string.Empty;
SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 100, "SysSvcAuth: Signed Connect response message");
}
return connectResponse;
}
[CLSCompliant(false)]
public bool ProcessClientAuthenticateMe(AuthenticateMe request)
{
SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 100, "SysSvcAuth: Processing client AuthenticateMe() call for connection id {0}", connectionID.ToString());
base.SignatureMethod = SigningMethod.Apollo;
if (!ValidRequest(request, ForceHmac: true))
{
base.SignatureMethod = SigningMethod.Baktun;
if (!ValidRequest(request, ForceHmac: true))
{
return false;
}
}
SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 100, "SysSvcAuth: AuthenticateMe() validated, signing set to {0}", (base.SignatureMethod == SigningMethod.Baktun) ? "System Platform 2012R2 Comptibility" : "System Platform 2014 Compatibility");
AuthenticationData consumerAuthenticationData = request.ConsumerAuthenticationData;
if (consumerAuthenticationData != null)
{
byte[] expected = ReCalculateAuthenticationData(m_RemotePublicKey, m_LocalPublicKey, consumerAuthenticationData.InitializationVector);
if (consumerAuthenticationData.AreEqual(expected))
{
SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 100, "SysSvcAuth: AuthenticateMe() authenticated client");
m_Authenticated = true;
}
}
return m_Authenticated;
}
[CLSCompliant(false)]
public static RenewResponse ProcessClientRenew(RenewRequest request)
{
SysAuthenticatorServiceCache.GetServiceAuthenticator(request.ConnectionValidator.ConnectionId)?.ValidRequest(request);
return null;
}
[CLSCompliant(false)]
public static void ProcessClientUpdateSystemAuthenticationConfiguration(UpdateSystemAuthenticationConfiguration request)
{
SysAuthenticatorServiceCache.GetServiceAuthenticator(request.ConnectionValidator.ConnectionId)?.ValidRequest(request);
}
[CLSCompliant(false)]
public void ProcessClientDisconnect(Disconnect request)
{
AuthenticationData consumerAuthenticationData = request.ConsumerAuthenticationData;
if (consumerAuthenticationData != null)
{
byte[] bytes = Decypher(consumerAuthenticationData.Data, consumerAuthenticationData.InitializationVector);
if (Guid.TryParse(Encoding.UTF8.GetString(bytes), out var result) && result == connectionID)
{
SysAuthenticatorServiceCache.RemoveServiceAuthenticator(result);
}
}
}
}
@@ -0,0 +1,85 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace ArchestrAServices.ASBContract;
public class SysAuthenticatorClientCache : SynchronizedKeyedCollection<Guid, SysAuthClientAuthentication>
{
private static readonly SysAuthenticatorClientCache clientConnections = new SysAuthenticatorClientCache();
private static object cacheLockObject = new object();
private SysAuthenticatorClientCache()
{
}
public static IEnumerable<SysAuthClientAuthentication> GetAllClientAuthenticators()
{
List<SysAuthClientAuthentication> list = new List<SysAuthClientAuthentication>();
lock (cacheLockObject)
{
list.AddRange(clientConnections.Items);
return list;
}
}
public static void AddClientAuthenticator(SysAuthClientAuthentication clientAuthenticator)
{
lock (cacheLockObject)
{
clientConnections.Purge();
}
if (clientAuthenticator == null)
{
return;
}
lock (cacheLockObject)
{
if (!clientConnections.Contains(clientAuthenticator.connectionID))
{
clientConnections.Add(clientAuthenticator);
}
}
}
public static SysAuthClientAuthentication GetClientAuthenticator(Guid connectionId)
{
SysAuthClientAuthentication result = null;
lock (cacheLockObject)
{
if (clientConnections.Contains(connectionId))
{
result = clientConnections[connectionId];
}
}
return result;
}
public static SysAuthClientAuthentication RemoveClientAuthenticator(Guid connectionId)
{
SysAuthClientAuthentication result = GetClientAuthenticator(connectionId);
lock (cacheLockObject)
{
if (clientConnections.Contains(connectionId))
{
result = clientConnections[connectionId];
clientConnections.Remove(connectionId);
}
}
return result;
}
protected void Purge()
{
foreach (Guid item in this.Where((SysAuthClientAuthentication item) => !item.IsOwnerAlive).Select(GetKeyForItem).ToList())
{
Remove(item);
}
}
protected override Guid GetKeyForItem(SysAuthClientAuthentication item)
{
return item.connectionID;
}
}
@@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
namespace ArchestrAServices.ASBContract;
public class SysAuthenticatorServiceCache : SynchronizedKeyedCollection<Guid, SysAuthServiceAuthentication>
{
private static readonly SysAuthenticatorServiceCache serviceConnections = new SysAuthenticatorServiceCache();
private static object ServiceCacheLockObject = new object();
private SysAuthenticatorServiceCache()
{
}
public static IEnumerable<SysAuthServiceAuthentication> GetAllServiceAuthenticators()
{
List<SysAuthServiceAuthentication> list = new List<SysAuthServiceAuthentication>();
lock (ServiceCacheLockObject)
{
list.AddRange(serviceConnections.Items);
return list;
}
}
public static void AddServiceAuthenticator(SysAuthServiceAuthentication serviceAuthenticator)
{
if (serviceAuthenticator == null)
{
return;
}
lock (ServiceCacheLockObject)
{
if (!serviceConnections.Contains(serviceAuthenticator.connectionID))
{
serviceConnections.Add(serviceAuthenticator);
}
}
}
public static SysAuthServiceAuthentication GetServiceAuthenticator(Guid connectionId)
{
SysAuthServiceAuthentication result = null;
lock (ServiceCacheLockObject)
{
if (serviceConnections.Contains(connectionId))
{
result = serviceConnections[connectionId];
}
}
return result;
}
public static SysAuthServiceAuthentication RemoveServiceAuthenticator(Guid connectionId)
{
SysAuthServiceAuthentication serviceAuthenticator = GetServiceAuthenticator(connectionId);
if (serviceAuthenticator != null)
{
lock (ServiceCacheLockObject)
{
serviceConnections.Remove(connectionId);
}
}
return serviceAuthenticator;
}
protected override Guid GetKeyForItem(SysAuthServiceAuthentication item)
{
return item.connectionID;
}
}
@@ -0,0 +1,31 @@
using System.CodeDom.Compiler;
using System.ComponentModel;
using System.Diagnostics;
using System.ServiceModel;
using System.Xml.Serialization;
namespace ArchestrAServices.ASBContract;
[DebuggerStepThrough]
[GeneratedCode("System.ServiceModel", "4.0.0.0")]
[EditorBrowsable(EditorBrowsableState.Advanced)]
[MessageContract(WrapperName = "UpdateSystemAuthenticationConfigurationRequest", WrapperNamespace = "http://asb.contracts.messages/20111111", IsWrapped = true)]
public class UpdateSystemAuthenticationConfiguration : ConnectedRequest
{
[MessageBodyMember(Namespace = "http://asb.contracts.messages/20111111", Order = 0)]
public string EncryptedConfigurationData;
[MessageBodyMember(Namespace = "http://asb.contracts.messages/20111111", Order = 1)]
[XmlElement(DataType = "base64Binary")]
public byte[] InitializationVector;
public UpdateSystemAuthenticationConfiguration()
{
}
public UpdateSystemAuthenticationConfiguration(string EncryptedConfigurationData, byte[] InitializationVector)
{
this.EncryptedConfigurationData = EncryptedConfigurationData;
this.InitializationVector = InitializationVector;
}
}
@@ -0,0 +1,39 @@
using System;
using System.Xml.Serialization;
namespace Asb.Base.V2.ContractTypes;
[Serializable]
[XmlType(Namespace = "urn:data.asb.se:2")]
public class UserTokenContract
{
[XmlElement(IsNullable = true, ElementName = "Encryption", Order = 0)]
public ushort? Encryption { get; set; }
[XmlElement(IsNullable = true, ElementName = "HostName", Order = 1)]
public string HostName { get; set; }
[XmlElement(IsNullable = true, ElementName = "IdType", Order = 2)]
public ushort? IdType { get; set; }
[XmlElement(IsNullable = true, ElementName = "LocationId", Order = 3)]
public string LocationId { get; set; }
[XmlElement(IsNullable = true, ElementName = "UserName", Order = 4)]
public string UserName { get; set; }
[XmlElement(DataType = "base64Binary", IsNullable = true, ElementName = "Password", Order = 5)]
public byte[] Password { get; set; }
[XmlElement(IsNullable = true, ElementName = "Validity", Order = 6)]
public ushort? Validity { get; set; }
[XmlElement(DataType = "base64Binary", IsNullable = true, ElementName = "SamlToken", Order = 7)]
public byte[] SamlToken { get; set; }
[XmlElement(DataType = "base64Binary", IsNullable = true, ElementName = "JwtToken", Order = 8)]
public byte[] JwtToken { get; set; }
[XmlElement(DataType = "base64Binary", IsNullable = true, ElementName = "X509Certificate", Order = 9)]
public byte[] X509Certificate { get; set; }
}
@@ -0,0 +1,122 @@
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Xml;
namespace Asb.Base.V2.Serialization;
public sealed class BaseV2Serializer : XmlObjectSerializer
{
private const string BaseV2Prefix = "ASBBaseV2";
private readonly Type elementType;
private readonly bool useCustomSerialization;
private readonly XmlObjectSerializer fallbackSerializer;
public BaseV2Serializer(Type type, XmlObjectSerializer fallbackSerializer)
{
this.fallbackSerializer = fallbackSerializer;
elementType = type;
if (!(type == null))
{
Type c = (type.IsArray ? type.GetElementType() : type);
useCustomSerialization = typeof(IBaseV2CustomSerializable).IsAssignableFrom(c);
}
}
public override bool IsStartObject(XmlDictionaryReader reader)
{
if (useCustomSerialization)
{
return string.Compare(reader.LocalName, "ASBBaseV2", StringComparison.CurrentCultureIgnoreCase) == 0;
}
return fallbackSerializer.IsStartObject(reader);
}
public override object ReadObject(XmlDictionaryReader reader, bool verifyObjectName)
{
if (useCustomSerialization)
{
using MemoryStream input = new MemoryStream(reader.ReadElementContentAsBase64());
using BinaryReader binaryReader = new BinaryReader(input);
if (binaryReader.ReadBoolean())
{
return null;
}
if (Activator.CreateInstance(elementType.IsArray ? elementType.GetElementType() : elementType) is IBaseV2CustomSerializable baseV2CustomSerializable)
{
if (elementType.IsArray)
{
int arrayLength = binaryReader.ReadInt32();
return baseV2CustomSerializable.InitializeArrayFromStream(binaryReader, arrayLength);
}
baseV2CustomSerializable.InitializeFromStream(binaryReader);
return baseV2CustomSerializable;
}
}
return fallbackSerializer.ReadObject(reader, verifyObjectName);
}
public override void WriteEndObject(XmlDictionaryWriter writer)
{
if (useCustomSerialization)
{
writer.WriteEndElement();
}
else
{
fallbackSerializer.WriteEndObject(writer);
}
}
public override void WriteObjectContent(XmlDictionaryWriter writer, object graph)
{
bool flag = false;
if (useCustomSerialization)
{
using MemoryStream memoryStream = new MemoryStream();
using BinaryWriter binaryWriter = new BinaryWriter(memoryStream);
binaryWriter.Write(graph == null);
if (graph == null)
{
flag = true;
}
else if (elementType.IsArray)
{
if (Activator.CreateInstance(elementType.GetElementType()) is IBaseV2CustomSerializable baseV2CustomSerializable)
{
baseV2CustomSerializable.WriteArrayToStream(graph, binaryWriter);
flag = true;
}
}
else if (graph is IBaseV2CustomSerializable baseV2CustomSerializable2)
{
baseV2CustomSerializable2.WriteToStream(binaryWriter);
flag = true;
}
if (flag)
{
byte[] array = memoryStream.ToArray();
writer.WriteBase64(array, 0, array.Length);
}
}
if (!flag)
{
fallbackSerializer.WriteObjectContent(writer, graph);
}
}
public override void WriteStartObject(XmlDictionaryWriter writer, object graph)
{
if (useCustomSerialization)
{
writer.WriteStartElement("ASBBaseV2");
}
else
{
fallbackSerializer.WriteStartObject(writer, graph);
}
}
}
@@ -0,0 +1,79 @@
using System;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
namespace Asb.Base.V2.Serialization;
public sealed class BaseV2SerializerContractBehaviorAttribute : Attribute, IContractBehavior
{
public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
ReplaceSerializerOperationBehavior(contractDescription);
}
public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
{
ReplaceSerializerOperationBehavior(contractDescription);
}
public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
{
foreach (OperationDescription operation in contractDescription.Operations)
{
foreach (MessageDescription message in operation.Messages)
{
ValidateMessagePartDescription(message.Body.ReturnValue);
foreach (MessagePartDescription part in message.Body.Parts)
{
ValidateMessagePartDescription(part);
}
foreach (MessageHeaderDescription header in message.Headers)
{
ValidateCustomSerializableType(header.Type);
}
}
}
}
private static void ValidateMessagePartDescription(MessagePartDescription part)
{
if (part != null)
{
ValidateCustomSerializableType(part.Type);
}
}
private static void ValidateCustomSerializableType(Type type)
{
if (typeof(IBaseV2CustomSerializable).IsAssignableFrom(type))
{
if (!type.IsPublic)
{
throw new InvalidOperationException("Custom serialization is supported in public types only");
}
if (type.IsClass && type.GetConstructor(new Type[0]) == null)
{
throw new InvalidOperationException("Custom serializable types must have a public, parameterless constructor");
}
}
}
private static void ReplaceSerializerOperationBehavior(ContractDescription contract)
{
foreach (OperationDescription operation in contract.Operations)
{
for (int i = 0; i < operation.Behaviors.Count; i++)
{
if (operation.Behaviors[i] is DataContractSerializerOperationBehavior)
{
operation.Behaviors[i] = new BaseV2SerializerOperationBehavior(operation);
}
}
}
}
}
@@ -0,0 +1,30 @@
#define TRACE
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.Serialization;
using System.ServiceModel.Description;
using System.Xml;
using ArchestrAServices.Common;
namespace Asb.Base.V2.Serialization;
public class BaseV2SerializerOperationBehavior : DataContractSerializerOperationBehavior
{
public BaseV2SerializerOperationBehavior(OperationDescription operation)
: base(operation)
{
}
public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes)
{
SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 0, "BaseV2SerializerOperationBehavior:CreateSerializer-creating an instance for BaseV2Serializer class");
return new BaseV2Serializer(type, base.CreateSerializer(type, name, ns, knownTypes));
}
public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes)
{
SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 0, "BaseV2SerializerOperationBehavior:CreateSerializer-creating an instance for BaseV2Serializer class");
return new BaseV2Serializer(type, base.CreateSerializer(type, name, ns, knownTypes));
}
}
@@ -0,0 +1,14 @@
using System.IO;
namespace Asb.Base.V2.Serialization;
public interface IBaseV2CustomSerializable
{
void WriteToStream(BinaryWriter writer);
void InitializeFromStream(BinaryReader reader);
void WriteArrayToStream(object graph, BinaryWriter writer);
object InitializeArrayFromStream(BinaryReader reader, int arrayLength);
}
@@ -0,0 +1,33 @@
using System;
using System.IO;
namespace Asb.Base.V2.Serialization;
public static class SerializationExtensions
{
public static void WriteStringSafe(this BinaryWriter writer, string value)
{
if (writer == null)
{
throw new ArgumentNullException("writer");
}
writer.Write(value == null);
if (value != null)
{
writer.Write(value);
}
}
public static string ReadStringSafe(this BinaryReader reader)
{
if (reader == null)
{
throw new ArgumentNullException("reader");
}
if (!reader.ReadBoolean())
{
return reader.ReadString();
}
return null;
}
}
@@ -0,0 +1,43 @@
namespace Asb.Base.V2;
public enum ArchestrAError
{
Success = 0,
InvalidConnectionId = 1,
ApplicationAuthenticationError = 2,
UserAuthenticationError = 3,
UserAuthorizationError = 4,
NotSupportedOperation = 5,
MonitoredItemsNotFound = 6,
InvalidSubscriptionId = 7,
ItemAlreadyRegistered = 8,
ItemAlreadyDeletedOrDoesNotExist = 9,
InvalidMonitoredItems = 10,
OperationFailed = 11,
SpecificError = 12,
BadNoCommunication = 13,
BadNothingToDo = 14,
BadTooManyOperations = 15,
BadNodeIdInvalid = 16,
BrowseFailed = 17,
WriteFailedBadOutOfRange = 18,
WriteFailedBadTypeMismatch = 19,
WriteFailedBadDimensionMismatch = 20,
WriteFailedAccessDenied = 21,
WriteFailedSecuredWrite = 22,
WriteFailedVerifiedWrite = 23,
IndexOutOfRange = 24,
RequestTimedOut = 25,
DataTypeConversionNotSupported = 26,
ItemCannotBeRegisteredNoName = 27,
ItemCannotBeRegisteredNoId = 28,
ItemAlreadyBeingMonitored = 29,
SubscriptionIdAlreadyExist = 30,
OperationWouldBlock = 31,
PublishComplete = 32,
WriteFailedUserNotHavingAccessRights = 33,
WriteFailedVerifierNotHavingVerifyRights = 34,
NotLicensedError = 35,
DownstreamDeviceUnavailable = 36,
Unknown = 65535
}
@@ -0,0 +1,130 @@
using System;
using System.Xml.Serialization;
namespace Asb.Base.V2;
[Serializable]
[XmlType(Namespace = "urn:data.asb.se:2")]
public class ArchestrAResult
{
[XmlElement(ElementName = "Success", Order = 0)]
public bool Success { get; set; }
[XmlElement(ElementName = "ResultCode", Order = 1)]
public int ResultCode { get; set; }
[XmlElement(ElementName = "SpecificErrorCode", Order = 2)]
public uint SpecificErrorCode { get; set; }
[XmlElement(ElementName = "Status", Order = 3)]
public uint Status { get; set; }
[XmlElement(ElementName = "Location", Order = 4)]
public string Location { get; set; }
[XmlElement(ElementName = "SuccessMessages", Order = 5)]
public string[] SuccessMessages { get; set; }
[XmlElement(ElementName = "InformationMessages", Order = 6)]
public string[] InformationMessages { get; set; }
[XmlElement(ElementName = "ErrorMessages", Order = 7)]
public string[] ErrorMessages { get; set; }
[XmlElement(ElementName = "Extensions", Order = 8)]
public NamedValue[] Extensions { get; set; }
[XmlIgnore]
public static bool CollectStackTraceInExceptions { get; set; }
[XmlIgnore]
public ArchestrAError ResultCodeAsError
{
get
{
if (ResultCode < 65535)
{
return (ArchestrAError)ResultCode;
}
return ArchestrAError.Unknown;
}
set
{
ResultCode = (int)value;
}
}
public static ArchestrAResult Create(ArchestrAResult archestraResult)
{
ArchestrAResult archestrAResult = archestraResult;
if (archestrAResult == null)
{
archestrAResult = new ArchestrAResult
{
Success = true,
ErrorMessages = new string[0],
InformationMessages = new string[0],
SuccessMessages = new string[0],
Extensions = new NamedValue[0],
ResultCode = 0
};
}
return archestrAResult;
}
public static ArchestrAResult MakeGoodResult()
{
return new ArchestrAResult
{
ResultCodeAsError = ArchestrAError.Success,
Status = 0u,
SpecificErrorCode = 0u,
Success = true
};
}
public static ArchestrAResult MakeResult(ArchestrAError error, ushort status)
{
return new ArchestrAResult
{
ResultCodeAsError = error,
Status = status,
Success = (error == ArchestrAError.Success)
};
}
public static ArchestrAResult MakeResult(ArchestrAError error, ushort status, uint specificError)
{
return new ArchestrAResult
{
ResultCodeAsError = error,
Status = status,
SpecificErrorCode = specificError,
Success = (error == ArchestrAError.Success)
};
}
public static ArchestrAResult MakeErrorResult(string message)
{
if (string.IsNullOrWhiteSpace(message))
{
throw new ArgumentNullException("message");
}
return MakeResult(ArchestrAError.Unknown, 0, 0u).AddErrorMessage(message);
}
public static ArchestrAResult MakeErrorResult(ArchestrAError error, string message)
{
if (string.IsNullOrWhiteSpace(message))
{
throw new ArgumentNullException("message");
}
return MakeResult(ArchestrAError.Unknown, 0, 0u).AddErrorMessage(message);
}
public static ArchestrAResult MakeNotLicensedResult(string message)
{
string message2 = (string.IsNullOrWhiteSpace(message) ? "The requested connection is not licensed for the operation and will be terminated" : message);
return MakeResult(ArchestrAError.NotLicensedError, 0, 0u).AddErrorMessage(message2);
}
}
@@ -0,0 +1,258 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Text;
namespace Asb.Base.V2;
public static class ArchestrAResultExtensions
{
public static ArchestrAResult AddSuccessMessage(this ArchestrAResult result, [Localizable(false)] string message, params object[] arguments)
{
if (result == null)
{
return null;
}
result.AddSuccessMessage(FormatMessage(message, arguments));
return result;
}
public static ArchestrAResult AddSuccessMessage(this ArchestrAResult result, [Localizable(false)] string message)
{
if (result == null)
{
return null;
}
if (string.IsNullOrEmpty(message))
{
return result;
}
if (result.SuccessMessages == null)
{
result.SuccessMessages = new string[0];
}
List<string> list = result.SuccessMessages.ToList();
list.Add(message);
result.SuccessMessages = list.ToArray();
return result;
}
public static ArchestrAResult AddInformationMessage(this ArchestrAResult result, [Localizable(false)] string message, params object[] arguments)
{
if (result == null)
{
return null;
}
result.AddInformationMessage(FormatMessage(message, arguments));
return result;
}
public static ArchestrAResult AddInformationMessage(this ArchestrAResult result, [Localizable(false)] string message)
{
if (result == null)
{
return null;
}
if (string.IsNullOrEmpty(message))
{
return result;
}
if (result.InformationMessages == null)
{
result.InformationMessages = new string[0];
}
List<string> list = result.InformationMessages.ToList();
list.Add(message);
result.InformationMessages = list.ToArray();
return result;
}
public static ArchestrAResult AddErrorMessage(this ArchestrAResult result, [Localizable(false)] string message, params object[] arguments)
{
if (result == null)
{
return null;
}
result.AddErrorMessage(FormatMessage(message, arguments));
return result;
}
public static ArchestrAResult AddErrorMessage(this ArchestrAResult result, [Localizable(false)] string message)
{
if (result == null)
{
return null;
}
if (string.IsNullOrEmpty(message))
{
return result;
}
if (result.ErrorMessages == null)
{
result.ErrorMessages = new string[0];
}
List<string> list = result.ErrorMessages.ToList();
list.Add(message);
result.ErrorMessages = list.ToArray();
return result;
}
public static ArchestrAResult AddErrorMessages(this ArchestrAResult result, IEnumerable<string> messages)
{
if (result == null)
{
return null;
}
if (messages == null)
{
return result;
}
if (result.ErrorMessages == null)
{
result.ErrorMessages = new string[0];
}
List<string> list = result.ErrorMessages.ToList();
list.AddRange(messages);
result.ErrorMessages = list.ToArray();
return result;
}
public static ArchestrAResult AddExtension(this ArchestrAResult result, NamedValue extension)
{
if (result == null)
{
return null;
}
if (extension == null)
{
return result;
}
if (result.Extensions == null)
{
result.Extensions = new NamedValue[0];
}
List<NamedValue> list = result.Extensions.ToList();
list.Add(extension);
result.Extensions = list.ToArray();
return result;
}
public static ArchestrAResult AddExtension(this ArchestrAResult result, [Localizable(false)] string name, object value)
{
if (result == null)
{
return null;
}
if (result.Extensions == null)
{
result.Extensions = new NamedValue[0];
}
List<NamedValue> list = result.Extensions.ToList();
list.Add(new NamedValue
{
Name = name,
Value = Value.Create(value)
});
result.Extensions = list.ToArray();
return result;
}
public static ArchestrAResult Concatenate(this ArchestrAResult thisResult, ArchestrAResult result)
{
if (thisResult == null)
{
return null;
}
if (result != null)
{
if (!result.Success)
{
thisResult.Success = false;
}
if (result.ErrorMessages != null)
{
if (thisResult.ErrorMessages == null)
{
thisResult.ErrorMessages = new string[0];
}
List<string> list = thisResult.ErrorMessages.ToList();
list.AddRange(result.ErrorMessages);
thisResult.ErrorMessages = list.ToArray();
}
if (result.InformationMessages != null)
{
if (thisResult.InformationMessages == null)
{
thisResult.InformationMessages = new string[0];
}
List<string> list2 = thisResult.InformationMessages.ToList();
list2.AddRange(result.InformationMessages);
thisResult.ErrorMessages = list2.ToArray();
}
if (result.SuccessMessages != null)
{
if (thisResult.SuccessMessages == null)
{
thisResult.SuccessMessages = new string[0];
}
List<string> list3 = thisResult.SuccessMessages.ToList();
list3.AddRange(result.SuccessMessages);
thisResult.SuccessMessages = list3.ToArray();
}
if (result.Extensions != null)
{
if (thisResult.Extensions == null)
{
thisResult.Extensions = new NamedValue[0];
}
List<NamedValue> list4 = thisResult.Extensions.ToList();
list4.AddRange(result.Extensions);
thisResult.Extensions = list4.ToArray();
}
if (thisResult.ResultCode == 0)
{
thisResult.ResultCode = result.ResultCode;
}
}
return result;
}
public static string ToFormattedString(this ArchestrAResult result)
{
if (result == null)
{
return null;
}
StringBuilder stringBuilder = new StringBuilder();
if (result.Success)
{
stringBuilder.Append("Success");
if (result.SuccessMessages != null && result.SuccessMessages.Length != 0)
{
stringBuilder.Append(": ");
stringBuilder.Append(string.Join("| ", result.SuccessMessages));
}
}
else
{
stringBuilder.Append("Failure");
if (result.ErrorMessages != null && result.ErrorMessages.Length != 0)
{
stringBuilder.Append(": ");
stringBuilder.Append(string.Join("| ", result.ErrorMessages));
}
}
return stringBuilder.ToString();
}
private static string FormatMessage([Localizable(false)] string message, params object[] arguments)
{
string result = message;
if (arguments != null && arguments.Length != 0)
{
result = string.Format(CultureInfo.CurrentCulture, message, arguments);
}
return result;
}
}
@@ -0,0 +1,27 @@
using System.ServiceModel;
using System.Xml.Serialization;
namespace Asb.Base.V2;
[MessageContract(WrapperName = "AuthenticateMe", WrapperNamespace = "urn:msg.asb.se:2", IsWrapped = true)]
[XmlRoot(Namespace = "urn:msg.asb.se:2")]
public class AuthenticateMeRequest : ConnectedRequest
{
[MessageBodyMember(Namespace = "urn:msg.asb.se:2", Order = 0)]
[XmlElement(ElementName = "ConsumerAuthenticationData")]
public AuthenticationData ConsumerAuthenticationData { get; set; }
[MessageBodyMember(Namespace = "urn:msg.asb.se:2", Order = 1)]
[XmlElement(ElementName = "ConsumerMetaData")]
public ClientMetadata ConsumerMetaData { get; set; }
public AuthenticateMeRequest()
{
}
public AuthenticateMeRequest(AuthenticationData consumerAuthenticationData, ClientMetadata consumerMetaData)
{
ConsumerAuthenticationData = consumerAuthenticationData;
ConsumerMetaData = consumerMetaData;
}
}
@@ -0,0 +1,18 @@
using System.ServiceModel;
using System.Xml.Serialization;
namespace Asb.Base.V2;
[MessageContract(WrapperName = "AuthenticateMeResponse", WrapperNamespace = "urn:msg.asb.se:2", IsWrapped = true)]
[XmlRoot(Namespace = "urn:msg.asb.se:2")]
public class AuthenticateMeResponse : ConnectedResponse
{
public AuthenticateMeResponse()
{
}
public AuthenticateMeResponse(ArchestrAResult result, ConnectionState downstreamConnectionState)
: base(result, downstreamConnectionState)
{
}
}
@@ -0,0 +1,15 @@
using System;
using System.Xml.Serialization;
namespace Asb.Base.V2;
[Serializable]
[XmlType(Namespace = "urn:data.asb.se:2")]
public class AuthenticationData
{
[XmlElement(ElementName = "Data", DataType = "base64Binary", Order = 0)]
public byte[] Data { get; set; }
[XmlElement(ElementName = "InitializationVector", DataType = "base64Binary", Order = 1)]
public byte[] InitializationVector { get; set; }
}
@@ -0,0 +1,44 @@
namespace Asb.Base.V2;
public static class AuthenticationDataExtensions
{
public static bool AreEqual(this AuthenticationData value, AuthenticationData other)
{
try
{
if (value != null && value.Data != null && other != null && other.Data != null)
{
return value.AreEqual(other.Data);
}
}
catch
{
}
return false;
}
public static bool AreEqual(this AuthenticationData value, byte[] expected)
{
bool result = false;
try
{
if (value != null && value.Data != null && expected != null && value.Data.Length == expected.Length)
{
result = true;
for (int i = 0; i < value.Data.Length; i++)
{
if (value.Data[i] != expected[i])
{
result = false;
break;
}
}
}
}
catch
{
result = false;
}
return result;
}
}
@@ -0,0 +1,661 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Net;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Discovery;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using ArchestrAServices.Common;
using ArchestrAServices.Proxy;
using Asb.Base.V2.ContractTypes;
namespace Asb.Base.V2;
public class BaseV2Client<T> : IBaseV2, IDisposable where T : class, IAuthenticateAsb
{
private readonly object connectionLock = new object();
private readonly string connectionUser = string.Empty;
private readonly string connectionApplication = string.Empty;
private readonly TimeSpan timeToWaitForConnection = DefaultTimeToWaitForConnection;
private IClientManagement clientManager;
private long connectionInProgress;
private ConnectContext<T> successfulConnectionResult;
private ManualResetEvent connectionEstablishedEvent;
private bool disposed;
public static TimeSpan DefaultTimeToWaitForConnection => TimeSpan.FromSeconds(20.0);
public SecureCommunicationModes SecureCommunicationMode { get; set; }
public DateTime ServiceLoadTime { get; set; }
public bool Connected
{
get
{
if (successfulConnectionResult?.ServiceChannel != null)
{
return successfulConnectionResult.ServiceChannel.State == CommunicationState.Opened;
}
return false;
}
}
public CommunicationState State
{
get
{
if (successfulConnectionResult != null && successfulConnectionResult.ServiceChannel != null)
{
return successfulConnectionResult.ServiceChannel.State;
}
return CommunicationState.Closed;
}
}
public ConnectionState DownstreamConnectionState { get; protected set; }
internal ConnectContext<T> Context => successfulConnectionResult;
protected T ChannelClient => successfulConnectionResult.ServiceClient;
public Guid ConnectionId
{
get
{
if (successfulConnectionResult != null)
{
return successfulConnectionResult.ConnectionId;
}
return Guid.Empty;
}
set
{
}
}
public BaseV2Client()
{
clientManager = new ClientManagement();
SecureCommunicationMode = RegistryHandler.SecureCommunicationMode;
}
public BaseV2Client(TimeSpan connectTimeout)
: this()
{
if (connectTimeout.TotalMilliseconds > 2147483647.0 || connectTimeout < TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException("connectTimeout");
}
timeToWaitForConnection = connectTimeout;
}
internal BaseV2Client(TimeSpan connectTimeout, IClientManagement manager)
: this(manager)
{
if (connectTimeout.TotalMilliseconds > 2147483647.0 || connectTimeout < TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException("connectTimeout");
}
timeToWaitForConnection = connectTimeout;
}
internal BaseV2Client(TimeSpan connectTimeout, IClientManagement manager, string application, string user)
: this(connectTimeout, manager)
{
connectionApplication = application;
connectionUser = user;
}
public BaseV2Client(TimeSpan connectTimeout, string application, string user)
: this(connectTimeout)
{
connectionApplication = application;
connectionUser = user;
}
internal BaseV2Client(IClientManagement manager)
{
clientManager = manager;
SecureCommunicationMode = RegistryHandler.SecureCommunicationMode;
}
public bool Connect(EndpointDiscoveryMetadata selectedMetadata, string solutionName, ClientAccess access, Action<string> errorCallback)
{
return Connect(selectedMetadata, solutionName, access, errorCallback, useSecureConnection: false);
}
public bool Connect(EndpointDiscoveryMetadata selectedMetadata, string solutionName, ClientAccess access, Action<string> errorCallback, bool useSecureConnection)
{
ServiceTrace.LogCsv("Connect (endpoint discovered) entry");
ServiceTrace.LogResume("Connect (endpoint discovered) entry");
if (Interlocked.CompareExchange(ref connectionInProgress, 1L, 0L) != 0L)
{
string text = string.Format(CultureInfo.InvariantCulture, "Connect: another connection is in progress, cannot attempt a connection using selected discovery metadata");
ServiceTrace.LogError(text);
errorCallback?.Invoke(text);
return false;
}
try
{
bool flag = EstablishConnection(selectedMetadata, solutionName, access, errorCallback, useSecureConnection);
ServiceTrace.LogSuspend("Connect (endpoint discovered) exit, {0}", flag ? "succeeded" : "failed");
ServiceTrace.LogCsv("Connect (endpoint discovered) exit [success]", flag);
return flag;
}
finally
{
Interlocked.Exchange(ref connectionInProgress, 0L);
}
}
public void Disconnect()
{
ServiceTrace.LogCsv("Disconnect entry");
ServiceTrace.LogResume("Disconnect entry");
if (successfulConnectionResult == null || !successfulConnectionResult.Success)
{
return;
}
SystemAuthenticationClientAuthentication.DisconnectSecureSession(successfulConnectionResult.ConnectionId, delegate(DisconnectRequest request)
{
if (successfulConnectionResult != null && successfulConnectionResult.Success)
{
if (successfulConnectionResult.ServiceClient != null && successfulConnectionResult.ServiceChannel != null && successfulConnectionResult.ServiceChannel.State != CommunicationState.Faulted)
{
ServiceTrace.LogCsv("Calling WCF channel Disconnect method");
successfulConnectionResult.ServiceClient.Disconnect(request);
ServiceTrace.LogCsv("Returned from WCF channel Disconnect method");
}
Reset();
}
});
DownstreamConnectionState = ConnectionState.Unknown;
ServiceTrace.LogSuspend("Disconnect exit");
ServiceTrace.LogCsv("Disconnect exit");
}
public void Abort()
{
Reset();
}
internal void InjectClientManager(IClientManagement manager)
{
clientManager = manager;
}
protected static ReadOnlyCollection<EndpointDiscoveryMetadata> DiscoverEndpoints(XmlQualifiedName contract, string scopeRule)
{
return DiscoverEndpoints(contract, scopeRule, null);
}
protected static ReadOnlyCollection<EndpointDiscoveryMetadata> DiscoverEndpoints(XmlQualifiedName contract, string scopeRule, bool? useSecureConnection)
{
List<EndpointDiscoveryMetadata> list = new ClientManagement().DiscoverEndpointsForContract(contract, scopeRule)?.ToList();
if (list == null)
{
ServiceTrace.LogWarning(string.Format(CultureInfo.InvariantCulture, "DiscoverEndpoints: null FindResponse finding contract {0} with access name {1}", new object[2] { contract.Name, scopeRule }));
return new ReadOnlyCollection<EndpointDiscoveryMetadata>(new EndpointDiscoveryMetadata[0]);
}
if (list.Count == 0)
{
ServiceTrace.LogInfo(string.Format(CultureInfo.InvariantCulture, "DiscoverEndpoints found no endpoints for contract {0} with access name {1}", new object[2] { contract.Name, scopeRule }));
return new ReadOnlyCollection<EndpointDiscoveryMetadata>(new EndpointDiscoveryMetadata[0]);
}
return new ReadOnlyCollection<EndpointDiscoveryMetadata>(list);
}
protected bool Connect(XmlQualifiedName contract, string scopeRule, ClientAccess access, Action<string> errorCallback)
{
return Connect(contract, scopeRule, access, errorCallback, useSecureConnection: false);
}
protected bool Connect(XmlQualifiedName contract, string scopeRule, ClientAccess access, Action<string> errorCallback, bool useSecureConnection)
{
ServiceTrace.LogCsv("Connect (discover endpoint) entry");
ServiceTrace.LogResume("Connect (discover endpoint) entry");
if (contract == null)
{
string text = string.Format(CultureInfo.InvariantCulture, "Connect: no contract provided, no connection is possible");
ServiceTrace.LogError(text);
errorCallback?.Invoke(text);
return false;
}
if (Interlocked.CompareExchange(ref connectionInProgress, 1L, 0L) != 0L)
{
string text2 = string.Format(CultureInfo.InvariantCulture, "Connect: another connection is in progress, cannot attempt a connection with a specified contract and access name");
ServiceTrace.LogError(text2);
errorCallback?.Invoke(text2);
return false;
}
try
{
List<EndpointDiscoveryMetadata> list = clientManager.DiscoverEndpointsForContract(contract, scopeRule)?.ToList();
if (list == null)
{
string text3 = string.Format(CultureInfo.InvariantCulture, "Connect: null FindResponse finding contract {0} with access name {1}", new object[2] { contract.Name, scopeRule });
ServiceTrace.LogError(text3);
errorCallback?.Invoke(text3);
return false;
}
if (list.Count == 0)
{
string text4 = string.Format(CultureInfo.InvariantCulture, "Connect found no endpoints for contract {0} with access name {1}", new object[2] { contract.Name, scopeRule });
ServiceTrace.LogError(text4);
errorCallback?.Invoke(text4);
return false;
}
EndpointDiscoveryMetadata selectedMetadata;
if (list.Count > 1)
{
Random random = new Random(DateTime.Now.Millisecond);
selectedMetadata = list[random.Next(list.Count)];
}
else
{
selectedMetadata = list[0];
}
bool flag = EstablishConnection(selectedMetadata, string.Empty, access, errorCallback, useSecureConnection);
ServiceTrace.LogSuspend("Connect (discover endpoint) exit, {0}", flag ? "succeeded" : "failed");
ServiceTrace.LogCsv("Connect (discover endpoint) exit [success]", flag);
return flag;
}
finally
{
Interlocked.Exchange(ref connectionInProgress, 0L);
}
}
protected UserTokenContract EncryptUserToken(UserToken originalToken)
{
if (originalToken == null)
{
return null;
}
UserTokenContract userTokenContract = new UserTokenContract
{
Encryption = originalToken.Encryption,
HostName = originalToken.HostName,
IdType = originalToken.IdType,
LocationId = originalToken.LocationId,
UserName = originalToken.UserName,
Validity = originalToken.Validity
};
SystemAuthenticationClientAuthentication clientAuthenticator = SysAuthenticatorClientCache.GetClientAuthenticator(successfulConnectionResult.ConnectionId);
if (clientAuthenticator == null || !clientAuthenticator.SecureSessionEstablished)
{
throw new InvalidOperationException("Cannot encrypt user token due to session in wrong state");
}
if (originalToken.Password != null)
{
byte[] bytes = Encoding.UTF8.GetBytes(originalToken.Password);
userTokenContract.Password = clientAuthenticator.Encypher(bytes, clientAuthenticator.EncryptionKey);
}
if (originalToken.SamlToken != null)
{
userTokenContract.SamlToken = clientAuthenticator.Encypher(originalToken.SamlToken, clientAuthenticator.EncryptionKey);
}
if (originalToken.JwtToken != null)
{
byte[] bytes2 = Encoding.UTF8.GetBytes(originalToken.JwtToken);
userTokenContract.JwtToken = clientAuthenticator.Encypher(bytes2, clientAuthenticator.EncryptionKey);
}
if (originalToken.X509Certificate != null)
{
userTokenContract.X509Certificate = clientAuthenticator.Encypher(originalToken.X509Certificate, clientAuthenticator.EncryptionKey);
}
return userTokenContract;
}
protected void Reset()
{
successfulConnectionResult?.Dispose();
successfulConnectionResult = null;
}
private bool EstablishConnection(EndpointDiscoveryMetadata selectedMetadata, string solutionName, ClientAccess access, Action<string> errorCallback, bool useSecureConnection)
{
ServiceTrace.LogCsv("CreateConnectContext entry");
ServiceTrace.LogResume("CreateConnectContext entry");
if (selectedMetadata == null)
{
errorCallback?.Invoke("No discovery endpoint metadata provided, cannot connect");
return false;
}
if (string.IsNullOrWhiteSpace(solutionName))
{
solutionName = new ASBSolutionManager().GetASBSolutionName(selectedMetadata, out var errorMessage);
if (!string.IsNullOrEmpty(errorMessage))
{
errorCallback?.Invoke(errorMessage);
return false;
}
}
lock (connectionLock)
{
successfulConnectionResult = null;
connectionEstablishedEvent = new ManualResetEvent(initialState: false);
}
using (CancellationTokenSource cancellationTokenSource = new CancellationTokenSource())
{
SpinConnectionTasks(selectedMetadata.ListenUris, solutionName, access, errorCallback, useSecureConnection, cancellationTokenSource.Token);
bool flag = connectionEstablishedEvent.WaitOne(timeToWaitForConnection);
ServiceTrace.LogVerbose("{0} task connected with the service", flag ? "A" : "No");
cancellationTokenSource.Cancel();
}
bool result;
lock (connectionLock)
{
connectionEstablishedEvent.Dispose();
connectionEstablishedEvent = null;
result = true;
if (successfulConnectionResult == null)
{
result = false;
errorCallback?.Invoke("No connection was established with a service endpoint");
}
}
ServiceTrace.LogSuspend("CreateConnectContext exit");
ServiceTrace.LogCsv("CreateConnectContext exit");
return result;
}
private void SpinConnectionTasks(Collection<Uri> listenUris, string solutionName, ClientAccess access, Action<string> errorCallback, bool useSecureConnection, CancellationToken cancellationToken)
{
ServiceTrace.LogVerbose("Spinning tasks for {0} listen Uris", listenUris.Count);
foreach (Uri endpointUri in listenUris)
{
string selectedEndpointUri = endpointUri.ToString();
Task.Factory.StartNew(delegate
{
NetTcpBindingSecurityMode securityMode = (useSecureConnection ? NetTcpBindingSecurityMode.CertificateEncryption : NetTcpBindingSecurityMode.None);
Binding binding = SvcUtilities.GetBinding(selectedEndpointUri, securityMode);
binding.OpenTimeout = new TimeSpan(0, 10, 0);
binding.ReceiveTimeout = new TimeSpan(0, 10, 0);
binding.SendTimeout = new TimeSpan(0, 10, 0);
binding.CloseTimeout = new TimeSpan(0, 10, 0);
EndpointAddress serviceEndpointAddress = new EndpointAddress(selectedEndpointUri);
if (useSecureConnection)
{
IPHostEntry hostEntry = Dns.GetHostEntry(endpointUri.Host);
serviceEndpointAddress = new EndpointAddress(endpointUri, EndpointIdentity.CreateDnsIdentity(hostEntry.HostName));
}
InternalConnect(serviceEndpointAddress, binding, solutionName, access, errorCallback, cancellationToken);
}, cancellationToken, TaskCreationOptions.None, TaskScheduler.Default);
}
}
private void InternalConnect(EndpointAddress serviceEndpointAddress, Binding binding, string solutionName, ClientAccess access, Action<string> errorCallback, CancellationToken cancellationToken)
{
if (serviceEndpointAddress == null)
{
throw new ArgumentNullException("serviceEndpointAddress");
}
if (binding == null)
{
throw new ArgumentNullException("binding");
}
if (string.IsNullOrEmpty(solutionName))
{
throw new ArgumentNullException("solutionName");
}
try
{
EstablishChannelConnection(serviceEndpointAddress, binding, solutionName, access, errorCallback, cancellationToken);
}
catch (CommunicationException ex)
{
ServiceTrace.LogWarning("BaseV2Client caught CommunicationException opening channel: " + ex.Message);
errorCallback?.Invoke("BaseV2Client caught CommunicationException opening channel: " + ex.Message);
if (ex.InnerException != null)
{
ServiceTrace.LogWarning(" " + ex.InnerException.Message);
errorCallback?.Invoke(" " + ex.InnerException.Message);
}
}
catch (TimeoutException ex2)
{
ServiceTrace.LogWarning("BaseV2Client caught TimeoutException opening channel: " + ex2.Message);
errorCallback?.Invoke("BaseV2Client caught TimeoutException opening channel: " + ex2.Message);
if (ex2.InnerException != null)
{
ServiceTrace.LogWarning(" " + ex2.InnerException.Message);
errorCallback?.Invoke(" " + ex2.InnerException.Message);
}
}
catch (Exception ex3)
{
ServiceTrace.LogWarning("BaseV2Client caught exception opening channel: " + ex3.Message);
errorCallback?.Invoke("BaseV2Client caught exception opening channel: " + ex3.Message);
}
}
private void EstablishChannelConnection(EndpointAddress serviceEndpointAddress, Binding binding, string solutionName, ClientAccess access, Action<string> errorCallback, CancellationToken cancellationToken)
{
ConnectContext<T> connectContext = clientManager.CreateConnectContext<T>(serviceEndpointAddress, binding, connectionApplication, connectionUser, cancellationToken);
if ((connectContext != null && connectContext.ServiceChannelFactory?.State == CommunicationState.Closed) || (connectContext != null && connectContext.ServiceChannel?.State == CommunicationState.Closed))
{
return;
}
if (clientManager.EstablishSecureSession(connectContext, solutionName, access))
{
ServiceTrace.LogVerbose("Secure connection with endpoint {0} is established using solution {1}", serviceEndpointAddress.Uri.AbsoluteUri, solutionName);
bool flag = false;
lock (connectionLock)
{
if (successfulConnectionResult == null)
{
flag = true;
successfulConnectionResult = connectContext;
ServiceTrace.LogVerbose("Secure connection with endpoint {0} using solution {1} is first, signal success", serviceEndpointAddress.Uri.AbsoluteUri, solutionName);
connectionEstablishedEvent?.Set();
}
}
if (!flag)
{
ServiceTrace.LogVerbose("Secure connection with endpoint {0} using solution {1} is NOT first, disconnect", serviceEndpointAddress.Uri.AbsoluteUri, solutionName);
clientManager.DisconnectSecureSession(connectContext);
connectContext.Dispose();
}
}
else
{
if (connectContext != null && !string.IsNullOrEmpty(connectContext.ErrorMessage))
{
errorCallback?.Invoke(connectContext.ErrorMessage);
}
ServiceTrace.LogVerbose("Connection with endpoint {0} using solution {1} rejected", serviceEndpointAddress.Uri.AbsoluteUri, solutionName);
if (connectionEstablishedEvent != null)
{
connectionEstablishedEvent.Set();
}
}
}
public void OnConnect(ulong timeout, ConsumerMetadata metadata)
{
ServiceTrace.LogCsv("OnConnect entry");
ServiceTrace.LogResume("OnConnect entry");
throw new NotImplementedException();
}
public ArchestrAResult KeepAlive()
{
ServiceTrace.LogCsv("KeepAlive entry");
ServiceTrace.LogResume("KeepAlive entry");
ArchestrAResult archestrAResult = PrepareToSend(new KeepAliveRequest(), delegate(ConnectedRequest request, T channelClient)
{
ServiceTrace.LogVerbose("Calling WCF channel KeepAlive method");
KeepAliveResponse keepAliveResponse = channelClient.KeepAlive((KeepAliveRequest)request);
ServiceTrace.LogVerbose("Returned from WCF channel KeepAlive method");
if (keepAliveResponse == null)
{
return ArchestrAResult.MakeResult(ArchestrAError.BadNoCommunication, 0).AddErrorMessage("No response from the service");
}
UpdateDownstreamConnectionState(keepAliveResponse);
return keepAliveResponse.Result;
});
ServiceTrace.LogSuspend("KeepAlive exit with {0}", archestrAResult.Success ? "success" : "failure");
ServiceTrace.LogCsv("KeepAlive exit [success]", archestrAResult.Success);
return archestrAResult;
}
public ArchestrAResult GetStatusItems(out string[] items)
{
ServiceTrace.LogCsv("GetStatusItems entry");
ServiceTrace.LogResume("GetStatusItems entry");
string[] receivedItems = null;
ArchestrAResult archestrAResult = PrepareToSend(new GetStatusItemsRequest(), delegate(ConnectedRequest request, T channelClient)
{
ServiceTrace.LogCsv("Calling WCF channel GetStatusItems method");
GetStatusItemsResponse statusItems = channelClient.GetStatusItems((GetStatusItemsRequest)request);
ServiceTrace.LogCsv("Returned from WCF channel GetStatusItems method");
if (statusItems == null)
{
return ArchestrAResult.MakeResult(ArchestrAError.BadNoCommunication, 0).AddErrorMessage("No response from the service");
}
UpdateDownstreamConnectionState(statusItems);
receivedItems = statusItems.Items;
return statusItems.Result;
});
ServiceTrace.LogSuspend("GetStatusItems exit with {0}", archestrAResult.Success ? "success" : "failure");
ServiceTrace.LogCsv("GetStatusItems exit [success]", archestrAResult.Success);
items = receivedItems;
return archestrAResult;
}
public ArchestrAResult GetStatus(string[] itemsToReturn, out NamedValue[] items)
{
ServiceTrace.LogCsv("GetStatus entry");
ServiceTrace.LogResume("GetStatus entry");
NamedValue[] receivedItems = null;
ArchestrAResult archestrAResult = PrepareToSend(new GetStatusRequest
{
ItemsToReturn = itemsToReturn
}, delegate(ConnectedRequest request, T channelClient)
{
ServiceTrace.LogCsv("Calling WCF channel GetStatus method");
GetStatusResponse status = channelClient.GetStatus((GetStatusRequest)request);
ServiceTrace.LogCsv("Returned from WCF channel GetStatus method");
if (status == null)
{
return ArchestrAResult.MakeResult(ArchestrAError.BadNoCommunication, 0).AddErrorMessage("No response from the service");
}
UpdateDownstreamConnectionState(status);
receivedItems = status.Items;
return status.Result;
});
ServiceTrace.LogSuspend("GetStatus exit with {0}", archestrAResult.Success ? "success" : "failure");
ServiceTrace.LogCsv("GetStatus exit [success]", archestrAResult.Success);
items = receivedItems;
return archestrAResult;
}
public void OnDisconnect()
{
ServiceTrace.LogCsv("OnDisconnect entry");
ServiceTrace.LogResume("OnDisconnect entry");
throw new NotImplementedException();
}
protected ArchestrAResult PrepareToSend(ConnectedRequest request, Func<ConnectedRequest, T, ArchestrAResult> processFunc)
{
if (request == null)
{
return ArchestrAResult.MakeResult(ArchestrAError.BadNoCommunication, 0).AddErrorMessage("No request message provided for signature");
}
if (processFunc == null)
{
return ArchestrAResult.MakeResult(ArchestrAError.BadNoCommunication, 0).AddErrorMessage("No processing function provided");
}
ArchestrAResult archestrAResult = SignRequest(request);
if (!archestrAResult.Success)
{
return archestrAResult;
}
T channelClient = ChannelClient;
if (channelClient == null)
{
return ArchestrAResult.MakeResult(ArchestrAError.BadNoCommunication, 0).AddErrorMessage("No connected client for the current connection Id");
}
return processFunc(request, channelClient);
}
protected ArchestrAResult SignRequest(ConnectedRequest request)
{
ArchestrAResult result = ArchestrAResult.MakeResult(ArchestrAError.InvalidConnectionId, 0);
if (successfulConnectionResult != null && successfulConnectionResult.ServiceClient != null && State != CommunicationState.Faulted)
{
SystemAuthenticationClientAuthentication clientAuthenticator = SysAuthenticatorClientCache.GetClientAuthenticator(successfulConnectionResult.ConnectionId);
if (clientAuthenticator != null)
{
clientAuthenticator.Sign(request, forceHmac: false);
return ArchestrAResult.MakeGoodResult();
}
result.AddErrorMessage("Unable to find a signer using the current connection Id");
}
else
{
result.AddErrorMessage("Unable to use the client proxy for the current connection Id");
}
return result;
}
protected void UpdateDownstreamConnectionState(ConnectedResponse response)
{
if (response != null)
{
if (response.DownstreamConnectionState <= 6)
{
DownstreamConnectionState = (ConnectionState)response.DownstreamConnectionState;
return;
}
ServiceTrace.LogWarning(string.Format(CultureInfo.InvariantCulture, "ASB Base V2 client failed to parse downstream connection state value of {0}", new object[1] { response.DownstreamConnectionState }));
DownstreamConnectionState = ConnectionState.Unknown;
}
}
~BaseV2Client()
{
Dispose(disposing: false);
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (disposed)
{
return;
}
if (disposing)
{
if (successfulConnectionResult != null)
{
successfulConnectionResult.Dispose();
}
successfulConnectionResult = null;
}
disposed = true;
Reset();
}
}
@@ -0,0 +1,492 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading;
using ArchestrAServices.Common;
using Asb.Base.V2.ContractTypes;
namespace Asb.Base.V2;
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Multiple)]
public abstract class BaseV2Shim : IAuthenticateAsb
{
private sealed class ConnectionContext : IDisposable
{
private readonly TimeSpan keepAliveTimeout;
private readonly Timer timer;
private bool disposed;
public IContextChannel ConnectionChannel { get; private set; }
public IBaseV2 ConnectionImplementation { get; }
public ConnectionContext(IBaseV2 implementation, TimerCallback keepAliveTimeoutCallback, Guid connectionId, TimeSpan keepAliveTimeout)
{
ConnectionChannel = ((OperationContext.Current == null) ? null : OperationContext.Current.Channel);
ConnectionImplementation = implementation;
timer = new Timer(keepAliveTimeoutCallback, connectionId, (int)keepAliveTimeout.TotalMilliseconds, -1);
this.keepAliveTimeout = keepAliveTimeout;
}
~ConnectionContext()
{
Dispose(disposing: false);
}
public void RestartTimer()
{
timer.Change((int)keepAliveTimeout.TotalMilliseconds, -1);
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (disposed)
{
return;
}
disposed = true;
if (disposing)
{
if (ConnectionChannel != null)
{
ConnectionChannel.Close();
ConnectionChannel = null;
}
if (timer != null)
{
timer.Dispose();
}
}
}
}
private static readonly ReaderWriterLockSlim implementationLock = new ReaderWriterLockSlim();
private static readonly Dictionary<Guid, ConnectionContext> implementations = new Dictionary<Guid, ConnectionContext>();
private static readonly TimeSpan defaultKeepAliveTimeout = TimeSpan.FromSeconds(30.0);
public virtual ConnectionState DownstreamConnectionState { get; set; }
protected virtual TimeSpan KeepAliveTimeout => defaultKeepAliveTimeout;
public ConnectResponse Connect(ConnectRequest request)
{
if (request == null)
{
return null;
}
ServiceTrace.LogCsv("Connect entry [ConId]", request.ConnectionId);
ServiceTrace.LogResume("Connect entry, connection Id {0} ", request.ConnectionId);
ConnectResponse connectResponse = SystemAuthenticationServiceAuthentication.ProcessClientConnection(request);
ServiceTrace.LogVerbose("BaseV2Shim.Connect started new SysAuthenticator for connection Id {0}", connectResponse.ConnectionValidator.ConnectionId);
ServiceTrace.LogSuspend("Connect exit, connection Id {0}, success = {1}", request.ConnectionId, connectResponse.Result.Success);
ServiceTrace.LogCsv("Connect exit [ConId Success]", request.ConnectionId, connectResponse.Result.Success);
return connectResponse;
}
public AuthenticateMeResponse AuthenticateMe(AuthenticateMeRequest request)
{
if (request == null)
{
return null;
}
ServiceTrace.LogCsv("AuthenticateMe entry [ConnId]", request.ConnectionValidator.ConnectionId);
ServiceTrace.LogResume("AuthenticateMe entry, connection Id {0} ", request.ConnectionValidator.ConnectionId);
ArchestrAResult archestrAResult = ArchestrAResult.MakeResult(ArchestrAError.OperationFailed, 0);
SystemAuthenticationServiceAuthentication serviceAuthenticator = SysAuthenticatorServiceCache.GetServiceAuthenticator(request.ConnectionValidator.ConnectionId);
if (serviceAuthenticator != null)
{
if (serviceAuthenticator.ProcessClientAuthenticateMe(request))
{
ServiceTrace.LogVerbose("AuthenticateMe found authenticator and validated request message, establishing serivce implementation for connect Id {0})", serviceAuthenticator.ConnectionId);
ConsumerMetadata metadata = ConsumerMetadata.Create(request.ConsumerMetaData);
archestrAResult = CheckConsumerMetadata(metadata, serviceAuthenticator.ConnectionId);
if (archestrAResult.Success)
{
archestrAResult = CreateServiceImplmentation(serviceAuthenticator, metadata);
}
}
else
{
archestrAResult = ArchestrAResult.MakeResult(ArchestrAError.ApplicationAuthenticationError, 0);
string message = string.Format(CultureInfo.CurrentCulture, "AuthenticateMe unable to authenticate client for ConnectionId {0}", new object[1] { serviceAuthenticator.ConnectionId });
ServiceTrace.LogWarning(message);
archestrAResult.AddErrorMessage(message);
}
}
if (!archestrAResult.Success)
{
OnDisconnect(request.ConnectionValidator.ConnectionId);
}
ServiceTrace.LogSuspend("AuthenticateMe exit, connection Id {0}, success = {1}", request.ConnectionValidator.ConnectionId, archestrAResult.Success);
ServiceTrace.LogCsv("AuthenticateMe exit [ConId Success]", request.ConnectionValidator.ConnectionId, archestrAResult.Success);
return new AuthenticateMeResponse(archestrAResult, DownstreamConnectionState);
}
public KeepAliveResponse KeepAlive(KeepAliveRequest request)
{
if (request == null)
{
return null;
}
ServiceTrace.LogCsv("KeepAlive entry [ConnId]", request.ConnectionValidator.ConnectionId);
ServiceTrace.LogResume("KeepAlive entry, connection Id {0} ", request.ConnectionValidator.ConnectionId);
ArchestrAResult result = ArchestrAResult.MakeResult(ArchestrAError.OperationFailed, 0);
SystemAuthenticationServiceAuthentication serviceAuthenticator = SysAuthenticatorServiceCache.GetServiceAuthenticator(request.ConnectionValidator.ConnectionId);
if (serviceAuthenticator != null && serviceAuthenticator.ValidRequest(request, forceHmac: false))
{
implementationLock.EnterReadLock();
bool flag;
ConnectionContext value;
try
{
flag = implementations.TryGetValue(request.ConnectionValidator.ConnectionId, out value);
}
finally
{
implementationLock.ExitReadLock();
}
if (flag && value != null)
{
value.RestartTimer();
IBaseV2 connectionImplementation = value.ConnectionImplementation;
try
{
result = EnsureValidResult(connectionImplementation.KeepAlive());
}
catch (Exception ex)
{
ServiceTrace.LogWarning("KeepAlive caught exception from implementation for connection Id {0}: {1}", request.ConnectionValidator.ConnectionId, ex.Message);
if (ex.InnerException != null)
{
ServiceTrace.LogWarning(" {0}", ex.InnerException.Message);
}
}
}
}
ServiceTrace.LogResume("KeepAlive exit, connection Id {0}", request.ConnectionValidator.ConnectionId);
ServiceTrace.LogResume("KeepAlive exit [ConId]", request.ConnectionValidator.ConnectionId);
return new KeepAliveResponse(result, DownstreamConnectionState);
}
public GetStatusItemsResponse GetStatusItems(GetStatusItemsRequest request)
{
if (request == null)
{
return null;
}
ServiceTrace.LogCsv("GetStatusItems entry [ConnId]", request.ConnectionValidator.ConnectionId);
ServiceTrace.LogResume("GetStatusItems entry, connection Id {0} ", request.ConnectionValidator.ConnectionId);
GetStatusItemsResponse getStatusItemsResponse = new GetStatusItemsResponse(ArchestrAResult.MakeResult(ArchestrAError.InvalidConnectionId, 0), null, DownstreamConnectionState);
IBaseV2 implementation = GetImplementation<IBaseV2>(request);
if (implementation != null)
{
try
{
getStatusItemsResponse.Result = EnsureValidResult(implementation.GetStatusItems(out var items));
List<string> list = items.ToList();
list.Add("ServiceLoadTime");
getStatusItemsResponse.Items = list.ToArray();
}
catch (Exception ex)
{
ServiceTrace.LogWarning("GetStatusItems caught exception from implementation for ConnectionId {0}: {1}", request.ConnectionValidator.ConnectionId, ex.Message);
getStatusItemsResponse.Result.AddErrorMessage(ex.Message);
if (ex.InnerException != null)
{
ServiceTrace.LogWarning(" {0}", ex.InnerException.Message);
getStatusItemsResponse.Result.AddErrorMessage(ex.InnerException.Message);
}
getStatusItemsResponse.Result.ResultCodeAsError = ArchestrAError.OperationFailed;
}
}
ServiceTrace.LogSuspend("GetStatusItems exit, connection Id {0}, success = {1}", request.ConnectionValidator.ConnectionId, getStatusItemsResponse.Result.Success);
ServiceTrace.LogCsv("GetStatusItems exit [ConId Success]", request.ConnectionValidator.ConnectionId, getStatusItemsResponse.Result.Success);
return getStatusItemsResponse;
}
public GetStatusResponse GetStatus(GetStatusRequest request)
{
if (request == null)
{
return null;
}
ServiceTrace.LogCsv("GetStatus entry [ConnId]", request.ConnectionValidator.ConnectionId);
ServiceTrace.LogResume("GetStatus entry, connection Id {0} ", request.ConnectionValidator.ConnectionId);
GetStatusResponse getStatusResponse = new GetStatusResponse(ArchestrAResult.MakeResult(ArchestrAError.InvalidConnectionId, 0), null, DownstreamConnectionState);
IBaseV2 implementation = GetImplementation<IBaseV2>(request);
if (implementation != null)
{
try
{
getStatusResponse.Result = EnsureValidResult(implementation.GetStatus(request.ItemsToReturn, out var items));
List<NamedValue> list = items.ToList();
list.Add(new NamedValue
{
Name = "ServiceLoadTime",
Value = Value.Create(implementation.ServiceLoadTime)
});
getStatusResponse.Items = list.ToArray();
}
catch (Exception ex)
{
ServiceTrace.LogWarning("GetStatus caught exception from implementation for ConnectionId {0}: {1}", request.ConnectionValidator.ConnectionId, ex.Message);
getStatusResponse.Result.AddErrorMessage(ex.Message);
if (ex.InnerException != null)
{
ServiceTrace.LogWarning(" {0}", ex.InnerException.Message);
getStatusResponse.Result.AddErrorMessage(ex.InnerException.Message);
}
getStatusResponse.Result.ResultCodeAsError = ArchestrAError.OperationFailed;
}
}
ServiceTrace.LogSuspend("GetStatus exit, connection Id {0}, success = {1}", request.ConnectionValidator.ConnectionId, getStatusResponse.Result.Success);
ServiceTrace.LogCsv("GetStatus exit [ConId Success]", request.ConnectionValidator.ConnectionId, getStatusResponse.Result.Success);
return getStatusResponse;
}
public RenewResponse Renew(RenewRequest request)
{
if (request == null)
{
return null;
}
ServiceTrace.LogCsv("Renew entry [ConnId]", request.ConnectionValidator.ConnectionId);
ServiceTrace.LogResume("Renew entry, connection Id {0} ", request.ConnectionValidator.ConnectionId);
RenewResponse renewResponse = SystemAuthenticationServiceAuthentication.ProcessClientRenew(request);
ServiceTrace.LogSuspend("Renew exit, connection Id {0}, success = {1}", request.ConnectionValidator.ConnectionId, renewResponse.Result.Success);
ServiceTrace.LogCsv("Renew exit [ConId Success]", request.ConnectionValidator.ConnectionId, renewResponse.Result.Success);
return renewResponse;
}
public void UpdateSystemAuthenticationConfiguration(UpdateSystemAuthenticationConfigurationRequest request)
{
if (request != null)
{
ServiceTrace.LogCsv("UpdateSystemAuthenticationConfiguration entry [ConnId]", request.ConnectionValidator.ConnectionId);
ServiceTrace.LogResume("UpdateSystemAuthenticationConfiguration entry, connection Id {0} ", request.ConnectionValidator.ConnectionId);
SystemAuthenticationServiceAuthentication.ProcessClientUpdateSystemAuthenticationConfiguration(request);
ServiceTrace.LogSuspend("UpdateSystemAuthenticationConfiguration exit, connection Id {0}", request.ConnectionValidator.ConnectionId);
ServiceTrace.LogCsv("UpdateSystemAuthenticationConfiguration exit [ConId]", request.ConnectionValidator.ConnectionId);
}
}
public void Disconnect(DisconnectRequest request)
{
if (request != null)
{
ServiceTrace.LogCsv("Disconnect entry [ConnId]", request.ConnectionValidator.ConnectionId);
ServiceTrace.LogResume("Disconnect entry, connection Id {0} ", request.ConnectionValidator.ConnectionId);
SystemAuthenticationServiceAuthentication serviceAuthenticator = SysAuthenticatorServiceCache.GetServiceAuthenticator(request.ConnectionValidator.ConnectionId);
if (serviceAuthenticator != null && serviceAuthenticator.ValidRequest(request, forceHmac: false))
{
OnDisconnect(request.ConnectionValidator.ConnectionId);
serviceAuthenticator.ProcessClientDisconnect(request);
}
ServiceTrace.LogSuspend("Disconnect exit, connection Id {0}", request.ConnectionValidator.ConnectionId);
ServiceTrace.LogCsv("Disconnect exit [ConId]", request.ConnectionValidator.ConnectionId);
}
}
protected UserToken DecryptUserToken(Guid connectionId, UserTokenContract wireToken)
{
if (wireToken == null)
{
return null;
}
SystemAuthenticationServiceAuthentication serviceAuthenticator = SysAuthenticatorServiceCache.GetServiceAuthenticator(connectionId);
if (serviceAuthenticator == null || !serviceAuthenticator.SecureSessionEstablished)
{
throw new InvalidOperationException("Cannot decrypt user token due to session in wrong state");
}
UserToken userToken = new UserToken
{
Encryption = wireToken.Encryption,
HostName = wireToken.HostName,
IdType = wireToken.IdType,
LocationId = wireToken.LocationId,
UserName = wireToken.UserName,
Validity = wireToken.Validity
};
if (wireToken.Password != null)
{
byte[] bytes = serviceAuthenticator.Decypher(wireToken.Password, serviceAuthenticator.EncryptionKey);
userToken.Password = Encoding.UTF8.GetString(bytes);
}
if (wireToken.SamlToken != null)
{
userToken.SamlToken = serviceAuthenticator.Decypher(wireToken.SamlToken, serviceAuthenticator.EncryptionKey);
}
if (wireToken.JwtToken != null)
{
byte[] bytes2 = serviceAuthenticator.Decypher(wireToken.JwtToken, serviceAuthenticator.EncryptionKey);
userToken.JwtToken = Encoding.UTF8.GetString(bytes2);
}
if (wireToken.X509Certificate != null)
{
userToken.X509Certificate = serviceAuthenticator.Decypher(wireToken.X509Certificate, serviceAuthenticator.EncryptionKey);
}
return userToken;
}
protected static ArchestrAResult EnsureValidResult(ArchestrAResult result)
{
if (result == null)
{
return ArchestrAResult.MakeErrorResult("Service returned no result");
}
return result;
}
private ArchestrAResult CreateServiceImplmentation(SystemAuthenticationServiceAuthentication authenticator, ConsumerMetadata metadata)
{
ArchestrAResult result = ArchestrAResult.MakeGoodResult();
IBaseV2 implementation = GetImplementation();
if (implementation == null)
{
result = ArchestrAResult.MakeResult(ArchestrAError.Unknown, 0);
string message = string.Format(CultureInfo.CurrentCulture, "AuthenticateMe could not create a service implementation object for ConnectionId {0}", new object[1] { authenticator.ConnectionId });
ServiceTrace.LogWarning(message);
result.AddErrorMessage(message);
return result;
}
try
{
ServiceTrace.LogCsv("AuthenticateMe found authenticator and validated request message, calling implementation OnConnect [ConId]", authenticator.ConnectionId);
ServiceTrace.LogVerbose("AuthenticateMe found authenticator and validated request message, calling implementation OnConnect for connection Id {0}", authenticator.ConnectionId);
implementation.ServiceLoadTime = DateTime.UtcNow;
implementation.ConnectionId = authenticator.ConnectionId;
implementation.OnConnect(authenticator.Lifetime, metadata);
CreateConnectionContext(authenticator.ConnectionId, implementation);
}
catch (Exception ex)
{
result = ArchestrAResult.MakeResult(ArchestrAError.Unknown, 0);
ServiceTrace.LogWarning("AuthenticateMe caught exception from implementation for ConnectionId {0}: {1}", authenticator.ConnectionId, ex.Message);
result.AddErrorMessage(ex.Message);
if (ex.InnerException != null)
{
ServiceTrace.LogWarning(" {0}", ex.InnerException.Message);
result.AddErrorMessage(ex.InnerException.Message);
}
}
return result;
}
private void CreateConnectionContext(Guid connectionId, IBaseV2 implementation)
{
implementationLock.EnterWriteLock();
try
{
implementations.Add(connectionId, new ConnectionContext(implementation, KeepaliveHandler, connectionId, KeepAliveTimeout));
ServiceTrace.LogVerbose("AuthenticateMe added implementation for connection Id {0}", connectionId);
}
finally
{
implementationLock.ExitWriteLock();
}
}
private static void OnDisconnect(Guid connectionId)
{
IBaseV2 baseV = null;
bool flag = false;
implementationLock.EnterWriteLock();
try
{
flag = implementations.TryGetValue(connectionId, out var value);
if (flag)
{
implementations.Remove(connectionId);
ServiceTrace.LogVerbose("OnDisconnect removed implementation for ConnectionId {0}", connectionId);
baseV = value.ConnectionImplementation;
value.Dispose();
}
}
catch (Exception ex)
{
ServiceTrace.LogVerbose("OnDisconnect handled an exception: {0}", ex);
}
finally
{
implementationLock.ExitWriteLock();
}
if (flag && baseV != null)
{
try
{
ServiceTrace.LogCsv("OnDisconnect found authenticator and validated request message, calling implementation OnDisconnect Id =", connectionId);
baseV.OnDisconnect();
}
catch (Exception ex2)
{
ServiceTrace.LogWarning("OnDisconnect caught exception from implementation for ConnectionId {0}: {1}", connectionId, ex2.Message);
if (ex2.InnerException != null)
{
ServiceTrace.LogWarning(" {0}", ex2.InnerException.Message);
}
}
}
SysAuthenticatorServiceCache.RemoveServiceAuthenticator(connectionId);
}
private static void KeepaliveHandler(object connectionId)
{
try
{
OnDisconnect((Guid)connectionId);
}
catch (Exception ex)
{
ServiceTrace.LogVerbose("KeepaliveHandler handled an exception {0}", ex);
}
}
protected virtual ArchestrAResult CheckConsumerMetadata(ConsumerMetadata metadata, Guid connectionId)
{
return ArchestrAResult.MakeGoodResult();
}
protected abstract IBaseV2 GetImplementation();
protected static T GetImplementation<T>(ConnectedRequest request) where T : class, IBaseV2
{
if (request == null)
{
return null;
}
SystemAuthenticationServiceAuthentication serviceAuthenticator = SysAuthenticatorServiceCache.GetServiceAuthenticator(request.ConnectionValidator.ConnectionId);
if (serviceAuthenticator != null && serviceAuthenticator.ValidRequest(request, forceHmac: false))
{
implementationLock.EnterReadLock();
bool flag;
ConnectionContext value;
try
{
flag = implementations.TryGetValue(request.ConnectionValidator.ConnectionId, out value);
}
finally
{
implementationLock.ExitReadLock();
}
if (flag && value != null)
{
value.RestartTimer();
return value.ConnectionImplementation as T;
}
}
return null;
}
}
@@ -0,0 +1,12 @@
using System;
using System.Xml.Serialization;
namespace Asb.Base.V2;
[Serializable]
[XmlType(Namespace = "urn:data.asb.se:2", IncludeInSchema = false)]
public enum ClientAccess
{
FullAccess,
ReadOnly
}
@@ -0,0 +1,173 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Discovery;
using System.ServiceModel.Security;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using ArchestrAServices.Common;
namespace Asb.Base.V2;
internal class ClientManagement : IClientManagement
{
public ConnectContext<T> CreateConnectContext<T>(EndpointAddress serviceEndpointAddress, Binding binding, string application, string user, CancellationToken cancellationToken) where T : class, IAuthenticateAsb
{
ConnectContext<T> connectContext = new ConnectContext<T>
{
Success = false,
ErrorMessage = string.Empty,
ServiceChannelFactory = null,
ServiceClient = null,
ServiceChannel = null,
ConnectionId = Guid.Empty,
ConnectionUser = user,
ConnectionApplication = application
};
ServiceTrace.LogVerbose("Try connecting with endpoint {0}", serviceEndpointAddress.Uri.AbsoluteUri);
connectContext.ServiceChannelFactory = new ChannelFactory<T>(binding, serviceEndpointAddress);
if (binding is NetTcpBinding netTcpBinding && netTcpBinding.Security.Mode == SecurityMode.Transport && connectContext.ServiceChannelFactory.Credentials != null)
{
connectContext.ServiceChannelFactory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.ChainTrust;
connectContext.ServiceChannelFactory.Credentials.ServiceCertificate.Authentication.RevocationMode = X509RevocationMode.NoCheck;
}
InjectCustomBehavior(connectContext.ServiceChannelFactory);
if (!OpenOrAbort(connectContext.ServiceChannelFactory, cancellationToken))
{
ServiceTrace.LogVerbose("BaseV2Client CreateConnectContext is cancelled when create channel for {0}", serviceEndpointAddress.Uri.AbsoluteUri);
return connectContext;
}
connectContext.ServiceClient = connectContext.ServiceChannelFactory.CreateChannel();
if (connectContext.ServiceClient == null)
{
ServiceTrace.LogWarning("BaseV2Client not able to create a client for the endpoint {0}", serviceEndpointAddress.Uri.AbsoluteUri);
return null;
}
connectContext.CastClientToChannel();
if (connectContext.ServiceChannel == null)
{
ServiceTrace.LogWarning("BaseV2Client not able to create a channel for the endpoint {0}", serviceEndpointAddress.Uri.AbsoluteUri);
return null;
}
if (!OpenOrAbort(connectContext.ServiceChannel, cancellationToken))
{
ServiceTrace.LogVerbose("BaseV2Client CreateConnectContext is cancelled when open channel for {0}", serviceEndpointAddress.Uri.AbsoluteUri);
}
return connectContext;
}
public virtual void InjectCustomBehavior<T>(ChannelFactory<T> channelFactory) where T : class, IAuthenticateAsb
{
}
public bool EstablishSecureSession<T>(ConnectContext<T> context, string solutionName, ClientAccess access) where T : class, IAuthenticateAsb
{
if (context?.ServiceChannel == null)
{
return false;
}
if (context.ServiceChannel.State != CommunicationState.Faulted)
{
ServiceTrace.LogVerbose("Channel with endpoint {0} is open, establishing secure session using solution {1}", context.ServiceChannel.RemoteAddress.Uri.AbsoluteUri, solutionName);
return context.EstablishSecureSession(solutionName, access);
}
ServiceTrace.LogVerbose("Secure connection with endpoint {0} is NOT established using solution {1}", context.ServiceChannel.RemoteAddress.Uri.AbsoluteUri, solutionName);
context.ServiceChannel.Abort();
context.Dispose();
if (string.IsNullOrEmpty(context.ErrorMessage))
{
context.ErrorMessage = "BaseV2Client could not connect with service: EstablishSecureSession failed";
}
ServiceTrace.LogWarning(context.ErrorMessage);
return false;
}
public void DisconnectSecureSession<T>(ConnectContext<T> context) where T : class, IAuthenticateAsb
{
context?.DisconnectSecureSession();
}
public IEnumerable<EndpointDiscoveryMetadata> DiscoverEndpointsForContract(XmlQualifiedName contract, string scopeRule)
{
if (contract == null)
{
throw new ArgumentNullException("contract");
}
ServiceTrace.LogCsv("DiscoverEndpointsForContract entry [Contract scopeRule]", contract, string.IsNullOrEmpty(scopeRule) ? "<empty>" : scopeRule);
ServiceTrace.LogResume("DiscoverEndpointsForContract entry, contract {0}, scopeRule {1}", contract, string.IsNullOrEmpty(scopeRule) ? "<empty>" : scopeRule);
FindResponse findResponse;
try
{
Uri uri = RegistryHandler.MakeLDSProbeEndpointAddress(Environment.MachineName);
ServiceTrace.LogVerbose("DiscoverEndpointsForContract({0}) generated LDS endpoint for localhost: {1}", contract, uri.AbsoluteUri);
FindCriteria findCriteria = new FindCriteria();
findCriteria.ContractTypeNames.Add(contract);
List<string> list = new List<string>();
if (!string.IsNullOrEmpty(scopeRule))
{
list.Add(scopeRule);
}
Collection<Uri> collection = SvcUtilities.CreateFindScopes(string.Empty, string.Empty, string.Empty, list);
ServiceTrace.LogVerbose("DiscoverEndpointsForContract({0}) generated {1} scope Uris:", contract, collection.Count);
findCriteria.Scopes.Clear();
foreach (Uri item in collection)
{
ServiceTrace.LogVerbose(" {0}", item.AbsoluteUri);
findCriteria.Scopes.Add(item);
}
using DiscoveryClient discoveryClient = new DiscoveryClient(new DiscoveryEndpoint(SvcUtilities.GetBinding(uri.AbsoluteUri), new EndpointAddress(uri)));
findResponse = discoveryClient.Find(findCriteria);
ServiceTrace.LogVerbose("DiscoverEndpointsForContract({0}) found {1} endpoints", contract, findResponse.Endpoints.Count);
}
catch (TargetInvocationException ex)
{
ServiceTrace.LogError("DiscoverEndpointsForContract({0}, {1}) TargetInvocationException: {2}", contract, scopeRule, ex.Message);
if (ex.InnerException != null)
{
ServiceTrace.LogError(" {0}", ex.InnerException.Message);
}
findResponse = null;
}
catch (ObjectDisposedException ex2)
{
ServiceTrace.LogError("DiscoverEndpointsForContract({0}, {1}) ObjectDisposedException: {2}", contract, scopeRule, ex2.Message);
if (ex2.InnerException != null)
{
ServiceTrace.LogError(" {0}", ex2.InnerException.Message);
}
findResponse = null;
}
catch (Exception ex3)
{
ServiceTrace.LogError("DiscoverEndpointsForContract({0}, {1}) Exception: {2}", contract, scopeRule, ex3.Message);
if (ex3.InnerException != null)
{
ServiceTrace.LogError(" {0}", ex3.InnerException.Message);
}
findResponse = null;
}
ServiceTrace.LogSuspend("DiscoverEndpointsForContract exit, contract {0}, scopeRule {1}", contract, string.IsNullOrEmpty(scopeRule) ? "<empty>" : scopeRule);
ServiceTrace.LogCsv("DiscoverEndpointsForContract exit [Contract scopeRule]", contract, string.IsNullOrEmpty(scopeRule) ? "<empty>" : scopeRule);
return findResponse?.Endpoints;
}
private static bool OpenOrAbort(ICommunicationObject communicationObject, CancellationToken cancellationToken)
{
Task task = Task.Factory.StartNew(communicationObject.Open, cancellationToken, TaskCreationOptions.None, TaskScheduler.Default);
try
{
task.Wait(cancellationToken);
}
catch (OperationCanceledException)
{
communicationObject.Abort();
return false;
}
return true;
}
}
@@ -0,0 +1,27 @@
using System;
using System.Xml.Serialization;
namespace Asb.Base.V2;
[Serializable]
[XmlType(Namespace = "urn:asb.se:2")]
public class ClientMetadata
{
[XmlElement(ElementName = "UserName", Order = 0)]
public string UserName { get; set; }
[XmlElement(ElementName = "HostName", Order = 1)]
public string HostName { get; set; }
[XmlElement(ElementName = "SessionId", Order = 2)]
public string SessionId { get; set; }
[XmlElement(ElementName = "SessionHostName", Order = 3)]
public string SessionHostName { get; set; }
[XmlElement(ElementName = "ApplicationName", Order = 4)]
public string ApplicationName { get; set; }
[XmlElement(ElementName = "Access", Order = 5)]
public ClientAccess Access { get; set; }
}
@@ -0,0 +1,134 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.ServiceModel;
namespace Asb.Base.V2;
public sealed class ConnectContext<T> : IDisposable where T : class, IAuthenticateAsb
{
private bool disposed;
public bool Success { get; set; }
public string ErrorMessage { get; set; }
public ChannelFactory<T> ServiceChannelFactory { get; set; }
public T ServiceClient { get; set; }
public IClientChannel ServiceChannel { get; set; }
public Guid ConnectionId { get; set; }
public string ConnectionUser { get; set; }
public string ConnectionApplication { get; set; }
~ConnectContext()
{
Dispose(disposing: false);
}
public bool EstablishSecureSession(string solutionName, ClientAccess access)
{
string errorMessage = string.Empty;
Guid connectId = Guid.Empty;
Success = SystemAuthenticationClientAuthentication.EstablishSecureSession(solutionName, GenerateClientMetadata(access), (ConnectRequest request) => ServiceClient.Connect(request), (AuthenticateMeRequest request) => ServiceClient.AuthenticateMe(request), delegate(Guid id)
{
connectId = id;
}, delegate(string msg)
{
errorMessage = msg;
});
if (Success)
{
ConnectionId = connectId;
}
else
{
ErrorMessage = errorMessage;
}
return Success;
}
public void DisconnectSecureSession()
{
SystemAuthenticationClientAuthentication.DisconnectSecureSession(ConnectionId, delegate(DisconnectRequest request)
{
ServiceClient.Disconnect(request);
});
}
public void CastClientToChannel()
{
ServiceChannel = ServiceClient as IClientChannel;
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
private ClientMetadata GenerateClientMetadata(ClientAccess access)
{
ClientMetadata clientMetadata = new ClientMetadata
{
UserName = (string.IsNullOrEmpty(ConnectionUser) ? Environment.UserName : ConnectionUser),
HostName = Environment.MachineName,
ApplicationName = (string.IsNullOrEmpty(ConnectionApplication) ? Process.GetCurrentProcess().ProcessName : ConnectionApplication),
Access = access
};
string terminalServicesClientName = GetTerminalServicesClientName();
if (terminalServicesClientName == "\0")
{
clientMetadata.SessionHostName = string.Empty;
clientMetadata.SessionId = string.Empty;
}
else
{
clientMetadata.SessionHostName = terminalServicesClientName;
clientMetadata.SessionId = Process.GetCurrentProcess().SessionId.ToString();
}
return clientMetadata;
}
private static string GetTerminalServicesClientName()
{
IntPtr ppBuffer;
int pBytesReturned;
bool num = NativeMethods.WTSQuerySessionInformation(NativeMethods.WTS_CURRENT_SERVER_HANDLE, -1, NativeMethods.WTS_INFO_CLASS.WTSClientName, out ppBuffer, out pBytesReturned);
string result = null;
if (num)
{
result = Marshal.PtrToStringAuto(ppBuffer);
NativeMethods.WTSFreeMemory(ppBuffer);
}
return result;
}
private void Dispose(bool disposing)
{
if (disposed)
{
return;
}
disposed = true;
if (disposing)
{
if (ServiceChannel != null)
{
ServiceChannel.Close();
ServiceChannel.Dispose();
}
ServiceChannel = null;
if (ServiceChannelFactory != null)
{
ServiceChannelFactory.Close();
((IDisposable)ServiceChannelFactory).Dispose();
}
ServiceChannelFactory = null;
}
}
}
@@ -0,0 +1,33 @@
using System;
using System.ServiceModel;
using System.Xml.Serialization;
namespace Asb.Base.V2;
[MessageContract(WrapperName = "Connect", WrapperNamespace = "urn:msg.asb.se:2", IsWrapped = true)]
[XmlRoot(Namespace = "urn:msg.asb.se:2")]
public class ConnectRequest : ServiceMessage
{
[MessageBodyMember(Namespace = "urn:msg.asb.se:2", Order = 0)]
[XmlElement(ElementName = "ConnectionId")]
public Guid ConnectionId { get; set; }
[MessageBodyMember(Namespace = "urn:msg.asb.se:2", Order = 1)]
[XmlElement(ElementName = "ConsumerPublicKey")]
public PublicKey ConsumerPublicKey { get; set; }
[MessageBodyMember(Namespace = "urn:msg.asb.se:2", Order = 2)]
[XmlElement(ElementName = "SecurityPolicy")]
public string SecurityPolicy { get; set; }
public ConnectRequest()
{
}
public ConnectRequest(Guid connectionId, PublicKey consumerPublicKey, string securityPolicy)
{
ConnectionId = connectionId;
ConsumerPublicKey = consumerPublicKey;
SecurityPolicy = securityPolicy;
}
}
@@ -0,0 +1,33 @@
using System.ServiceModel;
using System.Xml.Serialization;
namespace Asb.Base.V2;
[MessageContract(WrapperName = "ConnectResponse", WrapperNamespace = "urn:msg.asb.se:2", IsWrapped = true)]
[XmlRoot(Namespace = "urn:msg.asb.se:2")]
public class ConnectResponse : ConnectedResponse
{
[MessageBodyMember(Namespace = "urn:msg.asb.se:2", Order = 2)]
[XmlElement(ElementName = "ServicePublicKey")]
public PublicKey ServicePublicKey { get; set; }
[MessageBodyMember(Namespace = "urn:msg.asb.se:2", Order = 3)]
[XmlElement(ElementName = "ServiceAuthenticationData")]
public AuthenticationData ServiceAuthenticationData { get; set; }
[MessageBodyMember(Namespace = "urn:msg.asb.se:2", Order = 4)]
[XmlElement(ElementName = "ConnectionLifetime", DataType = "duration")]
public string ConnectionLifetime { get; set; }
public ConnectResponse()
{
}
public ConnectResponse(ArchestrAResult result, PublicKey servicePublicKey, AuthenticationData serviceAuthenticationData, string connectionLifetime)
: base(result)
{
ServicePublicKey = servicePublicKey;
ServiceAuthenticationData = serviceAuthenticationData;
ConnectionLifetime = connectionLifetime;
}
}
@@ -0,0 +1,15 @@
using System.ServiceModel;
namespace Asb.Base.V2;
[MessageContract]
public class ConnectedRequest : ServiceMessage
{
[MessageHeader(Namespace = "urn:hdr.asb.se:2")]
public ConnectionValidator ConnectionValidator { get; set; }
public ConnectedRequest()
{
ConnectionValidator = new ConnectionValidator();
}
}
@@ -0,0 +1,33 @@
using System.ServiceModel;
using System.Xml.Serialization;
namespace Asb.Base.V2;
[MessageContract]
public class ConnectedResponse : ConnectedRequest
{
[MessageBodyMember(Namespace = "urn:msg.asb.se:2", Order = 0)]
[XmlElement(ElementName = "Result")]
public ArchestrAResult Result { get; set; }
[MessageBodyMember(Namespace = "urn:msg.asb.se:2", Order = 1)]
[XmlElement(ElementName = "DownstreamState")]
public int DownstreamConnectionState { get; set; }
public ConnectedResponse()
{
Result = ArchestrAResult.MakeGoodResult();
DownstreamConnectionState = 0;
}
public ConnectedResponse(ArchestrAResult result)
: this(result, ConnectionState.Unknown)
{
}
public ConnectedResponse(ArchestrAResult result, ConnectionState downstreamConnectionState)
{
Result = result;
DownstreamConnectionState = (int)downstreamConnectionState;
}
}
@@ -0,0 +1,12 @@
namespace Asb.Base.V2;
public enum ConnectionState
{
Unknown,
Created,
Opening,
Opened,
Closing,
Closed,
Faulted
}
@@ -0,0 +1,21 @@
using System;
using System.Xml.Serialization;
namespace Asb.Base.V2;
[Serializable]
[XmlType(Namespace = "urn:asb.se:2")]
public class ConnectionValidator
{
[XmlElement(ElementName = "ConnectionId", Order = 0)]
public Guid ConnectionId { get; set; }
[XmlElement(ElementName = "MessageNumber", Order = 1)]
public ulong MessageNumber { get; set; }
[XmlElement(ElementName = "MessageAuthenticationCode", DataType = "base64Binary", Order = 2)]
public byte[] MessageAuthenticationCode { get; set; }
[XmlElement(ElementName = "SignatureInitializationVector", DataType = "base64Binary", Order = 3)]
public byte[] SignatureInitializationVector { get; set; }
}
@@ -0,0 +1,35 @@
namespace Asb.Base.V2;
public class ConsumerMetadata
{
public string UserName { get; private set; }
public string HostName { get; private set; }
public string SessionId { get; private set; }
public string SessionHostName { get; private set; }
public string ApplicationName { get; private set; }
public ClientAccess Access { get; set; }
public ConsumerMetadata(string userName, string hostName, string sessionId, string sessionHostName, string applicationName, ClientAccess access)
{
UserName = userName;
HostName = hostName;
SessionId = sessionId;
SessionHostName = sessionHostName;
ApplicationName = applicationName;
Access = access;
}
public static ConsumerMetadata Create(ClientMetadata metadata)
{
if (metadata == null)
{
return new ConsumerMetadata(string.Empty, string.Empty, string.Empty, string.Empty, string.Empty, ClientAccess.FullAccess);
}
return new ConsumerMetadata(metadata.UserName, metadata.HostName, metadata.SessionId, metadata.SessionHostName, metadata.ApplicationName, metadata.Access);
}
}
@@ -0,0 +1,14 @@
namespace Asb.Base.V2;
public class CustomEnum
{
public short Ordinal { get; private set; }
public string OrdinalValue { get; private set; }
public CustomEnum(short ordinal, string ordinalValue)
{
Ordinal = ordinal;
OrdinalValue = ordinalValue;
}
}
@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
namespace Asb.Base.V2;
public static class DataConversionUtilities
{
public static string ToBase64(this string value)
{
string result = string.Empty;
if (value != null)
{
result = Encoding.UTF8.GetBytes(value).ToBase64();
}
return result;
}
public static string FromBase64(this string value)
{
string result = string.Empty;
if (value != null)
{
byte[] bytes = value.FromBase64ToByteArray();
result = Encoding.UTF8.GetString(bytes);
}
return result;
}
public static string ToBase64(this byte[] value)
{
string result = string.Empty;
try
{
result = Convert.ToBase64String(value);
}
catch
{
}
return result;
}
public static string ToHex(this byte[] value)
{
StringBuilder stringBuilder = new StringBuilder();
if (value != null)
{
foreach (byte b in value)
{
stringBuilder.Append(b.ToString("X2", CultureInfo.CurrentCulture));
}
}
return stringBuilder.ToString();
}
public static byte[] FromBase64ToByteArray(this string value)
{
byte[] result = null;
if (value != null)
{
try
{
result = Convert.FromBase64String(value);
}
catch
{
}
}
return result;
}
public static byte[] FromHexToByteArray(this string value)
{
List<byte> list = new List<byte>();
if (value != null)
{
string text = value.Replace(" ", string.Empty);
text = text.Replace("\r", string.Empty);
text = text.Replace("\n", string.Empty);
if (text.Length % 2 == 0)
{
for (int i = 0; i < text.Length; i += 2)
{
if (byte.TryParse(text.Substring(i, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result))
{
list.Add(result);
}
}
}
}
return list.ToArray();
}
}
@@ -0,0 +1,21 @@
using System.ServiceModel;
using System.Xml.Serialization;
namespace Asb.Base.V2;
[MessageContract(WrapperName = "Disconnect", WrapperNamespace = "urn:msg.asb.se:2", IsWrapped = true)]
public class DisconnectRequest : ConnectedRequest
{
[MessageBodyMember(Namespace = "urn:msg.asb.se:2", Order = 0)]
[XmlElement(ElementName = "ConsumerAuthenticationData")]
public AuthenticationData ConsumerAuthenticationData { get; set; }
public DisconnectRequest()
{
}
public DisconnectRequest(AuthenticationData consumerAuthenticationData)
{
ConsumerAuthenticationData = consumerAuthenticationData;
}
}
@@ -0,0 +1,9 @@
namespace Asb.Base.V2;
public enum DiscoveryScope
{
Default,
Local,
Global,
Closest
}
@@ -0,0 +1,17 @@
using System;
using System.Xml.Serialization;
namespace Asb.Base.V2;
[Serializable]
[XmlInclude(typeof(SourceHandle))]
[XmlInclude(typeof(SolutionHandle))]
[XmlType(Namespace = "urn:data.asb.se:2")]
public class EntityHandle
{
[XmlElement(ElementName = "Key", Order = 0)]
public Value Key { get; set; }
[XmlElement(ElementName = "NamePath", Order = 1)]
public string NamePath { get; set; }
}
@@ -0,0 +1,10 @@
using System.ServiceModel;
using System.Xml.Serialization;
namespace Asb.Base.V2;
[MessageContract(WrapperName = "GetStatusItems", WrapperNamespace = "urn:msg.asb.se:2", IsWrapped = true)]
[XmlRoot(Namespace = "urn:msg.asb.se:2")]
public class GetStatusItemsRequest : ConnectedRequest
{
}
@@ -0,0 +1,23 @@
using System.ServiceModel;
using System.Xml.Serialization;
namespace Asb.Base.V2;
[MessageContract(WrapperName = "GetStatusItemsResponse", WrapperNamespace = "urn:msg.asb.se:2", IsWrapped = true)]
[XmlRoot(Namespace = "urn:msg.asb.se:2")]
public class GetStatusItemsResponse : ConnectedResponse
{
[MessageBodyMember(Namespace = "urn:msg.asb.se:2", Order = 2)]
[XmlElement(ElementName = "Items")]
public string[] Items { get; set; }
public GetStatusItemsResponse()
{
}
public GetStatusItemsResponse(ArchestrAResult result, string[] items, ConnectionState downstreamConnectionState)
: base(result, downstreamConnectionState)
{
Items = items;
}
}
@@ -0,0 +1,22 @@
using System.ServiceModel;
using System.Xml.Serialization;
namespace Asb.Base.V2;
[MessageContract(WrapperName = "GetStatus", WrapperNamespace = "urn:msg.asb.se:2", IsWrapped = true)]
[XmlRoot(Namespace = "urn:msg.asb.se:2")]
public class GetStatusRequest : ConnectedRequest
{
[MessageBodyMember(Namespace = "urn:msg.asb.se:2", Order = 0)]
[XmlElement(ElementName = "ItemsToReturn")]
public string[] ItemsToReturn { get; set; }
public GetStatusRequest()
{
}
public GetStatusRequest(string[] itemsToReturn)
{
ItemsToReturn = itemsToReturn;
}
}
@@ -0,0 +1,25 @@
using System.ServiceModel;
using System.Xml.Serialization;
using Asb.Base.V2.Serialization;
namespace Asb.Base.V2;
[MessageContract(WrapperName = "GetStatusResponse", WrapperNamespace = "urn:msg.asb.se:2", IsWrapped = true)]
[XmlRoot(Namespace = "urn:msg.asb.se:2")]
[BaseV2SerializerContractBehavior]
public class GetStatusResponse : ConnectedResponse
{
[MessageBodyMember(Namespace = "urn:msg.asb.se:2", Order = 2)]
[XmlElement(ElementName = "Items")]
public NamedValue[] Items { get; set; }
public GetStatusResponse()
{
}
public GetStatusResponse(ArchestrAResult result, NamedValue[] items, ConnectionState downstreamConnectionState)
: base(result, downstreamConnectionState)
{
Items = items;
}
}
@@ -0,0 +1,33 @@
using System.ServiceModel;
using Asb.Base.V2.Serialization;
namespace Asb.Base.V2;
[ServiceContract(Namespace = "urn:asb.se:2", ConfigurationName = "IAuthenticateAsb")]
[BaseV2SerializerContractBehavior]
public interface IAuthenticateAsb
{
[OperationContract(Action = "urn:asb.se:2/IAuthenticateAsb/Connect", ReplyAction = "urn:asb.se:2/IAuthenticateAsb/ConnectResponse")]
ConnectResponse Connect(ConnectRequest request);
[OperationContract(Action = "urn:asb.se:2/IAuthenticateAsb/AuthenticateMe", ReplyAction = "urn:asb.se:2/IAuthenticateAsb/AuthenticateMeResponse")]
AuthenticateMeResponse AuthenticateMe(AuthenticateMeRequest request);
[OperationContract(Action = "urn:asb.se:2/IAuthenticateAsb/Renew", ReplyAction = "urn:asb.se:2/IAuthenticateAsb/RenewResponse")]
RenewResponse Renew(RenewRequest request);
[OperationContract(Action = "urn:asb.se:2/IAuthenticateAsb/GetStatusItems", ReplyAction = "urn:asb.se:2/IAuthenticateAsb/GetStatusItemsResponse")]
GetStatusItemsResponse GetStatusItems(GetStatusItemsRequest request);
[OperationContract(Action = "urn:asb.se:2/IAuthenticateAsb/GetStatus", ReplyAction = "urn:asb.se:2/IAuthenticateAsb/GetStatusResponse")]
GetStatusResponse GetStatus(GetStatusRequest request);
[OperationContract(IsOneWay = true, Action = "urn:asb.se:2/IAuthenticateAsb/UpdateSystemAuthenticationConfiguration")]
void UpdateSystemAuthenticationConfiguration(UpdateSystemAuthenticationConfigurationRequest request);
[OperationContract(Action = "urn:asb.se:2/IAuthenticateAsb/KeepAlive")]
KeepAliveResponse KeepAlive(KeepAliveRequest request);
[OperationContract(IsOneWay = true, Action = "urn:asb.se:2/IAuthenticateAsb/Disconnect")]
void Disconnect(DisconnectRequest request);
}
@@ -0,0 +1,20 @@
using System;
namespace Asb.Base.V2;
public interface IBaseV2
{
Guid ConnectionId { get; set; }
DateTime ServiceLoadTime { get; set; }
void OnConnect(ulong timeout, ConsumerMetadata metadata);
ArchestrAResult KeepAlive();
ArchestrAResult GetStatusItems(out string[] items);
ArchestrAResult GetStatus(string[] itemsToReturn, out NamedValue[] items);
void OnDisconnect();
}
@@ -0,0 +1,21 @@
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Discovery;
using System.Threading;
using System.Xml;
namespace Asb.Base.V2;
internal interface IClientManagement
{
ConnectContext<T> CreateConnectContext<T>(EndpointAddress serviceEndpointAddress, Binding binding, string application, string user, CancellationToken cancellationToken) where T : class, IAuthenticateAsb;
void InjectCustomBehavior<T>(ChannelFactory<T> channelFactory) where T : class, IAuthenticateAsb;
bool EstablishSecureSession<T>(ConnectContext<T> context, string solutionName, ClientAccess access) where T : class, IAuthenticateAsb;
void DisconnectSecureSession<T>(ConnectContext<T> context) where T : class, IAuthenticateAsb;
IEnumerable<EndpointDiscoveryMetadata> DiscoverEndpointsForContract(XmlQualifiedName contract, string scopeRule);
}
@@ -0,0 +1,27 @@
using System;
using System.Numerics;
namespace Asb.Base.V2;
internal interface ISolutionParameters
{
string DefaultAsbSolutionName { get; }
string GetSolutionPassphrase(string asbSolution, Action<string> errorMessageHandler);
byte[] GetSolutionCertificate(string asbSolution);
string GetSolutionSaltValue(string asbSolution);
string GetSolutionHashAlgorithm(string asbSolution);
int GetSolutionPasswordIterations(string asbSolution);
string GetSolutionInitialVector(string asbSolution);
int GetSolutionKeySize(string asbSolution);
BigInteger GetSolutionPrime(string asbSolution);
BigInteger GetSolutionGenerator(string asbSolution);
}
@@ -0,0 +1,22 @@
using System.ServiceModel;
using System.Xml.Serialization;
namespace Asb.Base.V2;
[MessageContract(WrapperName = "KeepAlive", WrapperNamespace = "urn:msg.asb.se:2", IsWrapped = true)]
[XmlRoot(Namespace = "urn:msg.asb.se:2")]
public class KeepAliveRequest : ConnectedRequest
{
[MessageBodyMember(Namespace = "urn:msg.asb.se:2", Order = 0)]
[XmlElement(ElementName = "ConsumerAuthenticationData")]
public AuthenticationData ConsumerAuthenticationData { get; set; }
public KeepAliveRequest()
{
}
public KeepAliveRequest(AuthenticationData consumerAuthenticationData)
{
ConsumerAuthenticationData = consumerAuthenticationData;
}
}
@@ -0,0 +1,18 @@
using System.ServiceModel;
using System.Xml.Serialization;
namespace Asb.Base.V2;
[MessageContract(WrapperName = "KeepAliveResponse", WrapperNamespace = "urn:msg.asb.se:2", IsWrapped = true)]
[XmlRoot(Namespace = "urn:msg.asb.se:2")]
public class KeepAliveResponse : ConnectedResponse
{
public KeepAliveResponse()
{
}
public KeepAliveResponse(ArchestrAResult result, ConnectionState downstreamConnectionState)
: base(result, downstreamConnectionState)
{
}
}
@@ -0,0 +1,15 @@
using System;
using System.Xml.Serialization;
namespace Asb.Base.V2;
[Serializable]
[XmlType(Namespace = "urn:data.asb.se:2")]
public class NamedValue
{
[XmlElement(ElementName = "Name", Order = 0)]
public string Name { get; set; }
[XmlElement(ElementName = "Value", Order = 1)]
public Value Value { get; set; }
}
@@ -0,0 +1,23 @@
using System;
using System.Runtime.InteropServices;
namespace Asb.Base.V2;
internal static class NativeMethods
{
public enum WTS_INFO_CLASS
{
WTSSessionId = 4,
WTSClientName = 10
}
public static readonly IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
public const int WTS_CURRENT_SESSION = -1;
[DllImport("Wtsapi32.dll", CharSet = CharSet.Auto)]
public static extern bool WTSQuerySessionInformation(IntPtr hServer, int sessionId, WTS_INFO_CLASS wtsInfoClass, out IntPtr ppBuffer, out int pBytesReturned);
[DllImport("wtsapi32.dll", ExactSpelling = true)]
public static extern void WTSFreeMemory(IntPtr memory);
}
@@ -0,0 +1,12 @@
using System;
using System.Xml.Serialization;
namespace Asb.Base.V2;
[Serializable]
[XmlType(Namespace = "urn:data.asb.se:2")]
public class PublicKey
{
[XmlElement(ElementName = "Data", DataType = "base64Binary", Order = 0)]
public byte[] Data { get; set; }
}
@@ -0,0 +1,33 @@
using System;
using System.ServiceModel;
using System.Xml.Serialization;
namespace Asb.Base.V2;
[MessageContract(WrapperName = "Renew", WrapperNamespace = "urn:msg.asb.se:2", IsWrapped = true)]
[XmlRoot(Namespace = "urn:msg.asb.se:2")]
public class RenewRequest : ConnectedRequest
{
[MessageBodyMember(Namespace = "urn:msg.asb.se:2", Order = 0)]
[XmlElement(ElementName = "ConsumerAuthenticationData")]
public AuthenticationData ConsumerAuthenticationData { get; set; }
[MessageBodyMember(Namespace = "urn:msg.asb.se:2", Order = 1)]
[XmlElement(ElementName = "NewConnectionId")]
public Guid NewConnectionId { get; set; }
[MessageBodyMember(Namespace = "urn:msg.asb.se:2", Order = 2)]
[XmlElement(ElementName = "NewConsumerPublicKey")]
public PublicKey NewConsumerPublicKey { get; set; }
public RenewRequest()
{
}
public RenewRequest(AuthenticationData consumerAuthenticationData, Guid newConnectionId, PublicKey newConsumerPublicKey)
{
ConsumerAuthenticationData = consumerAuthenticationData;
NewConnectionId = newConnectionId;
NewConsumerPublicKey = newConsumerPublicKey;
}
}
@@ -0,0 +1,39 @@
using System;
using System.ServiceModel;
using System.Xml.Serialization;
namespace Asb.Base.V2;
[MessageContract(WrapperName = "RenewResponse", WrapperNamespace = "urn:msg.asb.se:2", IsWrapped = true)]
[XmlRoot(Namespace = "urn:msg.asb.se:2")]
public class RenewResponse : ConnectedResponse
{
[MessageBodyMember(Namespace = "urn:msg.asb.se:2", Order = 2)]
[XmlElement(ElementName = "NewConnectionId")]
public Guid NewConnectionId { get; set; }
[MessageBodyMember(Namespace = "urn:msg.asb.se:2", Order = 3)]
[XmlElement(ElementName = "NewConnectionLifetime", DataType = "duration")]
public string NewConnectionLifetime { get; set; }
[MessageBodyMember(Namespace = "urn:msg.asb.se:2", Order = 4)]
[XmlElement(ElementName = "NewServicePublicKey")]
public PublicKey NewServicePublicKey { get; set; }
[MessageBodyMember(Namespace = "urn:msg.asb.se:2", Order = 5)]
[XmlElement(ElementName = "NewServiceAuthenticationData")]
public AuthenticationData NewServiceAuthenticationData { get; set; }
public RenewResponse()
{
}
public RenewResponse(ArchestrAResult result, Guid newConnectionId, string newConnectionLifetime, PublicKey newServicePublicKey, AuthenticationData newServiceAuthenticationData)
: base(result)
{
NewConnectionId = newConnectionId;
NewConnectionLifetime = newConnectionLifetime;
NewServicePublicKey = newServicePublicKey;
NewServiceAuthenticationData = newServiceAuthenticationData;
}
}
@@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Xml.Linq;
using System.Xml.Serialization;
namespace Asb.Base.V2;
public static class SerializationExtensions
{
private static readonly Dictionary<Type, XmlSerializer> xmlSerializers = new Dictionary<Type, XmlSerializer>();
private static readonly object serializersLock = new object();
public static string ToXml(this object value)
{
string xmlText = string.Empty;
if (value != null)
{
try
{
using TextWriter textWriter = new StringWriter(CultureInfo.CurrentCulture);
lock (serializersLock)
{
XmlSerializer typeSerializer = GetTypeSerializer(value.GetType());
if (typeSerializer != null)
{
typeSerializer.Serialize(textWriter, value);
xmlText = textWriter.ToString();
}
}
}
catch
{
}
}
return NormalizeXmlText(xmlText);
}
private static XmlSerializer GetTypeSerializer(Type objectType)
{
XmlSerializer xmlSerializer = null;
if (objectType != null)
{
lock (serializersLock)
{
if (!xmlSerializers.ContainsKey(objectType))
{
string defaultNamespace = "urn:invensys.schemas";
object[] customAttributes = objectType.GetCustomAttributes(inherit: true);
for (int i = 0; i < customAttributes.Length; i++)
{
if (customAttributes[i] is XmlRootAttribute xmlRootAttribute)
{
defaultNamespace = xmlRootAttribute.Namespace;
break;
}
}
xmlSerializer = new XmlSerializer(objectType, defaultNamespace);
xmlSerializers.Add(objectType, xmlSerializer);
}
else
{
xmlSerializer = xmlSerializers[objectType];
}
}
}
return xmlSerializer;
}
private static string NormalizeXmlText(string xmlText)
{
if (string.IsNullOrEmpty(xmlText))
{
return xmlText;
}
if (Environment.Is64BitProcess)
{
using StringReader textReader = new StringReader(xmlText);
using IEnumerator<XElement> enumerator = XDocument.Load(textReader).Elements().GetEnumerator();
if (enumerator.MoveNext())
{
XElement current = enumerator.Current;
XAttribute xAttribute = current.Attribute(XNamespace.Xmlns + "xsd");
XAttribute xAttribute2 = current.Attribute(XNamespace.Xmlns + "xsi");
if (xAttribute != null && xAttribute2 != null)
{
current.ReplaceAttributes(xAttribute2, xAttribute);
}
using TextWriter textWriter = new StringWriter(CultureInfo.CurrentCulture);
current.Save(textWriter);
xmlText = textWriter.ToString();
}
}
return xmlText;
}
}
@@ -0,0 +1,8 @@
using System.ServiceModel;
namespace Asb.Base.V2;
[MessageContract]
public class ServiceMessage
{
}
@@ -0,0 +1,12 @@
using System;
using System.Xml.Serialization;
namespace Asb.Base.V2;
[Serializable]
[XmlType(Namespace = "urn:data.asb.se:2")]
public class SolutionHandle : SourceHandle
{
[XmlElement(ElementName = "SolutionName", Order = 0)]
public string SolutionName { get; set; }
}
@@ -0,0 +1,102 @@
using System;
using System.Numerics;
using System.Text;
using ArchestrAServices.Common;
namespace Asb.Base.V2;
public class SolutionParameters : ISolutionParameters
{
public string DefaultAsbSolutionName => SvcUtilities.ReadKeyValue(string.Empty, "DefaultASBSolution");
public string GetSolutionPassphrase(string asbSolution, Action<string> errorMessageHandler)
{
string passphrase;
string solutionPassphrase = RegistryHandler.GetSolutionPassphrase(asbSolution, out passphrase);
if (!string.IsNullOrEmpty(solutionPassphrase))
{
errorMessageHandler?.Invoke(solutionPassphrase);
}
return passphrase;
}
public byte[] GetSolutionCertificate(string asbSolution)
{
string s;
if ((s = SvcUtilities.ReadKeyValue(asbSolution, "Certificate")) != null)
{
return Encoding.UTF8.GetBytes(s);
}
return null;
}
public string GetSolutionSaltValue(string asbSolution)
{
string result;
if ((result = SvcUtilities.ReadKeyValue(asbSolution, "saltValue")) != null)
{
return result;
}
return null;
}
public string GetSolutionHashAlgorithm(string asbSolution)
{
string result;
if ((result = SvcUtilities.ReadKeyValue(asbSolution, "HashAlgorthim")) != null)
{
return result;
}
return null;
}
public int GetSolutionPasswordIterations(string asbSolution)
{
string s;
if ((s = SvcUtilities.ReadKeyValue(asbSolution, "passowordIterations")) != null && int.TryParse(s, out var result))
{
return result;
}
return 0;
}
public string GetSolutionInitialVector(string asbSolution)
{
string result;
if ((result = SvcUtilities.ReadKeyValue(asbSolution, "initailizationVector")) != null)
{
return result;
}
return null;
}
public int GetSolutionKeySize(string asbSolution)
{
string s;
if ((s = SvcUtilities.ReadKeyValue(asbSolution, "keySize")) != null && int.TryParse(s, out var result))
{
return result;
}
return 0;
}
public BigInteger GetSolutionPrime(string asbSolution)
{
string value;
if ((value = SvcUtilities.ReadKeyValue(asbSolution, "Prime")) != null && BigInteger.TryParse(value, out var result))
{
return result;
}
return BigInteger.Zero;
}
public BigInteger GetSolutionGenerator(string asbSolution)
{
string value;
if ((value = SvcUtilities.ReadKeyValue(asbSolution, "Generator")) != null && BigInteger.TryParse(value, out var result))
{
return result;
}
return BigInteger.Zero;
}
}
@@ -0,0 +1,13 @@
using System;
using System.Xml.Serialization;
namespace Asb.Base.V2;
[Serializable]
[XmlInclude(typeof(SolutionHandle))]
[XmlType(Namespace = "urn:data.asb.se:2")]
public class SourceHandle : EntityHandle
{
[XmlElement(ElementName = "SourceId", Order = 0)]
public ushort SourceId { get; set; }
}
@@ -0,0 +1,251 @@
using System;
using System.Numerics;
using System.Security.Cryptography;
using ArchestrAServices.Common;
namespace Asb.Base.V2;
public class SysAuthParameters
{
private const string SDecimal768 = "1552518092300708935130918131258481755631334049434514313202351194902966239949102107258669453876591642442910007680288864229150803718918046342632727613031282983744380820890196288509170691316593175367469551763119843371637221007210577919";
private static readonly byte[] sOakley768 = new byte[96]
{
255, 255, 255, 255, 255, 255, 255, 255, 201, 15,
218, 162, 33, 104, 194, 52, 196, 198, 98, 139,
128, 220, 28, 209, 41, 2, 78, 8, 138, 103,
204, 116, 2, 11, 190, 166, 59, 19, 155, 34,
81, 74, 8, 121, 142, 52, 4, 221, 239, 149,
25, 179, 205, 58, 67, 27, 48, 43, 10, 109,
242, 95, 20, 55, 79, 225, 53, 109, 109, 81,
194, 69, 228, 133, 181, 118, 98, 94, 126, 198,
244, 76, 66, 233, 166, 58, 54, 32, 255, 255,
255, 255, 255, 255, 255, 255
};
private const string SDecimal1024 = "179769313486231590770839156793787453197860296048756011706444423684197180216158519368947833795864925541502180565485980503646440548199239100050792877003355816639229553136239076508735759914822574862575007425302077447712589550957937778424442426617334727629299387668709205606050270810842907692932019128194";
private static readonly byte[] sOakley1024 = new byte[128]
{
255, 255, 255, 255, 255, 255, 255, 255, 201, 15,
218, 162, 33, 104, 194, 52, 196, 198, 98, 139,
128, 220, 28, 209, 41, 2, 78, 8, 138, 103,
204, 116, 2, 11, 190, 166, 59, 19, 155, 34,
81, 74, 8, 121, 142, 52, 4, 221, 239, 149,
25, 179, 205, 58, 67, 27, 48, 43, 10, 109,
242, 95, 20, 55, 79, 225, 53, 109, 109, 81,
194, 69, 228, 133, 181, 118, 98, 94, 126, 198,
244, 76, 66, 233, 166, 55, 237, 107, 11, 255,
92, 182, 244, 6, 183, 237, 238, 56, 107, 251,
90, 137, 159, 165, 174, 159, 36, 17, 124, 75,
31, 230, 73, 40, 102, 81, 236, 230, 83, 129,
255, 255, 255, 255, 255, 255, 255, 255
};
private const string SDecimal1536 = "2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919";
private static readonly byte[] sOakley1536 = new byte[192]
{
255, 255, 255, 255, 255, 255, 255, 255, 201, 15,
218, 162, 33, 104, 194, 52, 196, 198, 98, 139,
128, 220, 28, 209, 41, 2, 78, 8, 138, 103,
204, 116, 2, 11, 190, 166, 59, 19, 155, 34,
81, 74, 8, 121, 142, 52, 4, 221, 239, 149,
25, 179, 205, 58, 67, 27, 48, 43, 10, 109,
242, 95, 20, 55, 79, 225, 53, 109, 109, 81,
194, 69, 228, 133, 181, 118, 98, 94, 126, 198,
244, 76, 66, 233, 166, 55, 237, 107, 11, 255,
92, 182, 244, 6, 183, 237, 238, 56, 107, 251,
90, 137, 159, 165, 174, 159, 36, 17, 124, 75,
31, 230, 73, 40, 102, 81, 236, 228, 91, 61,
194, 0, 124, 184, 161, 99, 191, 5, 152, 218,
72, 54, 28, 85, 211, 154, 105, 22, 63, 168,
253, 36, 207, 95, 131, 101, 93, 35, 220, 163,
173, 150, 28, 98, 243, 86, 32, 133, 82, 187,
158, 213, 41, 7, 112, 150, 150, 109, 103, 12,
53, 78, 74, 188, 152, 4, 241, 116, 108, 8,
202, 35, 115, 39, 255, 255, 255, 255, 255, 255,
255, 255
};
private const int DhKeySizeDft = 1024;
private const int DhSecretSizeDft = 160;
private static readonly string dhPassphraseDft = Environment.MachineName;
private const uint ConnectionLifetimeDft = 60000u;
private const string SaltValueDft = "s@1tValue";
private static readonly string hashAlgorithmDft = CngAlgorithm.MD5.ToString();
private const int PasswordIterationsDft = 1;
private const string InitialVectorDft = "ba172e9941be138b";
private const int KeySizeDft = 256;
private readonly ISolutionParameters solutionParameterSource;
private string sysAuthPassphrase;
public string AsbSolutionName { get; set; }
public bool AsbSolutionValid { get; set; }
public int DhKeySize { get; set; }
public int DhSecretSize { get; set; }
public BigInteger DhP { get; set; }
public BigInteger DhG { get; set; }
public string DhPassphrase
{
get
{
return sysAuthPassphrase;
}
set
{
ResetToDefaults();
sysAuthPassphrase = value;
AsbSolutionValid = true;
}
}
public byte[] DhCertificate { get; private set; }
public uint ConnectionLifetime { get; set; }
public string SaltValue { get; set; }
public string HashAlgorithm { get; set; }
public int PasswordIterations { get; set; }
public string InitialVector { get; set; }
public int KeySize { get; set; }
public SysAuthParameters(string asbSolutionName = null)
{
ServiceTrace.LogVerbose("SysAuthParameters constructor with asbSolutionName = {0}", string.IsNullOrEmpty(asbSolutionName) ? "<null>" : asbSolutionName);
AsbSolutionName = asbSolutionName;
solutionParameterSource = new SolutionParameters();
AsbSolutionValid = false;
ResetToDefaults();
LoadAsbSolution();
}
internal SysAuthParameters(string asbSolutionName, ISolutionParameters parameters)
{
ServiceTrace.LogVerbose("SysAuthParameters constructor with asbSolutionName = {0}", string.IsNullOrEmpty(asbSolutionName) ? "<null>" : asbSolutionName);
AsbSolutionName = asbSolutionName;
solutionParameterSource = parameters;
AsbSolutionValid = false;
ResetToDefaults();
LoadAsbSolution();
}
private void ResetToDefaults()
{
AsbSolutionValid = false;
DhKeySize = 1024;
DhSecretSize = 160;
sysAuthPassphrase = dhPassphraseDft;
DhCertificate = null;
ConnectionLifetime = 60000u;
SaltValue = "s@1tValue";
HashAlgorithm = hashAlgorithmDft;
PasswordIterations = 1;
InitialVector = "ba172e9941be138b";
KeySize = 256;
GenerateKey();
}
private void LoadAsbSolution()
{
ServiceTrace.LogResume("LoadAsbSolution entry");
try
{
if (solutionParameterSource == null)
{
ServiceTrace.LogError("LoadAsbSolution: No solution source provided");
AsbSolutionValid = false;
return;
}
if (string.IsNullOrEmpty(AsbSolutionName))
{
AsbSolutionName = solutionParameterSource.DefaultAsbSolutionName;
if (string.IsNullOrEmpty(AsbSolutionName))
{
ServiceTrace.LogError("LoadAsbSolution: Unable to get default ASB solution name");
AsbSolutionValid = false;
}
ServiceTrace.LogInfo("LoadAsbSolution created with empty solution name, resetting to default '{0}'", string.IsNullOrEmpty(AsbSolutionName) ? "<null>" : AsbSolutionName);
}
AsbSolutionValid = false;
if (!string.IsNullOrEmpty(AsbSolutionName))
{
ServiceTrace.LogVerbose("LoadAsbSolution: Using solution {0}", AsbSolutionName);
string errorMessage = string.Empty;
DhPassphrase = solutionParameterSource.GetSolutionPassphrase(AsbSolutionName, delegate(string msg)
{
errorMessage = msg;
});
if (string.IsNullOrEmpty(errorMessage))
{
DhCertificate = solutionParameterSource.GetSolutionCertificate(AsbSolutionName);
SaltValue = solutionParameterSource.GetSolutionSaltValue(AsbSolutionName);
HashAlgorithm = solutionParameterSource.GetSolutionHashAlgorithm(AsbSolutionName);
PasswordIterations = solutionParameterSource.GetSolutionPasswordIterations(AsbSolutionName);
InitialVector = solutionParameterSource.GetSolutionInitialVector(AsbSolutionName);
KeySize = solutionParameterSource.GetSolutionKeySize(AsbSolutionName);
DhP = solutionParameterSource.GetSolutionPrime(AsbSolutionName);
DhG = solutionParameterSource.GetSolutionGenerator(AsbSolutionName);
AsbSolutionValid = true;
}
else
{
ServiceTrace.LogError("LoadAsbSolution: Error loading passphrase: " + errorMessage);
}
}
}
catch (Exception ex)
{
ServiceTrace.LogError("LoadAsbSolution: Exception caught: {0}", ex.Message);
AsbSolutionValid = false;
}
ServiceTrace.LogSuspend("LoadAsbSolution exit");
}
private void GenerateKey()
{
bool flag;
BigInteger result;
if (DhKeySize == 768)
{
flag = BigInteger.TryParse("1552518092300708935130918131258481755631334049434514313202351194902966239949102107258669453876591642442910007680288864229150803718918046342632727613031282983744380820890196288509170691316593175367469551763119843371637221007210577919", out result);
}
else if (DhKeySize == 1024)
{
flag = BigInteger.TryParse("179769313486231590770839156793787453197860296048756011706444423684197180216158519368947833795864925541502180565485980503646440548199239100050792877003355816639229553136239076508735759914822574862575007425302077447712589550957937778424442426617334727629299387668709205606050270810842907692932019128194", out result);
}
else
{
if (DhKeySize != 1536)
{
throw new ArgumentException("Invalid bit size.");
}
flag = BigInteger.TryParse("2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919", out result);
}
if (flag)
{
DhP = result;
}
DhG = new BigInteger(22);
}
}
@@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
namespace Asb.Base.V2;
public class SysAuthenticatorClientCache : SynchronizedKeyedCollection<Guid, SystemAuthenticationClientAuthentication>
{
private static readonly SysAuthenticatorClientCache clientConnections = new SysAuthenticatorClientCache();
private static object cacheLockObject = new object();
private SysAuthenticatorClientCache()
{
}
public static IEnumerable<SystemAuthenticationClientAuthentication> GetAllClientAuthenticators()
{
List<SystemAuthenticationClientAuthentication> list = new List<SystemAuthenticationClientAuthentication>();
lock (cacheLockObject)
{
list.AddRange(clientConnections.Items);
return list;
}
}
public static void AddClientAuthenticator(SystemAuthenticationClientAuthentication clientAuthenticator)
{
if (clientAuthenticator == null)
{
return;
}
lock (cacheLockObject)
{
if (!clientConnections.Contains(clientAuthenticator.ConnectionId))
{
clientConnections.Add(clientAuthenticator);
}
}
}
public static SystemAuthenticationClientAuthentication GetClientAuthenticator(Guid connectionId)
{
SystemAuthenticationClientAuthentication result = null;
lock (cacheLockObject)
{
if (clientConnections.Contains(connectionId))
{
result = clientConnections[connectionId];
}
}
return result;
}
public static SystemAuthenticationClientAuthentication RemoveClientAuthenticator(Guid connectionId)
{
SystemAuthenticationClientAuthentication result = null;
lock (cacheLockObject)
{
if (clientConnections.Contains(connectionId))
{
result = clientConnections[connectionId];
clientConnections.Remove(connectionId);
}
}
return result;
}
protected override Guid GetKeyForItem(SystemAuthenticationClientAuthentication item)
{
return item.ConnectionId;
}
}
@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Asb.Base.V2;
public class SysAuthenticatorServiceCache : SynchronizedKeyedCollection<Guid, SystemAuthenticationServiceAuthentication>
{
private static readonly SysAuthenticatorServiceCache serviceConnections = new SysAuthenticatorServiceCache();
private static readonly object serviceCacheLockObject = new object();
private SysAuthenticatorServiceCache()
{
}
public static IEnumerable<SystemAuthenticationServiceAuthentication> GetAllServiceAuthenticators()
{
return serviceConnections.Items.AsEnumerable();
}
public static void AddServiceAuthenticator(SystemAuthenticationServiceAuthentication serviceAuthenticator)
{
if (serviceAuthenticator == null)
{
return;
}
lock (serviceCacheLockObject)
{
if (!serviceConnections.Contains(serviceAuthenticator.ConnectionId))
{
serviceConnections.Add(serviceAuthenticator);
}
}
}
public static SystemAuthenticationServiceAuthentication GetServiceAuthenticator(Guid connectionId)
{
SystemAuthenticationServiceAuthentication result = null;
lock (serviceCacheLockObject)
{
if (serviceConnections.Contains(connectionId))
{
result = serviceConnections[connectionId];
}
}
return result;
}
public static SystemAuthenticationServiceAuthentication RemoveServiceAuthenticator(Guid connectionId)
{
SystemAuthenticationServiceAuthentication serviceAuthenticator = GetServiceAuthenticator(connectionId);
if (serviceAuthenticator != null)
{
lock (serviceCacheLockObject)
{
serviceConnections.Remove(connectionId);
}
}
return serviceAuthenticator;
}
protected override Guid GetKeyForItem(SystemAuthenticationServiceAuthentication item)
{
return item.ConnectionId;
}
}
@@ -0,0 +1,142 @@
using System;
using System.Globalization;
using System.Text;
using ArchestrAServices.Common;
namespace Asb.Base.V2;
public class SystemAuthenticationClientAuthentication : SystemAuthenticationConnectionBase
{
public uint Timeout { get; set; }
public SystemAuthenticationClientAuthentication(string asbSolution)
: base(asbSolution)
{
Reset();
base.ReasonSecureSessionNotEstablished = "Constructed";
}
public static bool EstablishSecureSession(string asbSolution, ClientMetadata clientMetadata, Func<ConnectRequest, ConnectResponse> connectDelegate, Func<AuthenticateMeRequest, AuthenticateMeResponse> authenticateMeDelegate, Action<Guid> connectionIdHandler, Action<string> reasonSecureSessionNotEstablishedHandler)
{
SystemAuthenticationClientAuthentication systemAuthenticationClientAuthentication = new SystemAuthenticationClientAuthentication(asbSolution);
SysAuthenticatorClientCache.AddClientAuthenticator(systemAuthenticationClientAuthentication);
Guid connectionId = systemAuthenticationClientAuthentication.ConnectionId;
PublicKey consumerPublicKey = new PublicKey
{
Data = systemAuthenticationClientAuthentication.LocalPublicKey
};
ConnectRequest arg = new ConnectRequest(connectionId, consumerPublicKey, asbSolution);
ConnectResponse connectResponse = null;
try
{
connectResponse = connectDelegate?.Invoke(arg);
}
catch (Exception ex)
{
string text = string.Format(CultureInfo.CurrentCulture, "Exception connecting to service during EstablishSecureSession: {0}", new object[1] { ex.Message });
ServiceTrace.LogWarning(text);
reasonSecureSessionNotEstablishedHandler?.Invoke(text);
}
if (connectResponse != null)
{
if (connectResponse.Result.Success)
{
systemAuthenticationClientAuthentication.RemotePublicKey = connectResponse.ServicePublicKey.Data;
systemAuthenticationClientAuthentication.ReasonSecureSessionNotEstablished = string.Empty;
if (systemAuthenticationClientAuthentication.ValidResponse(connectResponse, forceHmac: true))
{
byte[] initializationVector;
AuthenticateMeRequest authenticateMeRequest = new AuthenticateMeRequest(new AuthenticationData
{
Data = systemAuthenticationClientAuthentication.CalculateAuthenticationData(systemAuthenticationClientAuthentication.LocalPublicKey, systemAuthenticationClientAuthentication.RemotePublicKey, out initializationVector),
InitializationVector = initializationVector
}, clientMetadata);
systemAuthenticationClientAuthentication.Sign(authenticateMeRequest, forceHmac: true);
AuthenticateMeResponse authenticateMeResponse = authenticateMeDelegate(authenticateMeRequest);
if (authenticateMeResponse != null && authenticateMeResponse.Result.Success)
{
systemAuthenticationClientAuthentication.SecureSessionEstablished = true;
connectionIdHandler?.Invoke(connectionId);
}
else
{
ServiceTrace.LogVerbose("Service rejected the connection at the AuthenticateMe stage");
string obj = "Service rejected the connection at the AuthenticateMe stage";
if (authenticateMeResponse != null)
{
obj = ((authenticateMeResponse.Result.ErrorMessages == null || authenticateMeResponse.Result.ErrorMessages.Length == 0) ? string.Format(CultureInfo.CurrentCulture, "Service returned error {0} in response to AuthenticateMe method, cannot establish secure connection.", new object[1] { authenticateMeResponse.Result.ResultCodeAsError }) : authenticateMeResponse.Result.ErrorMessages[0]);
}
reasonSecureSessionNotEstablishedHandler?.Invoke(obj);
SysAuthenticatorClientCache.RemoveClientAuthenticator(connectionId);
connectionIdHandler?.Invoke(Guid.Empty);
}
}
else
{
if (!string.IsNullOrEmpty(systemAuthenticationClientAuthentication.ReasonSecureSessionNotEstablished))
{
reasonSecureSessionNotEstablishedHandler?.Invoke("Service returned response to Connect method, but validation failed: " + systemAuthenticationClientAuthentication.ReasonSecureSessionNotEstablished);
}
else
{
reasonSecureSessionNotEstablishedHandler?.Invoke("Service returned response to Connect method, but validation data was not valid, cannot establish secure session");
}
SysAuthenticatorClientCache.RemoveClientAuthenticator(connectionId);
connectionIdHandler?.Invoke(Guid.Empty);
}
}
else
{
if (connectResponse.Result.ErrorMessages != null && connectResponse.Result.ErrorMessages.Length != 0)
{
reasonSecureSessionNotEstablishedHandler?.Invoke(string.Format(CultureInfo.CurrentCulture, "Service returned error {0} in response to Connect method, cannot establish secure connection. Additional information:", new object[1] { connectResponse.Result.ResultCodeAsError }));
string[] errorMessages = connectResponse.Result.ErrorMessages;
foreach (string obj2 in errorMessages)
{
reasonSecureSessionNotEstablishedHandler?.Invoke(obj2);
}
}
else
{
reasonSecureSessionNotEstablishedHandler?.Invoke(string.Format(CultureInfo.CurrentCulture, "Service returned error {0} in response to Connect method, cannot establish secure connection.", new object[1] { connectResponse.Result.ResultCodeAsError }));
}
SysAuthenticatorClientCache.RemoveClientAuthenticator(connectionId);
connectionIdHandler?.Invoke(Guid.Empty);
}
}
else
{
SysAuthenticatorClientCache.RemoveClientAuthenticator(connectionId);
connectionIdHandler?.Invoke(Guid.Empty);
}
return systemAuthenticationClientAuthentication.SecureSessionEstablished;
}
public void AbortSession()
{
Reset();
base.ReasonSecureSessionNotEstablished = "Session Aborted";
}
public static void DisconnectSecureSession(Guid connectionId, Action<DisconnectRequest> disconnectDelegate)
{
SystemAuthenticationClientAuthentication clientAuthenticator = SysAuthenticatorClientCache.GetClientAuthenticator(connectionId);
if (clientAuthenticator != null)
{
byte[] initializationVector;
DisconnectRequest disconnectRequest = new DisconnectRequest(new AuthenticationData
{
Data = clientAuthenticator.EncypherWithNewInitializationVector(Encoding.UTF8.GetBytes(clientAuthenticator.ConnectionId.ToString()), out initializationVector),
InitializationVector = initializationVector
});
clientAuthenticator.Sign(disconnectRequest, forceHmac: false);
disconnectDelegate?.Invoke(disconnectRequest);
}
}
private new void Reset()
{
base.Reset();
Timeout = 10000u;
}
}
@@ -0,0 +1,509 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Numerics;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using ArchestrAServices.Common;
namespace Asb.Base.V2;
public class SystemAuthenticationConnectionBase
{
private static readonly RNGCryptoServiceProvider random = new RNGCryptoServiceProvider();
private static readonly byte[] passwordsalt = Encoding.ASCII.GetBytes("ArchestrAService");
protected static string AsbAuthenticationVersion = "V2";
protected static readonly object MessageNumberLock = new object();
private readonly List<ulong> outOfSyncMessageNumbers = new List<ulong>();
private ulong highestMessageNumberReceived;
private byte[] cryptoKey;
private byte[] encryptionKey;
protected SysAuthParameters SolutionParameters;
protected byte[] PrivateKey;
protected byte[] LocalPublicKey;
protected byte[] RemotePublicKey;
protected ulong NextMessageNumber = 1uL;
internal static ISolutionParameters TestParameters { private get; set; }
internal byte[] CryptoKey => cryptoKey ?? (cryptoKey = CalculateCryptoKey());
internal byte[] EncryptionKey => encryptionKey ?? (encryptionKey = CalculateEncryptionKey());
private byte[] SolutionPassphrase
{
get
{
byte[] result = null;
if (SolutionParameters.AsbSolutionValid)
{
if (!string.IsNullOrEmpty(SolutionParameters.DhPassphrase))
{
result = Encoding.UTF8.GetBytes(SolutionParameters.DhPassphrase);
}
if (SolutionParameters.DhCertificate != null && SolutionParameters.DhCertificate.Length != 0)
{
result = new X509Certificate(SolutionParameters.DhCertificate).GetPublicKey();
}
}
return result;
}
}
public Guid ConnectionId { get; set; } = Guid.Empty;
public ConnectionValidator ConnectionValidator { get; protected set; }
public bool SecureSessionEstablished { get; protected set; }
public string ReasonSecureSessionNotEstablished { get; protected set; }
public string DhPassphrase
{
get
{
return SolutionParameters.DhPassphrase;
}
set
{
SolutionParameters.DhPassphrase = value;
}
}
public string DhHashAlgorithm => SolutionParameters.HashAlgorithm;
public string DhAsbSolutionName => SolutionParameters.AsbSolutionName;
public SystemAuthenticationConnectionBase(string asbSolutionName = null)
{
if (TestParameters != null)
{
SolutionParameters = new SysAuthParameters(asbSolutionName, TestParameters);
}
else
{
SolutionParameters = new SysAuthParameters(asbSolutionName);
}
ReasonSecureSessionNotEstablished = "Constructed";
Reset();
}
protected void Reset()
{
SecureSessionEstablished = false;
ReasonSecureSessionNotEstablished = "Reset";
ConnectionId = Guid.NewGuid();
PrivateKey = GetPrivateKey(SolutionParameters.KeySize);
LocalPublicKey = CalculatePublicKey(PrivateKey);
cryptoKey = null;
SecureSessionEstablished = false;
}
private byte[] GetPrivateKey(int length)
{
byte[] array = null;
if (length > 0)
{
BigInteger bigInteger = SolutionParameters.DhP - new BigInteger(1);
BigInteger bigInteger2 = new BigInteger(0);
while (bigInteger2 >= bigInteger || bigInteger2 <= 0L)
{
array = new byte[length / 8];
random.GetBytes(array);
bigInteger2 = new BigInteger(array);
}
}
return array;
}
protected byte[] CalculatePublicKey(byte[] privateKey)
{
BigInteger exponent = new BigInteger(privateKey);
BigInteger dhG = SolutionParameters.DhG;
BigInteger dhP = SolutionParameters.DhP;
return BigInteger.ModPow(dhG, exponent, dhP).ToByteArray();
}
protected byte[] CalculateConnectionKey(byte[] remotePublicKey, byte[] localPrivateKey)
{
BigInteger value = new BigInteger(remotePublicKey);
BigInteger exponent = new BigInteger(localPrivateKey);
BigInteger dhP = SolutionParameters.DhP;
return BigInteger.ModPow(value, exponent, dhP).ToByteArray();
}
private HMAC NewSolutionHmac(bool forceHmac)
{
HMAC result;
switch (DhHashAlgorithm.ToLower())
{
case "md5":
ServiceTrace.LogVerbose("Solution HMAC is MD5");
result = new HMACMD5(CryptoKey);
break;
case "sha1":
ServiceTrace.LogVerbose("Solution HMAC is SHA1");
result = new HMACSHA1(CryptoKey);
break;
case "sha512":
ServiceTrace.LogVerbose("Solution HMAC is SHA512");
result = new HMACSHA512(CryptoKey);
break;
default:
ServiceTrace.LogVerbose("Solution HMAC is NONE");
result = null;
if (forceHmac)
{
result = new HMACSHA1(CryptoKey);
}
break;
}
return result;
}
public bool ValidRequest(ConnectedRequest request, bool forceHmac)
{
bool flag = false;
if (request == null)
{
ReasonSecureSessionNotEstablished = "ValidRequest: The message is null, cannot validate";
return false;
}
if (request.ConnectionValidator == null)
{
ReasonSecureSessionNotEstablished = "ValidRequest: The message ConnectionValidator field is null, cannot validate";
return false;
}
ConnectionValidator connectionValidator = request.ConnectionValidator;
byte[] messageAuthenticationCode = connectionValidator.MessageAuthenticationCode;
byte[] signatureInitializationVector = connectionValidator.SignatureInitializationVector;
byte[] array = null;
using (HMAC hMAC = NewSolutionHmac(forceHmac))
{
if (hMAC != null)
{
connectionValidator.MessageAuthenticationCode = new byte[0];
connectionValidator.SignatureInitializationVector = new byte[0];
byte[] bytes = Encoding.UTF8.GetBytes(request.ToXml());
connectionValidator.MessageAuthenticationCode = messageAuthenticationCode;
connectionValidator.SignatureInitializationVector = signatureInitializationVector;
byte[] array2 = hMAC.ComputeHash(bytes);
byte[] array3 = Decypher(messageAuthenticationCode, signatureInitializationVector);
bool flag2 = false;
if (array3 != null && array2.Length == array3.Length)
{
flag2 = true;
for (int i = 0; i < array2.Length; i++)
{
if (array2[i] != array3[i])
{
flag2 = false;
break;
}
}
}
array = ((!flag2) ? new byte[0] : messageAuthenticationCode);
}
}
if (array != null)
{
if (messageAuthenticationCode != null && array.Length == messageAuthenticationCode.Length)
{
flag = true;
for (int j = 0; j < messageAuthenticationCode.Length; j++)
{
if (messageAuthenticationCode[j] != array[j])
{
if (string.IsNullOrEmpty(ReasonSecureSessionNotEstablished))
{
ReasonSecureSessionNotEstablished = string.Format(CultureInfo.CurrentCulture, "ValidRequest: Received message hmac correct length {0} but differs at byte {1}, cannot validate", new object[2] { messageAuthenticationCode.Length, j });
}
flag = false;
break;
}
}
}
else if (messageAuthenticationCode == null)
{
if (string.IsNullOrEmpty(ReasonSecureSessionNotEstablished))
{
ReasonSecureSessionNotEstablished = "ValidRequest: Received message has null hmac, cannot validate";
}
}
else if (string.IsNullOrEmpty(ReasonSecureSessionNotEstablished))
{
ReasonSecureSessionNotEstablished = string.Format(CultureInfo.CurrentCulture, "ValidRequest: Received message hmac wrong length, cannot validate (received {0}, computed {1})", new object[2] { messageAuthenticationCode.Length, array.Length });
}
}
else
{
flag = true;
}
if (flag)
{
lock (this)
{
if (connectionValidator.MessageNumber <= highestMessageNumberReceived)
{
ReasonSecureSessionNotEstablished = string.Format(CultureInfo.CurrentCulture, "ValidRequest: Received message out of sequence, cannot validate (current {0}, highest {1})", new object[2] { connectionValidator.MessageNumber, highestMessageNumberReceived });
flag = false;
}
else if (outOfSyncMessageNumbers.Contains(connectionValidator.MessageNumber))
{
ReasonSecureSessionNotEstablished = string.Format(CultureInfo.CurrentCulture, "ValidRequest: Received message received late, cannot validate (current {0})", new object[1] { connectionValidator.MessageNumber });
flag = false;
}
else if (connectionValidator.MessageNumber == highestMessageNumberReceived + 1)
{
highestMessageNumberReceived = connectionValidator.MessageNumber;
}
else
{
outOfSyncMessageNumbers.Add(connectionValidator.MessageNumber);
}
outOfSyncMessageNumbers.Sort();
foreach (ulong outOfSyncMessageNumber in outOfSyncMessageNumbers)
{
if (outOfSyncMessageNumber == highestMessageNumberReceived + 1)
{
highestMessageNumberReceived = outOfSyncMessageNumber;
}
}
List<ulong> list = new List<ulong>();
foreach (ulong outOfSyncMessageNumber2 in outOfSyncMessageNumbers)
{
if (outOfSyncMessageNumber2 <= highestMessageNumberReceived)
{
list.Add(outOfSyncMessageNumber2);
}
}
foreach (ulong item in list)
{
outOfSyncMessageNumbers.Remove(item);
}
}
}
return flag;
}
public bool ValidResponse(ConnectedResponse response, bool forceHmac = false)
{
if (response != null && response.Result.Success)
{
return ValidRequest(response, forceHmac);
}
return false;
}
protected byte[] ReCalculateAuthenticationData(byte[] leftPart, byte[] rightPart, byte[] initializationVector)
{
List<byte> list = new List<byte>();
if (leftPart != null)
{
list.AddRange(leftPart);
}
if (rightPart != null)
{
list.AddRange(rightPart);
}
return ReEncypher(list.ToArray(), initializationVector);
}
protected byte[] CalculateAuthenticationData(byte[] leftPart, byte[] rightPart, out byte[] initializationVector)
{
List<byte> list = new List<byte>();
if (leftPart != null)
{
list.AddRange(leftPart);
}
if (rightPart != null)
{
list.AddRange(rightPart);
}
return EncypherWithNewInitializationVector(list.ToArray(), out initializationVector);
}
public void Sign(ConnectedRequest request, bool forceHmac)
{
if (request == null)
{
return;
}
lock (MessageNumberLock)
{
request.ConnectionValidator = new ConnectionValidator
{
ConnectionId = ConnectionId,
MessageNumber = NextMessageNumber++,
MessageAuthenticationCode = new byte[0],
SignatureInitializationVector = new byte[0]
};
using HMAC hMAC = NewSolutionHmac(forceHmac);
if (hMAC != null)
{
string text = request.ToXml();
ServiceTrace.LogVerbose("Signing XML message is {0}", text);
byte[] bytes = Encoding.UTF8.GetBytes(text);
request.ConnectionValidator.MessageAuthenticationCode = EncypherWithNewInitializationVector(hMAC.ComputeHash(bytes), out var initializationVector);
request.ConnectionValidator.SignatureInitializationVector = initializationVector;
}
}
}
public byte[] Encypher(byte[] clearData, byte[] initializationVector)
{
byte[] result = null;
if (clearData != null)
{
using AesManaged aesManaged = new AesManaged();
using Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(CryptoKey.ToBase64(), passwordsalt);
aesManaged.Key = rfc2898DeriveBytes.GetBytes(16);
aesManaged.IV = initializationVector;
using ICryptoTransform transform = aesManaged.CreateEncryptor();
using MemoryStream memoryStream = new MemoryStream();
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))
{
cryptoStream.Write(clearData, 0, clearData.Length);
cryptoStream.Close();
}
result = memoryStream.ToArray();
}
return result;
}
public byte[] EncypherWithNewInitializationVector(byte[] clearData, out byte[] initializationVector)
{
byte[] result = null;
initializationVector = null;
if (clearData != null)
{
using AesManaged aesManaged = new AesManaged();
using Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(CryptoKey.ToBase64(), passwordsalt);
aesManaged.Key = rfc2898DeriveBytes.GetBytes(16);
initializationVector = aesManaged.IV;
using ICryptoTransform transform = aesManaged.CreateEncryptor();
using MemoryStream memoryStream = new MemoryStream();
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))
{
cryptoStream.Write(clearData, 0, clearData.Length);
cryptoStream.Close();
}
result = memoryStream.ToArray();
}
return result;
}
public string Encypher(string clearText, out byte[] initializationVector)
{
string result = string.Empty;
initializationVector = null;
if (!string.IsNullOrEmpty(clearText))
{
byte[] bytes = Encoding.UTF8.GetBytes(clearText);
result = EncypherWithNewInitializationVector(bytes, out initializationVector).ToBase64();
}
return result;
}
public byte[] ReEncypher(byte[] clearData, byte[] initializationVector)
{
byte[] result = null;
if (clearData != null)
{
using AesManaged aesManaged = new AesManaged();
using Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(CryptoKey.ToBase64(), passwordsalt);
aesManaged.Key = rfc2898DeriveBytes.GetBytes(16);
aesManaged.IV = initializationVector;
using ICryptoTransform transform = aesManaged.CreateEncryptor();
using MemoryStream memoryStream = new MemoryStream();
using (CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Write))
{
cryptoStream.Write(clearData, 0, clearData.Length);
cryptoStream.Close();
}
result = memoryStream.ToArray();
}
return result;
}
public string ReEncypher(string clearText, byte[] initializationVector)
{
string result = string.Empty;
if (!string.IsNullOrEmpty(clearText))
{
byte[] bytes = Encoding.UTF8.GetBytes(clearText);
result = ReEncypher(bytes, initializationVector).ToBase64();
}
return result;
}
public byte[] Decypher(byte[] cypherData, byte[] initializationVector)
{
byte[] result = null;
if (cypherData != null)
{
using AesManaged aesManaged = new AesManaged();
using Rfc2898DeriveBytes rfc2898DeriveBytes = new Rfc2898DeriveBytes(CryptoKey.ToBase64(), passwordsalt);
aesManaged.Key = rfc2898DeriveBytes.GetBytes(16);
aesManaged.IV = initializationVector;
try
{
using ICryptoTransform transform = aesManaged.CreateDecryptor();
using MemoryStream stream = new MemoryStream(cypherData);
using CryptoStream cryptoStream = new CryptoStream(stream, transform, CryptoStreamMode.Read);
using MemoryStream memoryStream = new MemoryStream();
cryptoStream.CopyTo(memoryStream);
result = memoryStream.ToArray();
}
catch (Exception ex)
{
ReasonSecureSessionNotEstablished = "Decypher failed: " + ex.Message;
result = null;
}
}
return result;
}
public string Decypher(string cypherText, byte[] initializationVector)
{
string result = string.Empty;
if (!string.IsNullOrEmpty(cypherText))
{
byte[] cypherData = cypherText.FromBase64ToByteArray();
byte[] bytes = Decypher(cypherData, initializationVector);
result = Encoding.UTF8.GetString(bytes);
}
return result;
}
private byte[] CalculateCryptoKey()
{
List<byte> list = new List<byte>();
list.AddRange(CalculateConnectionKey(RemotePublicKey, PrivateKey));
byte[] solutionPassphrase = SolutionPassphrase;
if (solutionPassphrase != null)
{
list.AddRange(solutionPassphrase);
}
return list.ToArray();
}
private byte[] CalculateEncryptionKey()
{
return new HMACMD5(CryptoKey).ComputeHash(CryptoKey);
}
}
@@ -0,0 +1,110 @@
using System;
using System.Text;
using ArchestrAServices.Common;
namespace Asb.Base.V2;
public class SystemAuthenticationServiceAuthentication : SystemAuthenticationConnectionBase
{
public ulong Lifetime { get; private set; }
public SystemAuthenticationServiceAuthentication()
{
Reset();
Lifetime = 18000000uL;
}
public static ConnectResponse ProcessClientConnection(ConnectRequest request)
{
ServiceTrace.LogResume("SystemAuthenticationServiceAuthentication.ProcessClientConnection entry");
if (request == null)
{
return null;
}
ServiceTrace.LogVerbose("SysSvcAuth: Processing client Connect() call '{0}'", request.ConnectionId);
if (request.ConsumerPublicKey == null)
{
return null;
}
if (request.ConsumerPublicKey.Data == null)
{
return null;
}
SystemAuthenticationServiceAuthentication systemAuthenticationServiceAuthentication = new SystemAuthenticationServiceAuthentication
{
ConnectionId = request.ConnectionId,
RemotePublicKey = request.ConsumerPublicKey.Data
};
SysAuthenticatorServiceCache.AddServiceAuthenticator(systemAuthenticationServiceAuthentication);
PublicKey servicePublicKey = new PublicKey
{
Data = systemAuthenticationServiceAuthentication.LocalPublicKey
};
AuthenticationData authenticationData = new AuthenticationData();
authenticationData.Data = systemAuthenticationServiceAuthentication.CalculateAuthenticationData(systemAuthenticationServiceAuthentication.LocalPublicKey, systemAuthenticationServiceAuthentication.RemotePublicKey, out var initializationVector);
authenticationData.InitializationVector = initializationVector;
ArchestrAResult result = ArchestrAResult.MakeGoodResult();
systemAuthenticationServiceAuthentication.Lifetime = systemAuthenticationServiceAuthentication.SolutionParameters.ConnectionLifetime;
ConnectResponse connectResponse = new ConnectResponse(result, servicePublicKey, authenticationData, systemAuthenticationServiceAuthentication.Lifetime + ":" + SystemAuthenticationConnectionBase.AsbAuthenticationVersion);
systemAuthenticationServiceAuthentication.Sign(connectResponse, forceHmac: true);
systemAuthenticationServiceAuthentication.ReasonSecureSessionNotEstablished = string.Empty;
ServiceTrace.LogSuspend("SystemAuthenticationServiceAuthentication.ProcessClientConnection exit");
return connectResponse;
}
public bool ProcessClientAuthenticateMe(AuthenticateMeRequest request)
{
ServiceTrace.LogResume("SystemAuthenticationServiceAuthentication.ProcessClientAuthenticateMe entry with connection Id {0}", request.ConnectionValidator.ConnectionId);
ServiceTrace.LogVerbose("SystemAuthenticationServiceAuthentication: Processing client AuthenticateMe() call for connection id {0}", request.ConnectionValidator.ConnectionId);
if (!ValidRequest(request, forceHmac: true))
{
return false;
}
AuthenticationData consumerAuthenticationData = request.ConsumerAuthenticationData;
if (consumerAuthenticationData != null)
{
byte[] expected = ReCalculateAuthenticationData(RemotePublicKey, LocalPublicKey, consumerAuthenticationData.InitializationVector);
if (consumerAuthenticationData.AreEqual(expected))
{
ServiceTrace.LogVerbose("SystemAuthenticationServiceAuthentication: AuthenticateMe() authenticated client");
base.SecureSessionEstablished = true;
}
}
ServiceTrace.LogSuspend("SystemAuthenticationServiceAuthentication.ProcessClientAuthenticateMe exit");
return base.SecureSessionEstablished;
}
public static RenewResponse ProcessClientRenew(RenewRequest request)
{
ServiceTrace.LogResume("SystemAuthenticationServiceAuthentication.ProcessClientRenew entry with connection Id {0}", request.ConnectionValidator.ConnectionId);
SysAuthenticatorServiceCache.GetServiceAuthenticator(request.ConnectionValidator.ConnectionId)?.ValidRequest(request, forceHmac: false);
ServiceTrace.LogSuspend("SystemAuthenticationServiceAuthentication.ProcessClientRenew exit");
return null;
}
public static void ProcessClientUpdateSystemAuthenticationConfiguration(UpdateSystemAuthenticationConfigurationRequest request)
{
ServiceTrace.LogResume("SystemAuthenticationServiceAuthentication.ProcessClientUpdateSystemAuthenticationConfiguration entry with connection Id {0}", request.ConnectionValidator.ConnectionId);
SysAuthenticatorServiceCache.GetServiceAuthenticator(request.ConnectionValidator.ConnectionId)?.ValidRequest(request, forceHmac: false);
ServiceTrace.LogSuspend("SystemAuthenticationServiceAuthentication.ProcessClientUpdateSystemAuthenticationConfiguration exit");
}
public void ProcessClientDisconnect(DisconnectRequest request)
{
if (request == null)
{
return;
}
ServiceTrace.LogResume("SystemAuthenticationServiceAuthentication.ProcessClientDisconnect entry with connection Id {0}", request.ConnectionValidator.ConnectionId);
AuthenticationData consumerAuthenticationData = request.ConsumerAuthenticationData;
if (consumerAuthenticationData != null)
{
byte[] bytes = Decypher(consumerAuthenticationData.Data, consumerAuthenticationData.InitializationVector);
if (Guid.TryParse(Encoding.UTF8.GetString(bytes), out var result) && result == base.ConnectionId)
{
SysAuthenticatorServiceCache.RemoveServiceAuthenticator(result);
}
}
ServiceTrace.LogSuspend("SystemAuthenticationServiceAuthentication.ProcessClientDisconnect exit");
}
}
@@ -0,0 +1,27 @@
using System.ServiceModel;
using System.Xml.Serialization;
namespace Asb.Base.V2;
[MessageContract(WrapperName = "UpdateSystemAuthenticationConfiguration", WrapperNamespace = "urn:msg.asb.se:2", IsWrapped = true)]
[XmlRoot(Namespace = "urn:msg.asb.se:2")]
public class UpdateSystemAuthenticationConfigurationRequest : ConnectedRequest
{
[MessageBodyMember(Namespace = "urn:msg.asb.se:2", Order = 0)]
[XmlElement(ElementName = "EncryptedConfigurationData")]
public string EncryptedConfigurationData { get; set; }
[MessageBodyMember(Namespace = "urn:msg.asb.se:2", Order = 1)]
[XmlElement(ElementName = "InitializationVector", DataType = "base64Binary")]
public byte[] InitializationVector { get; set; }
public UpdateSystemAuthenticationConfigurationRequest()
{
}
public UpdateSystemAuthenticationConfigurationRequest(string encryptedConfigurationData, byte[] initializationVector)
{
EncryptedConfigurationData = encryptedConfigurationData;
InitializationVector = initializationVector;
}
}
@@ -0,0 +1,24 @@
namespace Asb.Base.V2;
public class UserToken
{
public ushort? Encryption { get; set; }
public string HostName { get; set; }
public ushort? IdType { get; set; }
public string LocationId { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public ushort? Validity { get; set; }
public string JwtToken { get; set; }
public byte[] SamlToken { get; set; }
public byte[] X509Certificate { get; set; }
}
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More