Compare commits
65 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1bfa2f8ce4 | |||
|
|
3a7629fada | ||
|
|
0b81172157 | ||
|
|
d49e27109e | ||
|
|
b655f5650e | ||
|
|
2bc74ddb4f | ||
|
|
1a7f60d3e1 | ||
|
|
16bd8b2d68 | ||
|
|
06f1b08050 | ||
|
|
8c3126316f | ||
|
|
9cd6edbeb7 | ||
|
|
ad88537c14 | ||
|
|
2611d94033 | ||
|
|
f892e1c93f | ||
|
|
91f6a680cf | ||
|
|
52322afeaa | ||
|
|
002da1559b | ||
|
|
01ad97b272 | ||
|
|
ac4217d9d4 | ||
|
|
bbb7c7a060 | ||
|
|
4bd2ad0024 | ||
|
|
3ccdcc701e | ||
|
|
923d70195d | ||
|
|
56ca05b230 | ||
|
|
82eaae0570 | ||
|
|
6bf95f46ee | ||
|
|
5c63105acf | ||
|
|
19716405b8 | ||
|
|
f0820875c3 | ||
|
|
8355a6b821 | ||
|
|
4d79f1b5db | ||
|
|
aef74fe8aa | ||
|
|
37a7881d25 | ||
|
|
9350412fb6 | ||
|
|
6a5e6056a7 | ||
|
|
c6c0ac623e | ||
|
|
c07abdaa62 | ||
|
|
f2d4541bab | ||
|
|
0eb8ff49f2 | ||
|
|
3b189d2865 | ||
|
|
6ff68d8812 | ||
|
|
e631d77f01 | ||
|
|
4e629a71b2 | ||
|
|
8db4b6d8a5 | ||
|
|
6b008f0e72 | ||
|
|
8e68283df6 | ||
|
|
9862ee4aa4 | ||
|
|
5cb0735213 | ||
|
|
5018ba17c2 | ||
|
|
5eeb3f874b | ||
|
|
91f18604fe | ||
|
|
c3b560cd17 | ||
|
|
e7d93e0732 | ||
|
|
1684280216 | ||
|
|
e93e20fa7f | ||
|
|
7a42da7f2c | ||
|
|
f8400caea6 | ||
|
|
447ca89baa | ||
|
|
8cc4279e1d | ||
|
|
4ede16318a | ||
|
|
1374758ffb | ||
|
|
4bfe7d8bc9 | ||
|
|
8c19366314 | ||
|
|
3a134be9df | ||
|
|
50efc7702b |
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
.vs
|
||||||
|
/_ReSharper.Caches
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
Copyright (c) 2014, Kevin Thompson
|
Copyright (c) 2019, Kevin Thompson
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 2012
|
# Visual Studio 15
|
||||||
|
VisualStudioVersion = 16.0.28527.54
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestClient", "TestClient\TestClient.csproj", "{E93FBF1A-5198-44D6-BDF0-880D17F2B81A}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestClient", "TestClient\TestClient.csproj", "{E93FBF1A-5198-44D6-BDF0-880D17F2B81A}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestProtocol", "TestProtocol\TestProtocol.csproj", "{9BFD94E1-D9FB-44D7-A6E7-8BAC2620E535}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestProtocol", "TestProtocol\TestProtocol.csproj", "{9BFD94E1-D9FB-44D7-A6E7-8BAC2620E535}"
|
||||||
|
|||||||
2
NSspi/.gitignore
vendored
Normal file
2
NSspi/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
bin
|
||||||
|
obj
|
||||||
@@ -1,9 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi
|
namespace NSspi
|
||||||
{
|
{
|
||||||
@@ -38,7 +33,6 @@ namespace NSspi
|
|||||||
buffer[position + 1] = (byte)( value >> 16 );
|
buffer[position + 1] = (byte)( value >> 16 );
|
||||||
buffer[position + 2] = (byte)( value >> 8 );
|
buffer[position + 2] = (byte)( value >> 8 );
|
||||||
buffer[position + 3] = (byte)( value );
|
buffer[position + 3] = (byte)( value );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using NSspi.Buffers;
|
using NSspi.Buffers;
|
||||||
using NSspi.Credentials;
|
using NSspi.Credentials;
|
||||||
|
|
||||||
@@ -33,7 +28,7 @@ namespace NSspi.Contexts
|
|||||||
/// <param name="requestedAttribs">Requested attributes that describe the desired properties of the
|
/// <param name="requestedAttribs">Requested attributes that describe the desired properties of the
|
||||||
/// context once it is established. If a context cannot be established that satisfies the indicated
|
/// context once it is established. If a context cannot be established that satisfies the indicated
|
||||||
/// properties, the context initialization is aborted.</param>
|
/// properties, the context initialization is aborted.</param>
|
||||||
public ClientContext( ClientCredential cred, string serverPrinc, ContextAttrib requestedAttribs )
|
public ClientContext( Credential cred, string serverPrinc, ContextAttrib requestedAttribs )
|
||||||
: base( cred )
|
: base( cred )
|
||||||
{
|
{
|
||||||
this.serverPrinc = serverPrinc;
|
this.serverPrinc = serverPrinc;
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Security.Principal;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using NSspi.Buffers;
|
using NSspi.Buffers;
|
||||||
using NSspi.Contexts;
|
|
||||||
using NSspi.Credentials;
|
using NSspi.Credentials;
|
||||||
|
|
||||||
namespace NSspi.Contexts
|
namespace NSspi.Contexts
|
||||||
@@ -87,6 +83,11 @@ namespace NSspi.Contexts
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Disposed { get; private set; }
|
public bool Disposed { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constant for wrapping only...no encryption
|
||||||
|
/// </summary>
|
||||||
|
protected uint KERB_WRAP_NO_ENCRYPT = 0x80000001;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Marks the context as having completed the initialization process, ie, exchanging of authentication tokens.
|
/// Marks the context as having completed the initialization process, ie, exchanging of authentication tokens.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -122,6 +123,105 @@ namespace NSspi.Contexts
|
|||||||
this.Disposed = true;
|
this.Disposed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the identity of the remote entity.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public IIdentity GetRemoteIdentity()
|
||||||
|
{
|
||||||
|
IIdentity result = null;
|
||||||
|
|
||||||
|
using( var tokenHandle = GetContextToken() )
|
||||||
|
{
|
||||||
|
bool gotRef = false;
|
||||||
|
|
||||||
|
RuntimeHelpers.PrepareConstrainedRegions();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
tokenHandle.DangerousAddRef( ref gotRef );
|
||||||
|
}
|
||||||
|
catch( Exception )
|
||||||
|
{
|
||||||
|
if( gotRef )
|
||||||
|
{
|
||||||
|
tokenHandle.DangerousRelease();
|
||||||
|
gotRef = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = new WindowsIdentity(
|
||||||
|
tokenHandle.DangerousGetHandle(),
|
||||||
|
this.Credential.SecurityPackage
|
||||||
|
);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// Make sure we release the handle, even if the allocation for
|
||||||
|
// WindowsIdentity fails.
|
||||||
|
tokenHandle.DangerousRelease();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SafeTokenHandle GetContextToken()
|
||||||
|
{
|
||||||
|
bool gotRef = false;
|
||||||
|
SecurityStatus status = SecurityStatus.InternalError;
|
||||||
|
SafeTokenHandle token;
|
||||||
|
|
||||||
|
RuntimeHelpers.PrepareConstrainedRegions();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.ContextHandle.DangerousAddRef( ref gotRef );
|
||||||
|
}
|
||||||
|
catch( Exception )
|
||||||
|
{
|
||||||
|
if( gotRef )
|
||||||
|
{
|
||||||
|
this.ContextHandle.DangerousRelease();
|
||||||
|
gotRef = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if( gotRef )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
status = ContextNativeMethods.QuerySecurityContextToken(
|
||||||
|
ref this.ContextHandle.rawHandle,
|
||||||
|
out token
|
||||||
|
);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
this.ContextHandle.DangerousRelease();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
token = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( status != SecurityStatus.OK )
|
||||||
|
{
|
||||||
|
throw new SSPIException( "Failed to query context token.", status );
|
||||||
|
}
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Encrypts the byte array using the context's session key.
|
/// Encrypts the byte array using the context's session key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -135,8 +235,9 @@ namespace NSspi.Contexts
|
|||||||
/// - The padding buffer.
|
/// - The padding buffer.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="input">The raw message to encrypt.</param>
|
/// <param name="input">The raw message to encrypt.</param>
|
||||||
|
/// <param name="wrapOnly">Only wrap the message, no encryption</param>
|
||||||
/// <returns>The packed and encrypted message.</returns>
|
/// <returns>The packed and encrypted message.</returns>
|
||||||
public byte[] Encrypt( byte[] input )
|
public byte[] Encrypt( byte[] input, bool wrapOnly = false )
|
||||||
{
|
{
|
||||||
// The message is encrypted in place in the buffer we provide to Win32 EncryptMessage
|
// The message is encrypted in place in the buffer we provide to Win32 EncryptMessage
|
||||||
SecPkgContext_Sizes sizes;
|
SecPkgContext_Sizes sizes;
|
||||||
@@ -161,9 +262,14 @@ namespace NSspi.Contexts
|
|||||||
|
|
||||||
using( adapter = new SecureBufferAdapter( new[] { trailerBuffer, dataBuffer, paddingBuffer } ) )
|
using( adapter = new SecureBufferAdapter( new[] { trailerBuffer, dataBuffer, paddingBuffer } ) )
|
||||||
{
|
{
|
||||||
|
uint qualityOfProtection = 0u;
|
||||||
|
if (wrapOnly)
|
||||||
|
{
|
||||||
|
qualityOfProtection = KERB_WRAP_NO_ENCRYPT;
|
||||||
|
}
|
||||||
status = ContextNativeMethods.SafeEncryptMessage(
|
status = ContextNativeMethods.SafeEncryptMessage(
|
||||||
this.ContextHandle,
|
this.ContextHandle,
|
||||||
0,
|
qualityOfProtection,
|
||||||
adapter,
|
adapter,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
@@ -217,8 +323,9 @@ namespace NSspi.Contexts
|
|||||||
/// - The padding buffer.
|
/// - The padding buffer.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="input">The packed and encrypted data.</param>
|
/// <param name="input">The packed and encrypted data.</param>
|
||||||
|
/// <param name="unwrapOnly">Only wrap the message, no encryption</param>
|
||||||
/// <returns>The original plaintext message.</returns>
|
/// <returns>The original plaintext message.</returns>
|
||||||
public byte[] Decrypt( byte[] input )
|
public byte[] Decrypt( byte[] input, bool unwrapOnly = false)
|
||||||
{
|
{
|
||||||
SecPkgContext_Sizes sizes;
|
SecPkgContext_Sizes sizes;
|
||||||
|
|
||||||
@@ -296,12 +403,16 @@ namespace NSspi.Contexts
|
|||||||
}
|
}
|
||||||
// else there was no padding.
|
// else there was no padding.
|
||||||
|
|
||||||
|
|
||||||
using( adapter = new SecureBufferAdapter( new[] { trailerBuffer, dataBuffer, paddingBuffer } ) )
|
using( adapter = new SecureBufferAdapter( new[] { trailerBuffer, dataBuffer, paddingBuffer } ) )
|
||||||
{
|
{
|
||||||
|
uint qualityOfProtection = 0u;
|
||||||
|
if (unwrapOnly)
|
||||||
|
{
|
||||||
|
qualityOfProtection = KERB_WRAP_NO_ENCRYPT;
|
||||||
|
}
|
||||||
status = ContextNativeMethods.SafeDecryptMessage(
|
status = ContextNativeMethods.SafeDecryptMessage(
|
||||||
this.ContextHandle,
|
this.ContextHandle,
|
||||||
0,
|
qualityOfProtection,
|
||||||
adapter,
|
adapter,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
@@ -389,6 +500,35 @@ namespace NSspi.Contexts
|
|||||||
return outMessage;
|
return outMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the Session Key from a context or null on failure.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Session keys are sometimes needed for other purposes or HMAC functions. This function
|
||||||
|
/// will run QueryAttribute to get the session key struct, and read and return the key from
|
||||||
|
/// that struct.
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns>byte[] with the session key data or null on failure</returns>
|
||||||
|
public byte[] QuerySessionKey()
|
||||||
|
{
|
||||||
|
SecurityStatus status;
|
||||||
|
|
||||||
|
byte[] SessionKey = null;
|
||||||
|
|
||||||
|
status = ContextNativeMethods.SafeQueryContextAttribute(
|
||||||
|
this.ContextHandle,
|
||||||
|
ContextQueryAttrib.SessionKey,
|
||||||
|
ref SessionKey
|
||||||
|
);
|
||||||
|
|
||||||
|
if( status != SecurityStatus.OK )
|
||||||
|
{
|
||||||
|
throw new SSPIException( "Failed to query session key.", status );
|
||||||
|
}
|
||||||
|
|
||||||
|
return SessionKey;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Verifies the signature of a signed message
|
/// Verifies the signature of a signed message
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Contexts
|
namespace NSspi.Contexts
|
||||||
{
|
{
|
||||||
@@ -36,7 +32,6 @@ namespace NSspi.Contexts
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
MutualAuth = 0x00000002,
|
MutualAuth = 0x00000002,
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Detect replayed messages that have been encoded by using the EncryptMessage or MakeSignature
|
/// Detect replayed messages that have been encoded by using the EncryptMessage or MakeSignature
|
||||||
/// message support functionality.
|
/// message support functionality.
|
||||||
@@ -121,7 +116,16 @@ namespace NSspi.Contexts
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
AcceptIntegrity = 0x00020000,
|
AcceptIntegrity = 0x00020000,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set by a client; indicates the context can only impersonate with limited privileges,
|
||||||
|
/// allowing the server only to identify the client when impersonating.
|
||||||
|
/// </summary>
|
||||||
InitIdentify = 0x00020000,
|
InitIdentify = 0x00020000,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set by a server; indicates the context can only impersonate with limited privileges,
|
||||||
|
/// allowing the server only to identify the client when impersonating.
|
||||||
|
/// </summary>
|
||||||
AcceptIdentify = 0x00080000,
|
AcceptIdentify = 0x00080000,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,13 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.ConstrainedExecution;
|
using System.Runtime.ConstrainedExecution;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using NSspi.Buffers;
|
using NSspi.Buffers;
|
||||||
using NSspi.Contexts;
|
|
||||||
|
|
||||||
namespace NSspi.Contexts
|
namespace NSspi.Contexts
|
||||||
{
|
{
|
||||||
@@ -58,7 +53,6 @@ namespace NSspi.Contexts
|
|||||||
ref TimeStamp expiry
|
ref TimeStamp expiry
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
[DllImport( "Secur32.dll", EntryPoint = "AcceptSecurityContext", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "AcceptSecurityContext", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus AcceptSecurityContext_2(
|
internal static extern SecurityStatus AcceptSecurityContext_2(
|
||||||
ref RawSspiHandle credHandle,
|
ref RawSspiHandle credHandle,
|
||||||
@@ -72,7 +66,6 @@ namespace NSspi.Contexts
|
|||||||
ref TimeStamp expiry
|
ref TimeStamp expiry
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
[DllImport( "Secur32.dll", EntryPoint = "InitializeSecurityContext", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "InitializeSecurityContext", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus InitializeSecurityContext_1(
|
internal static extern SecurityStatus InitializeSecurityContext_1(
|
||||||
ref RawSspiHandle credentialHandle,
|
ref RawSspiHandle credentialHandle,
|
||||||
@@ -89,7 +82,6 @@ namespace NSspi.Contexts
|
|||||||
ref TimeStamp expiry
|
ref TimeStamp expiry
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
[DllImport( "Secur32.dll", EntryPoint = "InitializeSecurityContext", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "InitializeSecurityContext", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus InitializeSecurityContext_2(
|
internal static extern SecurityStatus InitializeSecurityContext_2(
|
||||||
ref RawSspiHandle credentialHandle,
|
ref RawSspiHandle credentialHandle,
|
||||||
@@ -110,14 +102,13 @@ namespace NSspi.Contexts
|
|||||||
[DllImport( "Secur32.dll", EntryPoint = "DeleteSecurityContext", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "DeleteSecurityContext", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus DeleteSecurityContext( ref RawSspiHandle contextHandle );
|
internal static extern SecurityStatus DeleteSecurityContext( ref RawSspiHandle contextHandle );
|
||||||
|
|
||||||
|
|
||||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )]
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )]
|
||||||
[DllImport( "Secur32.dll", EntryPoint = "EncryptMessage", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "EncryptMessage", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus EncryptMessage(
|
internal static extern SecurityStatus EncryptMessage(
|
||||||
ref RawSspiHandle contextHandle,
|
ref RawSspiHandle contextHandle,
|
||||||
int qualityOfProtection,
|
uint qualityOfProtection,
|
||||||
IntPtr bufferDescriptor,
|
IntPtr bufferDescriptor,
|
||||||
int sequenceNumber
|
uint sequenceNumber
|
||||||
);
|
);
|
||||||
|
|
||||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )]
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )]
|
||||||
@@ -125,17 +116,17 @@ namespace NSspi.Contexts
|
|||||||
internal static extern SecurityStatus DecryptMessage(
|
internal static extern SecurityStatus DecryptMessage(
|
||||||
ref RawSspiHandle contextHandle,
|
ref RawSspiHandle contextHandle,
|
||||||
IntPtr bufferDescriptor,
|
IntPtr bufferDescriptor,
|
||||||
int sequenceNumber,
|
uint sequenceNumber,
|
||||||
int qualityOfProtection
|
uint qualityOfProtection
|
||||||
);
|
);
|
||||||
|
|
||||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )]
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )]
|
||||||
[DllImport( "Secur32.dll", EntryPoint = "MakeSignature", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "MakeSignature", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus MakeSignature(
|
internal static extern SecurityStatus MakeSignature(
|
||||||
ref RawSspiHandle contextHandle,
|
ref RawSspiHandle contextHandle,
|
||||||
int qualityOfProtection,
|
uint qualityOfProtection,
|
||||||
IntPtr bufferDescriptor,
|
IntPtr bufferDescriptor,
|
||||||
int sequenceNumber
|
uint sequenceNumber
|
||||||
);
|
);
|
||||||
|
|
||||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )]
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )]
|
||||||
@@ -143,8 +134,8 @@ namespace NSspi.Contexts
|
|||||||
internal static extern SecurityStatus VerifySignature(
|
internal static extern SecurityStatus VerifySignature(
|
||||||
ref RawSspiHandle contextHandle,
|
ref RawSspiHandle contextHandle,
|
||||||
IntPtr bufferDescriptor,
|
IntPtr bufferDescriptor,
|
||||||
int sequenceNumber,
|
uint sequenceNumber,
|
||||||
int qualityOfProtection
|
uint qualityOfProtection
|
||||||
);
|
);
|
||||||
|
|
||||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||||
@@ -163,11 +154,18 @@ namespace NSspi.Contexts
|
|||||||
ref SecPkgContext_String names
|
ref SecPkgContext_String names
|
||||||
);
|
);
|
||||||
|
|
||||||
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||||
|
[DllImport( "Secur32.dll", EntryPoint = "QueryContextAttributes", CharSet = CharSet.Unicode )]
|
||||||
|
internal static extern SecurityStatus QueryContextAttributes(
|
||||||
|
ref RawSspiHandle contextHandle,
|
||||||
|
ContextQueryAttrib attrib,
|
||||||
|
IntPtr attribute
|
||||||
|
);
|
||||||
|
|
||||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||||
[DllImport( "Secur32.dll", EntryPoint = "FreeContextBuffer", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "FreeContextBuffer", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus FreeContextBuffer( IntPtr handle );
|
internal static extern SecurityStatus FreeContextBuffer( IntPtr handle );
|
||||||
|
|
||||||
|
|
||||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||||
[DllImport( "Secur32.dll", EntryPoint = "ImpersonateSecurityContext", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "ImpersonateSecurityContext", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus ImpersonateSecurityContext( ref RawSspiHandle contextHandle );
|
internal static extern SecurityStatus ImpersonateSecurityContext( ref RawSspiHandle contextHandle );
|
||||||
@@ -176,6 +174,76 @@ namespace NSspi.Contexts
|
|||||||
[DllImport( "Secur32.dll", EntryPoint = "RevertSecurityContext", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "RevertSecurityContext", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus RevertSecurityContext( ref RawSspiHandle contextHandle );
|
internal static extern SecurityStatus RevertSecurityContext( ref RawSspiHandle contextHandle );
|
||||||
|
|
||||||
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||||
|
[DllImport( "Secur32.dll", EntryPoint = "QuerySecurityContextToken", SetLastError = true )]
|
||||||
|
internal static extern SecurityStatus QuerySecurityContextToken( ref RawSspiHandle contextHandle, [Out] out SafeTokenHandle handle );
|
||||||
|
|
||||||
|
[StructLayout( LayoutKind.Sequential )]
|
||||||
|
private class KeyStruct
|
||||||
|
{
|
||||||
|
public int size;
|
||||||
|
public IntPtr data;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static SecurityStatus SafeQueryContextAttribute(
|
||||||
|
SafeContextHandle handle,
|
||||||
|
ContextQueryAttrib attribute,
|
||||||
|
ref byte[] buffer
|
||||||
|
)
|
||||||
|
{
|
||||||
|
bool gotRef = false;
|
||||||
|
|
||||||
|
SecurityStatus status = SecurityStatus.InternalError;
|
||||||
|
RuntimeHelpers.PrepareConstrainedRegions();
|
||||||
|
|
||||||
|
int pointerSize = System.Environment.Is64BitOperatingSystem ? 8 : 4; //NOTE: update this when 128 bit processors exist
|
||||||
|
IntPtr alloc_buffer = Marshal.AllocHGlobal( sizeof( uint ) + pointerSize ); //NOTE: this is at most 4 + sizeof(void*) bytes
|
||||||
|
//see struct SecPkgContext_SessionKey
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa380096(v=vs.85).aspx
|
||||||
|
try
|
||||||
|
{
|
||||||
|
handle.DangerousAddRef( ref gotRef );
|
||||||
|
}
|
||||||
|
catch( Exception )
|
||||||
|
{
|
||||||
|
if( gotRef )
|
||||||
|
{
|
||||||
|
handle.DangerousRelease();
|
||||||
|
gotRef = false;
|
||||||
|
buffer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if( gotRef )
|
||||||
|
{
|
||||||
|
status = ContextNativeMethods.QueryContextAttributes(
|
||||||
|
ref handle.rawHandle,
|
||||||
|
attribute,
|
||||||
|
alloc_buffer
|
||||||
|
);
|
||||||
|
if( status == SecurityStatus.OK )
|
||||||
|
{
|
||||||
|
KeyStruct key = new KeyStruct();
|
||||||
|
|
||||||
|
Marshal.PtrToStructure( alloc_buffer, key ); // fit to the proper size, read a byte[]
|
||||||
|
|
||||||
|
byte[] sizedBuffer = new byte[key.size];
|
||||||
|
|
||||||
|
for( int i = 0; i < key.size; i++ )
|
||||||
|
sizedBuffer[i] = Marshal.ReadByte( key.data, i );
|
||||||
|
|
||||||
|
buffer = sizedBuffer;
|
||||||
|
}
|
||||||
|
handle.DangerousRelease();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Marshal.FreeHGlobal( alloc_buffer );
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Safely invokes the native EncryptMessage function, making sure that handle ref counting is
|
/// Safely invokes the native EncryptMessage function, making sure that handle ref counting is
|
||||||
/// performed in a proper CER.
|
/// performed in a proper CER.
|
||||||
@@ -187,9 +255,9 @@ namespace NSspi.Contexts
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
internal static SecurityStatus SafeEncryptMessage(
|
internal static SecurityStatus SafeEncryptMessage(
|
||||||
SafeContextHandle handle,
|
SafeContextHandle handle,
|
||||||
int qualityOfProtection,
|
uint qualityOfProtection,
|
||||||
SecureBufferAdapter bufferAdapter,
|
SecureBufferAdapter bufferAdapter,
|
||||||
int sequenceNumber )
|
uint sequenceNumber )
|
||||||
{
|
{
|
||||||
SecurityStatus status = SecurityStatus.InternalError;
|
SecurityStatus status = SecurityStatus.InternalError;
|
||||||
bool gotRef = false;
|
bool gotRef = false;
|
||||||
@@ -238,9 +306,9 @@ namespace NSspi.Contexts
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
internal static SecurityStatus SafeDecryptMessage(
|
internal static SecurityStatus SafeDecryptMessage(
|
||||||
SafeContextHandle handle,
|
SafeContextHandle handle,
|
||||||
int qualityOfProtection,
|
uint qualityOfProtection,
|
||||||
SecureBufferAdapter bufferAdapter,
|
SecureBufferAdapter bufferAdapter,
|
||||||
int sequenceNumber )
|
uint sequenceNumber )
|
||||||
{
|
{
|
||||||
SecurityStatus status = SecurityStatus.InvalidHandle;
|
SecurityStatus status = SecurityStatus.InvalidHandle;
|
||||||
bool gotRef = false;
|
bool gotRef = false;
|
||||||
@@ -289,9 +357,9 @@ namespace NSspi.Contexts
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
internal static SecurityStatus SafeMakeSignature(
|
internal static SecurityStatus SafeMakeSignature(
|
||||||
SafeContextHandle handle,
|
SafeContextHandle handle,
|
||||||
int qualityOfProtection,
|
uint qualityOfProtection,
|
||||||
SecureBufferAdapter adapter,
|
SecureBufferAdapter adapter,
|
||||||
int sequenceNumber )
|
uint sequenceNumber )
|
||||||
{
|
{
|
||||||
bool gotRef = false;
|
bool gotRef = false;
|
||||||
SecurityStatus status = SecurityStatus.InternalError;
|
SecurityStatus status = SecurityStatus.InternalError;
|
||||||
@@ -340,9 +408,9 @@ namespace NSspi.Contexts
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
internal static SecurityStatus SafeVerifySignature(
|
internal static SecurityStatus SafeVerifySignature(
|
||||||
SafeContextHandle handle,
|
SafeContextHandle handle,
|
||||||
int qualityOfProtection,
|
uint qualityOfProtection,
|
||||||
SecureBufferAdapter adapter,
|
SecureBufferAdapter adapter,
|
||||||
int sequenceNumber )
|
uint sequenceNumber )
|
||||||
{
|
{
|
||||||
bool gotRef = false;
|
bool gotRef = false;
|
||||||
SecurityStatus status = SecurityStatus.InternalError;
|
SecurityStatus status = SecurityStatus.InternalError;
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Contexts
|
namespace NSspi.Contexts
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Contexts
|
namespace NSspi.Contexts
|
||||||
{
|
{
|
||||||
@@ -36,5 +32,15 @@ namespace NSspi.Contexts
|
|||||||
/// Results for a query of this type are stored in a Win32 SecPkgContext_Authority structure.
|
/// Results for a query of this type are stored in a Win32 SecPkgContext_Authority structure.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
Authority = 6,
|
Authority = 6,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queries the context for it's neogtiated SessionKey
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Results for a query of this type are stored in a Win32 SecPkgContext_SessionKey structure
|
||||||
|
/// </remarks>
|
||||||
|
SessionKey = 9,
|
||||||
|
|
||||||
|
AccessToken = 13, //not implemented yet but this would be cool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Security.Principal;
|
||||||
using System.Linq;
|
using System.Threading;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Contexts
|
namespace NSspi.Contexts
|
||||||
{
|
{
|
||||||
@@ -20,8 +18,9 @@ namespace NSspi.Contexts
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
public class ImpersonationHandle : IDisposable
|
public class ImpersonationHandle : IDisposable
|
||||||
{
|
{
|
||||||
|
private readonly ServerContext server;
|
||||||
|
|
||||||
private bool disposed;
|
private bool disposed;
|
||||||
private ServerContext server;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the ImpersonationHandle. Does not perform impersonation.
|
/// Initializes a new instance of the ImpersonationHandle. Does not perform impersonation.
|
||||||
@@ -33,13 +32,16 @@ namespace NSspi.Contexts
|
|||||||
this.disposed = false;
|
this.disposed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finalizes the ImpersonationHandle by reverting the impersonation.
|
||||||
|
/// </summary>
|
||||||
~ImpersonationHandle()
|
~ImpersonationHandle()
|
||||||
{
|
{
|
||||||
Dispose( false );
|
Dispose( false );
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reverts the impersonation.
|
/// Reverts impersonation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
@@ -47,13 +49,28 @@ namespace NSspi.Contexts
|
|||||||
GC.SuppressFinalize( this );
|
GC.SuppressFinalize( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void Dispose( bool disposing )
|
/// <summary>
|
||||||
|
/// Reverts impersonation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">True if being disposed, false if being finalized.</param>
|
||||||
|
private void Dispose( bool disposing )
|
||||||
{
|
{
|
||||||
if( disposing && this.disposed == false && this.server != null && this.server.Disposed == false )
|
// This implements a variant of the typical dispose pattern. Always try to revert
|
||||||
{
|
// impersonation, even if finalizing. Don't do anything if we're already reverted.
|
||||||
this.server.RevertImpersonate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if( this.disposed == false )
|
||||||
|
{
|
||||||
|
this.disposed = true;
|
||||||
|
|
||||||
|
// Just in case the reference is being pulled out from under us, pull a stable copy
|
||||||
|
// of the reference while we're null-checking.
|
||||||
|
var serverCopy = this.server;
|
||||||
|
|
||||||
|
if( serverCopy != null && serverCopy.Disposed == false )
|
||||||
|
{
|
||||||
|
serverCopy.RevertImpersonate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.ConstrainedExecution;
|
using System.Runtime.ConstrainedExecution;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Contexts
|
namespace NSspi.Contexts
|
||||||
{
|
{
|
||||||
@@ -12,10 +8,17 @@ namespace NSspi.Contexts
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class SafeContextHandle : SafeSspiHandle
|
public class SafeContextHandle : SafeSspiHandle
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SafeContextHandle"/> class.
|
||||||
|
/// </summary>
|
||||||
public SafeContextHandle()
|
public SafeContextHandle()
|
||||||
: base()
|
: base()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Releases the safe context handle.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||||
protected override bool ReleaseHandle()
|
protected override bool ReleaseHandle()
|
||||||
{
|
{
|
||||||
|
|||||||
27
NSspi/Contexts/SafeTokenHandle.cs
Normal file
27
NSspi/Contexts/SafeTokenHandle.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace NSspi.Contexts
|
||||||
|
{
|
||||||
|
public class SafeTokenHandle : SafeHandle
|
||||||
|
{
|
||||||
|
public SafeTokenHandle() : base( IntPtr.Zero, true )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsInvalid
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return handle == IntPtr.Zero || handle == new IntPtr( -1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool ReleaseHandle()
|
||||||
|
{
|
||||||
|
NativeMethods.CloseHandle( this.handle );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
using System.Security.Principal;
|
||||||
using System.Threading.Tasks;
|
using System.Threading;
|
||||||
using NSspi.Buffers;
|
using NSspi.Buffers;
|
||||||
using NSspi.Credentials;
|
using NSspi.Credentials;
|
||||||
|
|
||||||
@@ -14,20 +12,27 @@ namespace NSspi.Contexts
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class ServerContext : Context
|
public class ServerContext : Context
|
||||||
{
|
{
|
||||||
private ContextAttrib requestedAttribs;
|
private readonly ContextAttrib requestedAttribs;
|
||||||
private ContextAttrib finalAttribs;
|
private readonly bool impersonationSetsThreadPrinciple;
|
||||||
|
|
||||||
|
private ContextAttrib finalAttribs;
|
||||||
private bool impersonating;
|
private bool impersonating;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs basic initialization of a new instance of the ServerContext class. The ServerContext
|
/// Performs basic initialization of a new instance of the ServerContext class. The
|
||||||
/// is not ready for message manipulation until a security context has been established with a client.
|
/// ServerContext is not ready for message manipulation until a security context has been
|
||||||
|
/// established with a client.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="cred"></param>
|
/// <param name="cred"></param>
|
||||||
/// <param name="requestedAttribs"></param>
|
/// <param name="requestedAttribs"></param>
|
||||||
public ServerContext(ServerCredential cred, ContextAttrib requestedAttribs) : base ( cred )
|
/// <param name="impersonationSetsThreadPrinciple">
|
||||||
|
/// If true, the `Thread.CurrentPrinciple` property will be modified by successful impersonation.
|
||||||
|
/// </param>
|
||||||
|
public ServerContext( Credential cred, ContextAttrib requestedAttribs, bool impersonationSetsThreadPrinciple = false ) : base( cred )
|
||||||
{
|
{
|
||||||
this.requestedAttribs = requestedAttribs;
|
this.requestedAttribs = requestedAttribs;
|
||||||
|
this.impersonationSetsThreadPrinciple = impersonationSetsThreadPrinciple;
|
||||||
|
|
||||||
this.finalAttribs = ContextAttrib.Zero;
|
this.finalAttribs = ContextAttrib.Zero;
|
||||||
|
|
||||||
this.impersonating = false;
|
this.impersonating = false;
|
||||||
@@ -125,16 +130,12 @@ namespace NSspi.Contexts
|
|||||||
ref this.finalAttribs,
|
ref this.finalAttribs,
|
||||||
ref rawExpiry
|
ref rawExpiry
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( status == SecurityStatus.OK )
|
if( status == SecurityStatus.OK )
|
||||||
{
|
{
|
||||||
nextToken = null;
|
|
||||||
|
|
||||||
base.Initialize( rawExpiry.ToDateTime() );
|
base.Initialize( rawExpiry.ToDateTime() );
|
||||||
|
|
||||||
if( outBuffer.Length != 0 )
|
if( outBuffer.Length != 0 )
|
||||||
@@ -183,6 +184,12 @@ namespace NSspi.Contexts
|
|||||||
{
|
{
|
||||||
throw new ObjectDisposedException( "ServerContext" );
|
throw new ObjectDisposedException( "ServerContext" );
|
||||||
}
|
}
|
||||||
|
else if( this.Initialized == false )
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
"The server context has not been completely initialized."
|
||||||
|
);
|
||||||
|
}
|
||||||
else if( impersonating )
|
else if( impersonating )
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException( "Cannot impersonate again while already impersonating." );
|
throw new InvalidOperationException( "Cannot impersonate again while already impersonating." );
|
||||||
@@ -220,7 +227,7 @@ namespace NSspi.Contexts
|
|||||||
|
|
||||||
this.ContextHandle.DangerousRelease();
|
this.ContextHandle.DangerousRelease();
|
||||||
|
|
||||||
this.impersonating = true;
|
this.impersonating = status == SecurityStatus.OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,6 +244,11 @@ namespace NSspi.Contexts
|
|||||||
throw new SSPIException( "Failed to impersonate the client", status );
|
throw new SSPIException( "Failed to impersonate the client", status );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( this.impersonating && this.impersonationSetsThreadPrinciple )
|
||||||
|
{
|
||||||
|
Thread.CurrentPrincipal = new WindowsPrincipal( (WindowsIdentity)GetRemoteIdentity() );
|
||||||
|
}
|
||||||
|
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,6 +294,10 @@ namespace NSspi.Contexts
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Releases all resources associted with the ServerContext.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing"></param>
|
||||||
protected override void Dispose( bool disposing )
|
protected override void Dispose( bool disposing )
|
||||||
{
|
{
|
||||||
// We were disposed while impersonating. This means that the consumer that is currently holding
|
// We were disposed while impersonating. This means that the consumer that is currently holding
|
||||||
|
|||||||
55
NSspi/Credentials/AuthData.cs
Normal file
55
NSspi/Credentials/AuthData.cs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace NSspi.Credentials
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides authentication data in native method calls.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Implements the 'SEC_WINNT_AUTH_IDENTITY' structure. See:
|
||||||
|
///
|
||||||
|
/// https://msdn.microsoft.com/en-us/library/windows/desktop/aa380131(v=vs.85).aspx
|
||||||
|
/// </remarks>
|
||||||
|
[StructLayout( LayoutKind.Sequential )]
|
||||||
|
internal struct NativeAuthData
|
||||||
|
{
|
||||||
|
public NativeAuthData( string domain, string username, string password, NativeAuthDataFlag flag )
|
||||||
|
{
|
||||||
|
this.Domain = domain;
|
||||||
|
this.DomainLength = domain.Length;
|
||||||
|
|
||||||
|
this.User = username;
|
||||||
|
this.UserLength = username.Length;
|
||||||
|
|
||||||
|
this.Password = password;
|
||||||
|
this.PasswordLength = password.Length;
|
||||||
|
|
||||||
|
this.Flags = flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MarshalAs( UnmanagedType.LPWStr )]
|
||||||
|
public string User;
|
||||||
|
|
||||||
|
public int UserLength;
|
||||||
|
|
||||||
|
[MarshalAs( UnmanagedType.LPWStr )]
|
||||||
|
public string Domain;
|
||||||
|
|
||||||
|
public int DomainLength;
|
||||||
|
|
||||||
|
[MarshalAs( UnmanagedType.LPWStr )]
|
||||||
|
public string Password;
|
||||||
|
|
||||||
|
public int PasswordLength;
|
||||||
|
|
||||||
|
public NativeAuthDataFlag Flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal enum NativeAuthDataFlag : int
|
||||||
|
{
|
||||||
|
Ansi = 1,
|
||||||
|
|
||||||
|
Unicode = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Credentials
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Represents the credentials of the user running the current process, for use as an SSPI client.
|
|
||||||
/// </summary>
|
|
||||||
public class ClientCredential : CurrentCredential
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the ClientCredential class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="package">The security package to acquire the credential handle from.</param>
|
|
||||||
public ClientCredential( string package )
|
|
||||||
: base( package, CredentialUse.Outbound )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
20
NSspi/Credentials/ClientCurrentCredential.cs
Normal file
20
NSspi/Credentials/ClientCurrentCredential.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace NSspi.Credentials
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a handle to the credentials of the user running the current process, to be used to
|
||||||
|
/// authenticate as a client.
|
||||||
|
/// </summary>
|
||||||
|
public class ClientCurrentCredential : CurrentCredential
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the ClientCurrentCredential class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="package">The security package to acquire the credential handle from.</param>
|
||||||
|
public ClientCurrentCredential( string package )
|
||||||
|
: base( package, CredentialUse.Outbound )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.DirectoryServices.AccountManagement;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.ConstrainedExecution;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using NSspi.Credentials;
|
|
||||||
|
|
||||||
namespace NSspi.Credentials
|
namespace NSspi.Credentials
|
||||||
{
|
{
|
||||||
@@ -16,16 +9,16 @@ namespace NSspi.Credentials
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class Credential : IDisposable
|
public class Credential : IDisposable
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The name of the security package that controls the credential.
|
||||||
|
/// </summary>
|
||||||
|
private readonly string securityPackage;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the Credential has been disposed.
|
/// Whether the Credential has been disposed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private bool disposed;
|
private bool disposed;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The name of the security package that controls the credential.
|
|
||||||
/// </summary>
|
|
||||||
private string securityPackage;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A safe handle to the credential's handle.
|
/// A safe handle to the credential's handle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -42,11 +35,10 @@ namespace NSspi.Credentials
|
|||||||
/// <param name="package">The security package to acquire the credential from.</param>
|
/// <param name="package">The security package to acquire the credential from.</param>
|
||||||
public Credential( string package )
|
public Credential( string package )
|
||||||
{
|
{
|
||||||
this.disposed = false;
|
|
||||||
this.securityPackage = package;
|
this.securityPackage = package;
|
||||||
|
|
||||||
|
this.disposed = false;
|
||||||
this.expiry = DateTime.MinValue;
|
this.expiry = DateTime.MinValue;
|
||||||
|
|
||||||
this.PackageInfo = PackageSupport.GetPackageCapabilities( this.SecurityPackage );
|
this.PackageInfo = PackageSupport.GetPackageCapabilities( this.SecurityPackage );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,6 +177,10 @@ namespace NSspi.Credentials
|
|||||||
GC.SuppressFinalize( this );
|
GC.SuppressFinalize( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Releases all resources associted with the credential.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing"></param>
|
||||||
protected virtual void Dispose( bool disposing )
|
protected virtual void Dispose( bool disposing )
|
||||||
{
|
{
|
||||||
if( this.disposed == false )
|
if( this.disposed == false )
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.ConstrainedExecution;
|
using System.Runtime.ConstrainedExecution;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using NSspi.Credentials;
|
|
||||||
|
|
||||||
namespace NSspi.Credentials
|
namespace NSspi.Credentials
|
||||||
{
|
{
|
||||||
@@ -25,13 +20,27 @@ namespace NSspi.Credentials
|
|||||||
ref TimeStamp expiry
|
ref TimeStamp expiry
|
||||||
);
|
);
|
||||||
|
|
||||||
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )]
|
||||||
|
[DllImport( "Secur32.dll", EntryPoint = "AcquireCredentialsHandle", CharSet = CharSet.Unicode )]
|
||||||
|
internal static extern SecurityStatus AcquireCredentialsHandle_AuthData(
|
||||||
|
string principleName,
|
||||||
|
string packageName,
|
||||||
|
CredentialUse credentialUse,
|
||||||
|
IntPtr loginId,
|
||||||
|
ref NativeAuthData authData,
|
||||||
|
IntPtr getKeyFunc,
|
||||||
|
IntPtr getKeyData,
|
||||||
|
ref RawSspiHandle credentialHandle,
|
||||||
|
ref TimeStamp expiry
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||||
[DllImport( "Secur32.dll", EntryPoint = "FreeCredentialsHandle", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "FreeCredentialsHandle", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus FreeCredentialsHandle(
|
internal static extern SecurityStatus FreeCredentialsHandle(
|
||||||
ref RawSspiHandle credentialHandle
|
ref RawSspiHandle credentialHandle
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The overload of the QueryCredentialsAttribute method that is used for querying the name attribute.
|
/// The overload of the QueryCredentialsAttribute method that is used for querying the name attribute.
|
||||||
/// In this call, it takes a void* to a structure that contains a wide char pointer. The wide character
|
/// In this call, it takes a void* to a structure that contains a wide char pointer. The wide character
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Credentials
|
namespace NSspi.Credentials
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Credentials
|
namespace NSspi.Credentials
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Credentials
|
namespace NSspi.Credentials
|
||||||
{
|
{
|
||||||
@@ -64,6 +60,5 @@ namespace NSspi.Credentials
|
|||||||
|
|
||||||
this.Expiry = rawExpiry.ToDateTime();
|
this.Expiry = rawExpiry.ToDateTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
78
NSspi/Credentials/PasswordCredential.cs
Normal file
78
NSspi/Credentials/PasswordCredential.cs
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NSspi.Credentials
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents credentials acquired by providing a username, password, and domain.
|
||||||
|
/// </summary>
|
||||||
|
public class PasswordCredential : Credential
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the PasswordCredential class.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// It is possible to acquire a valid handle to credentials that do not provide a valid
|
||||||
|
/// username-password combination. The username and password are not validation until the
|
||||||
|
/// authentication cycle begins.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="domain">The domain to authenticate to.</param>
|
||||||
|
/// <param name="username">The username of the user to authenticate as.</param>
|
||||||
|
/// <param name="password">The user's password.</param>
|
||||||
|
/// <param name="secPackage">The SSPI security package to create credentials for.</param>
|
||||||
|
/// <param name="use">
|
||||||
|
/// Specify inbound when acquiring credentials for a server; outbound for a client.
|
||||||
|
/// </param>
|
||||||
|
public PasswordCredential( string domain, string username, string password, string secPackage, CredentialUse use )
|
||||||
|
: base( secPackage )
|
||||||
|
{
|
||||||
|
NativeAuthData authData = new NativeAuthData( domain, username, password, NativeAuthDataFlag.Unicode );
|
||||||
|
|
||||||
|
Init( authData, secPackage, use );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Init( NativeAuthData authData, string secPackage, CredentialUse use )
|
||||||
|
{
|
||||||
|
string packageName;
|
||||||
|
TimeStamp rawExpiry = new TimeStamp();
|
||||||
|
SecurityStatus status = SecurityStatus.InternalError;
|
||||||
|
|
||||||
|
// -- Package --
|
||||||
|
// Copy off for the call, since this.SecurityPackage is a property.
|
||||||
|
packageName = this.SecurityPackage;
|
||||||
|
|
||||||
|
this.Handle = new SafeCredentialHandle();
|
||||||
|
|
||||||
|
|
||||||
|
// The finally clause is the actual constrained region. The VM pre-allocates any stack space,
|
||||||
|
// performs any allocations it needs to prepare methods for execution, and postpones any
|
||||||
|
// instances of the 'uncatchable' exceptions (ThreadAbort, StackOverflow, OutOfMemory).
|
||||||
|
RuntimeHelpers.PrepareConstrainedRegions();
|
||||||
|
try { }
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
status = CredentialNativeMethods.AcquireCredentialsHandle_AuthData(
|
||||||
|
null,
|
||||||
|
packageName,
|
||||||
|
use,
|
||||||
|
IntPtr.Zero,
|
||||||
|
ref authData,
|
||||||
|
IntPtr.Zero,
|
||||||
|
IntPtr.Zero,
|
||||||
|
ref this.Handle.rawHandle,
|
||||||
|
ref rawExpiry
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( status != SecurityStatus.OK )
|
||||||
|
{
|
||||||
|
throw new SSPIException( "Failed to call AcquireCredentialHandle", status );
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Expiry = rawExpiry.ToDateTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Credentials
|
namespace NSspi.Credentials
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.ConstrainedExecution;
|
using System.Runtime.ConstrainedExecution;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Credentials
|
namespace NSspi.Credentials
|
||||||
{
|
{
|
||||||
@@ -12,10 +8,17 @@ namespace NSspi.Credentials
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class SafeCredentialHandle : SafeSspiHandle
|
public class SafeCredentialHandle : SafeSspiHandle
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SafeCredentialHandle"/> class.
|
||||||
|
/// </summary>
|
||||||
public SafeCredentialHandle()
|
public SafeCredentialHandle()
|
||||||
: base()
|
: base()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Releases the resources held by the credential handle.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||||
protected override bool ReleaseHandle()
|
protected override bool ReleaseHandle()
|
||||||
{
|
{
|
||||||
@@ -28,5 +31,4 @@ namespace NSspi.Credentials
|
|||||||
return status == SecurityStatus.OK;
|
return status == SecurityStatus.OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,23 +1,19 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Credentials
|
namespace NSspi.Credentials
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the credentials of the user running the current process, for use as an SSPI server.
|
/// Represents a handle to the credentials of the user running the current process, to be used to
|
||||||
|
/// authenticate as a server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ServerCredential : CurrentCredential
|
public class ServerCurrentCredential : CurrentCredential
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the ServerCredential class, acquiring credentials from
|
/// Initializes a new instance of the ServerCredential class, acquiring credentials from
|
||||||
/// the current thread's security context.
|
/// the current thread's security context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="package">The name of the security package to obtain credentials from.</param>
|
/// <param name="package">The name of the security package to obtain credentials from.</param>
|
||||||
public ServerCredential( string package )
|
public ServerCurrentCredential( string package )
|
||||||
: base( package, CredentialUse.Inbound )
|
: base( package, CredentialUse.Inbound )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
82
NSspi/EnumMgr.cs
Normal file
82
NSspi/EnumMgr.cs
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace NSspi
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Tags an enumeration member with a string that can be programmatically accessed.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage( AttributeTargets.Field )]
|
||||||
|
public class EnumStringAttribute : Attribute
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="EnumStringAttribute"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">The string to associate with the enumeration member.</param>
|
||||||
|
public EnumStringAttribute( string text )
|
||||||
|
{
|
||||||
|
this.Text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the string associated with the enumeration member.
|
||||||
|
/// </summary>
|
||||||
|
public string Text { get; private set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts betwen enumeration members and the strings associated to the members through the
|
||||||
|
/// <see cref="EnumStringAttribute"/> type.
|
||||||
|
/// </summary>
|
||||||
|
public class EnumMgr
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the text associated with the given enumeration member through a <see cref="EnumStringAttribute"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string ToText( Enum value )
|
||||||
|
{
|
||||||
|
FieldInfo field = value.GetType().GetField( value.ToString() );
|
||||||
|
|
||||||
|
EnumStringAttribute[] attribs = (EnumStringAttribute[])field.GetCustomAttributes( typeof( EnumStringAttribute ), false );
|
||||||
|
|
||||||
|
if( attribs == null || attribs.Length == 0 )
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return attribs[0].Text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the enumeration member that is tagged with the given text using the <see cref="EnumStringAttribute"/> type.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The enumeration type to inspect.</typeparam>
|
||||||
|
/// <param name="text"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static T FromText<T>( string text )
|
||||||
|
{
|
||||||
|
FieldInfo[] fields = typeof( T ).GetFields();
|
||||||
|
|
||||||
|
EnumStringAttribute[] attribs;
|
||||||
|
|
||||||
|
foreach( FieldInfo field in fields )
|
||||||
|
{
|
||||||
|
attribs = (EnumStringAttribute[])field.GetCustomAttributes( typeof( EnumStringAttribute ), false );
|
||||||
|
|
||||||
|
foreach( EnumStringAttribute attrib in attribs )
|
||||||
|
{
|
||||||
|
if( attrib.Text == text )
|
||||||
|
{
|
||||||
|
return (T)field.GetValue( null );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ArgumentException( "Could not find a matching enumeration value for the text '" + text + "'." );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,95 +1,31 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
<TargetFrameworks>netstandard2.0;net40</TargetFrameworks>
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
|
||||||
<ProjectGuid>{4B4CD933-BF62-4F92-B8FA-6771758C5197}</ProjectGuid>
|
|
||||||
<OutputType>Library</OutputType>
|
|
||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
|
||||||
<RootNamespace>NSspi</RootNamespace>
|
<RootNamespace>NSspi</RootNamespace>
|
||||||
<AssemblyName>NSspi</AssemblyName>
|
<AssemblyName>NSspi</AssemblyName>
|
||||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
<FileAlignment>512</FileAlignment>
|
<Authors>Kevin Thompson</Authors>
|
||||||
<TargetFrameworkProfile />
|
<PackageReleaseNotes>Adds support for accessing the remote identity.</PackageReleaseNotes>
|
||||||
</PropertyGroup>
|
<PackageProjectUrl>https://github.com/antiduh/nsspi</PackageProjectUrl>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
<Version>0.3.1.0</Version>
|
||||||
<DebugSymbols>true</DebugSymbols>
|
<SignAssembly>true</SignAssembly>
|
||||||
<DebugType>full</DebugType>
|
<DelaySign>false</DelaySign>
|
||||||
<Optimize>false</Optimize>
|
<AssemblyOriginatorKeyFile>nsspi key.snk</AssemblyOriginatorKeyFile>
|
||||||
<OutputPath>bin\Debug\</OutputPath>
|
<PackageLicenseFile>License.txt</PackageLicenseFile>
|
||||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
|
|
||||||
<Prefer32Bit>false</Prefer32Bit>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<OutputPath>bin\Release\</OutputPath>
|
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<DocumentationFile>bin\Release\NSspi.XML</DocumentationFile>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<StartupObject>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</StartupObject>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="System" />
|
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
|
||||||
<Reference Include="System.Core" />
|
<PackageReference Include="System.Security.Principal.Windows" Version="4.5.1" />
|
||||||
<Reference Include="System.DirectoryServices" />
|
|
||||||
<Reference Include="System.DirectoryServices.AccountManagement" />
|
|
||||||
<Reference Include="System.Xml.Linq" />
|
|
||||||
<Reference Include="System.Data.DataSetExtensions" />
|
|
||||||
<Reference Include="Microsoft.CSharp" />
|
|
||||||
<Reference Include="System.Data" />
|
|
||||||
<Reference Include="System.Xml" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="ByteWriter.cs" />
|
<None Include="..\License.txt">
|
||||||
<Compile Include="Contexts\ClientContext.cs" />
|
<Pack>True</Pack>
|
||||||
<Compile Include="Contexts\Context.cs" />
|
<PackagePath></PackagePath>
|
||||||
<Compile Include="Contexts\ContextAttrib.cs" />
|
</None>
|
||||||
<Compile Include="Contexts\ContextNativeMethods.cs" />
|
|
||||||
<Compile Include="Contexts\ContextQueries.cs" />
|
|
||||||
<Compile Include="Contexts\ContextQueryAttrib.cs" />
|
|
||||||
<Compile Include="Contexts\ImpersonationHandle.cs" />
|
|
||||||
<Compile Include="Contexts\SafeContextHandle.cs" />
|
|
||||||
<Compile Include="Credentials\CurrentCredential.cs" />
|
|
||||||
<Compile Include="SecPkgInfo.cs" />
|
|
||||||
<Compile Include="Contexts\ServerContext.cs" />
|
|
||||||
<Compile Include="Credentials\ClientCredential.cs" />
|
|
||||||
<Compile Include="Credentials\Credential.cs" />
|
|
||||||
<Compile Include="Credentials\CredentialNativeMethods.cs" />
|
|
||||||
<Compile Include="Credentials\CredentialQueryAttrib.cs" />
|
|
||||||
<Compile Include="Credentials\CredentialUse.cs" />
|
|
||||||
<Compile Include="Credentials\QueryNameSupport.cs" />
|
|
||||||
<Compile Include="Credentials\SafeCredentialHandle.cs" />
|
|
||||||
<Compile Include="Credentials\ServerCredential.cs" />
|
|
||||||
<Compile Include="NativeMethods.cs" />
|
|
||||||
<Compile Include="PackageSupport.cs" />
|
|
||||||
<Compile Include="PackageNames.cs" />
|
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
|
||||||
<Compile Include="SecureBuffer\SecureBuffer.cs" />
|
|
||||||
<Compile Include="SecureBuffer\SecureBufferAdapter.cs" />
|
|
||||||
<Compile Include="SecureBuffer\SecureBufferDataRep.cs" />
|
|
||||||
<Compile Include="SecureBuffer\SecureBufferDesc.cs" />
|
|
||||||
<Compile Include="SecureBuffer\SecureBufferType.cs" />
|
|
||||||
<Compile Include="SecurityStatus.cs" />
|
|
||||||
<Compile Include="SSPIException.cs" />
|
|
||||||
<Compile Include="SspiHandle.cs" />
|
|
||||||
<Compile Include="TimeStamp.cs" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup />
|
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
|
||||||
<Target Name="BeforeBuild">
|
|
||||||
</Target>
|
|
||||||
<Target Name="AfterBuild">
|
|
||||||
</Target>
|
|
||||||
-->
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -1,11 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.ConstrainedExecution;
|
using System.Runtime.ConstrainedExecution;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using NSspi.Contexts;
|
|
||||||
|
|
||||||
namespace NSspi
|
namespace NSspi
|
||||||
{
|
{
|
||||||
@@ -15,7 +10,6 @@ namespace NSspi
|
|||||||
[DllImport( "Secur32.dll", EntryPoint = "FreeContextBuffer", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "FreeContextBuffer", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus FreeContextBuffer( IntPtr buffer );
|
internal static extern SecurityStatus FreeContextBuffer( IntPtr buffer );
|
||||||
|
|
||||||
|
|
||||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||||
[DllImport( "Secur32.dll", EntryPoint = "QuerySecurityPackageInfo", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "QuerySecurityPackageInfo", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus QuerySecurityPackageInfo( string packageName, ref IntPtr pkgInfo );
|
internal static extern SecurityStatus QuerySecurityPackageInfo( string packageName, ref IntPtr pkgInfo );
|
||||||
@@ -24,5 +18,8 @@ namespace NSspi
|
|||||||
[DllImport( "Secur32.dll", EntryPoint = "EnumerateSecurityPackages", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "EnumerateSecurityPackages", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus EnumerateSecurityPackages( ref int numPackages, ref IntPtr pkgInfoArry );
|
internal static extern SecurityStatus EnumerateSecurityPackages( ref int numPackages, ref IntPtr pkgInfoArry );
|
||||||
|
|
||||||
|
[DllImport( "Kernel32.dll", EntryPoint = "CloseHandle", SetLastError = true )]
|
||||||
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||||
|
internal static extern bool CloseHandle( IntPtr handle );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi
|
namespace NSspi
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi
|
namespace NSspi
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,18 +1,4 @@
|
|||||||
using System.Reflection;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
|
||||||
// set of attributes. Change these attribute values to modify the information
|
|
||||||
// associated with an assembly.
|
|
||||||
[assembly: AssemblyTitle("NSspi")]
|
|
||||||
[assembly: AssemblyDescription("")]
|
|
||||||
[assembly: AssemblyConfiguration("")]
|
|
||||||
[assembly: AssemblyCompany("Kevin Thompson")]
|
|
||||||
[assembly: AssemblyProduct("NSspi")]
|
|
||||||
[assembly: AssemblyCopyright("Copyright © Kevin Thompson 2014")]
|
|
||||||
[assembly: AssemblyTrademark("")]
|
|
||||||
[assembly: AssemblyCulture("")]
|
|
||||||
|
|
||||||
// Setting ComVisible to false makes the types in this assembly not visible
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
// to COM components. If you need to access a type in this assembly from
|
// to COM components. If you need to access a type in this assembly from
|
||||||
@@ -21,16 +7,3 @@ using System.Runtime.InteropServices;
|
|||||||
|
|
||||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
[assembly: Guid( "9abf710c-c646-42aa-8183-76bfa141a07b" )]
|
[assembly: Guid( "9abf710c-c646-42aa-8183-76bfa141a07b" )]
|
||||||
|
|
||||||
// Version information for an assembly consists of the following four values:
|
|
||||||
//
|
|
||||||
// Major Version
|
|
||||||
// Minor Version
|
|
||||||
// Build Number
|
|
||||||
// Revision
|
|
||||||
//
|
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
|
||||||
// by using the '*' as shown below:
|
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
|
||||||
[assembly: AssemblyVersion("1.0.0.0")]
|
|
||||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi
|
namespace NSspi
|
||||||
{
|
{
|
||||||
@@ -35,7 +31,7 @@ namespace NSspi
|
|||||||
protected SSPIException( SerializationInfo info, StreamingContext context )
|
protected SSPIException( SerializationInfo info, StreamingContext context )
|
||||||
: base( info, context )
|
: base( info, context )
|
||||||
{
|
{
|
||||||
this.message = info.GetString( "messsage" );
|
this.message = info.GetString( "message" );
|
||||||
this.errorCode = (SecurityStatus)info.GetUInt32( "errorCode" );
|
this.errorCode = (SecurityStatus)info.GetUInt32( "errorCode" );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +66,12 @@ namespace NSspi
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return string.Format( "{0}. Error Code = '{1:X}'.", this.message, this.errorCode );
|
return string.Format(
|
||||||
|
"{0}. Error Code = '0x{1:X}' - \"{2}\".",
|
||||||
|
this.message,
|
||||||
|
this.errorCode,
|
||||||
|
EnumMgr.ToText( this.errorCode )
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi
|
namespace NSspi
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Buffers
|
namespace NSspi.Buffers
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.ConstrainedExecution;
|
using System.Runtime.ConstrainedExecution;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Buffers
|
namespace NSspi.Buffers
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Buffers
|
namespace NSspi.Buffers
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.ConstrainedExecution;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Buffers
|
namespace NSspi.Buffers
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Buffers
|
namespace NSspi.Buffers
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi
|
namespace NSspi
|
||||||
{
|
{
|
||||||
@@ -30,56 +26,158 @@ namespace NSspi
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The request completed successfully
|
/// The request completed successfully
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[EnumString( "No error" )]
|
||||||
OK = 0x00000000,
|
OK = 0x00000000,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The token returned by the context needs to be provided to the cooperating party
|
/// The token returned by the context needs to be provided to the cooperating party
|
||||||
/// to continue construction of the context.
|
/// to continue construction of the context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[EnumString( "Authentication cycle needs to continue" )]
|
||||||
ContinueNeeded = 0x00090312,
|
ContinueNeeded = 0x00090312,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Occurs after a client calls InitializeSecurityContext to indicate that the client
|
/// Occurs after a client calls InitializeSecurityContext to indicate that the client
|
||||||
/// must call CompleteAuthToken.
|
/// must call CompleteAuthToken.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[EnumString( "Authentication cycle needs to perform a 'complete'." )]
|
||||||
CompleteNeeded = 0x00090313,
|
CompleteNeeded = 0x00090313,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Occurs after a client calls InitializeSecurityContext to indicate that the client
|
/// Occurs after a client calls InitializeSecurityContext to indicate that the client
|
||||||
/// must call CompleteAuthToken and pass the result to the server.
|
/// must call CompleteAuthToken and pass the result to the server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[EnumString( "Authentication cycle needs to perform a 'complete' and then continue." )]
|
||||||
CompAndContinue = 0x00090314,
|
CompAndContinue = 0x00090314,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An attempt to use the context was performed after the context's expiration time elapsed.
|
/// An attempt to use the context was performed after the context's expiration time elapsed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[EnumString( "The security context was used after its expiration time passed." )]
|
||||||
ContextExpired = 0x00090317,
|
ContextExpired = 0x00090317,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The credentials supplied to the security context were not fully initialized.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "The credentials supplied to the security context were not fully initialized." )]
|
||||||
CredentialsNeeded = 0x00090320,
|
CredentialsNeeded = 0x00090320,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The context data must be re-negotiated with the peer.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "The context data must be re-negotiated with the peer." )]
|
||||||
Renegotiate = 0x00090321,
|
Renegotiate = 0x00090321,
|
||||||
|
|
||||||
// Errors
|
// -------------- Errors --------------
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The SSPI operation failed due to insufficient memory resources.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "Not enough memory." )]
|
||||||
OutOfMemory = 0x80090300,
|
OutOfMemory = 0x80090300,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The handle provided to the API was invalid.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "The handle provided to the API was invalid." )]
|
||||||
InvalidHandle = 0x80090301,
|
InvalidHandle = 0x80090301,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The attempted operation is not supported.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "The attempted operation is not supported." )]
|
||||||
Unsupported = 0x80090302,
|
Unsupported = 0x80090302,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The specified principle is not known in the authentication system.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "The specified principle is not known in the authentication system." )]
|
||||||
TargetUnknown = 0x80090303,
|
TargetUnknown = 0x80090303,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An internal error occurred
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "An internal error occurred." )]
|
||||||
InternalError = 0x80090304,
|
InternalError = 0x80090304,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// No security provider package was found with the given name.
|
/// No security provider package was found with the given name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[EnumString( "The requested security package was not found." )]
|
||||||
PackageNotFound = 0x80090305,
|
PackageNotFound = 0x80090305,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cannot use the provided credentials, the caller is not the owner of the credentials.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "The caller is not the owner of the desired credentials." )]
|
||||||
NotOwner = 0x80090306,
|
NotOwner = 0x80090306,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The requested security package failed to initalize, and thus cannot be used.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "The requested security package failed to initalize, and thus cannot be used." )]
|
||||||
CannotInstall = 0x80090307,
|
CannotInstall = 0x80090307,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A token was provided that contained incorrect or corrupted data.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "The provided authentication token is invalid or corrupted." )]
|
||||||
InvalidToken = 0x80090308,
|
InvalidToken = 0x80090308,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The security package is not able to marshall the logon buffer, so the logon attempt has failed
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "The security package is not able to marshall the logon buffer, so the logon attempt has failed." )]
|
||||||
CannotPack = 0x80090309,
|
CannotPack = 0x80090309,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The per-message Quality of Protection is not supported by the security package.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "The per-message Quality of Protection is not supported by the security package." )]
|
||||||
QopNotSupported = 0x8009030A,
|
QopNotSupported = 0x8009030A,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Impersonation is not supported.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "Impersonation is not supported with the current security package." )]
|
||||||
NoImpersonation = 0x8009030B,
|
NoImpersonation = 0x8009030B,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The logon was denied, perhaps because the provided credentials were incorrect.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "The logon was denied, perhaps because the provided credentials were incorrect." )]
|
||||||
LogonDenied = 0x8009030C,
|
LogonDenied = 0x8009030C,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The credentials provided are not recognized by the selected security package.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "The credentials provided are not recognized by the selected security package." )]
|
||||||
UnknownCredentials = 0x8009030D,
|
UnknownCredentials = 0x8009030D,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// No credentials are available in the selected security package.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "No credentials are available in the selected security package." )]
|
||||||
NoCredentials = 0x8009030E,
|
NoCredentials = 0x8009030E,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A message that was provided to the Decrypt or VerifySignature functions was altered after
|
||||||
|
/// it was created.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "A message that was provided to the Decrypt or VerifySignature functions was altered " +
|
||||||
|
"after it was created." )]
|
||||||
MessageAltered = 0x8009030F,
|
MessageAltered = 0x8009030F,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A message was received out of the expected order.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "A message was received out of the expected order." )]
|
||||||
OutOfSequence = 0x80090310,
|
OutOfSequence = 0x80090310,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current security package cannot contact an authenticating authority.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "The current security package cannot contact an authenticating authority." )]
|
||||||
NoAuthenticatingAuthority = 0x80090311,
|
NoAuthenticatingAuthority = 0x80090311,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -93,19 +191,87 @@ namespace NSspi
|
|||||||
/// will indicate success, but will save off the extra, unrelated data in a buffer of
|
/// will indicate success, but will save off the extra, unrelated data in a buffer of
|
||||||
/// type 'extra'.
|
/// type 'extra'.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
|
[EnumString( "The buffer provided to an SSPI API call contained a message that was not complete." )]
|
||||||
IncompleteMessage = 0x80090318,
|
IncompleteMessage = 0x80090318,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The credentials supplied were not complete, and could not be verified. The context could not be initialized.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "The credentials supplied were not complete, and could not be verified. The context could not be initialized." )]
|
||||||
IncompleteCredentials = 0x80090320,
|
IncompleteCredentials = 0x80090320,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The buffers supplied to a security function were too small.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "The buffers supplied to a security function were too small." )]
|
||||||
BufferNotEnough = 0x80090321,
|
BufferNotEnough = 0x80090321,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The target principal name is incorrect.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "The target principal name is incorrect." )]
|
||||||
WrongPrincipal = 0x80090322,
|
WrongPrincipal = 0x80090322,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The clocks on the client and server machines are skewed.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "The clocks on the client and server machines are skewed." )]
|
||||||
TimeSkew = 0x80090324,
|
TimeSkew = 0x80090324,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The certificate chain was issued by an authority that is not trusted.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "The certificate chain was issued by an authority that is not trusted." )]
|
||||||
UntrustedRoot = 0x80090325,
|
UntrustedRoot = 0x80090325,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The message received was unexpected or badly formatted.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "The message received was unexpected or badly formatted." )]
|
||||||
IllegalMessage = 0x80090326,
|
IllegalMessage = 0x80090326,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An unknown error occurred while processing the certificate.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "An unknown error occurred while processing the certificate." )]
|
||||||
CertUnknown = 0x80090327,
|
CertUnknown = 0x80090327,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The received certificate has expired.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "The received certificate has expired." )]
|
||||||
CertExpired = 0x80090328,
|
CertExpired = 0x80090328,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The client and server cannot communicate, because they do not possess a common algorithm.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "The client and server cannot communicate, because they do not possess a common algorithm." )]
|
||||||
AlgorithmMismatch = 0x80090331,
|
AlgorithmMismatch = 0x80090331,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The security context could not be established due to a failure in the requested quality
|
||||||
|
/// of service (e.g. mutual authentication or delegation).
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "The security context could not be established due to a failure in the requested " +
|
||||||
|
"quality of service (e.g. mutual authentication or delegation)." )]
|
||||||
SecurityQosFailed = 0x80090332,
|
SecurityQosFailed = 0x80090332,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Smartcard logon is required and was not used.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "Smartcard logon is required and was not used." )]
|
||||||
SmartcardLogonRequired = 0x8009033E,
|
SmartcardLogonRequired = 0x8009033E,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An unsupported preauthentication mechanism was presented to the Kerberos package.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "An unsupported preauthentication mechanism was presented to the Kerberos package." )]
|
||||||
UnsupportedPreauth = 0x80090343,
|
UnsupportedPreauth = 0x80090343,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Client's supplied SSPI channel bindings were incorrect.
|
||||||
|
/// </summary>
|
||||||
|
[EnumString( "Client's supplied SSPI channel bindings were incorrect." )]
|
||||||
BadBinding = 0x80090346
|
BadBinding = 0x80090346
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,5 +290,4 @@ namespace NSspi
|
|||||||
return (uint)status > 0x80000000u;
|
return (uint)status > 0x80000000u;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.ConstrainedExecution;
|
using System.Runtime.ConstrainedExecution;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using NSspi.Contexts;
|
|
||||||
|
|
||||||
namespace NSspi
|
namespace NSspi
|
||||||
{
|
{
|
||||||
@@ -61,17 +55,27 @@ namespace NSspi
|
|||||||
{
|
{
|
||||||
internal RawSspiHandle rawHandle;
|
internal RawSspiHandle rawHandle;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SafeSspiHandle"/> class.
|
||||||
|
/// </summary>
|
||||||
protected SafeSspiHandle()
|
protected SafeSspiHandle()
|
||||||
: base( IntPtr.Zero, true )
|
: base( IntPtr.Zero, true )
|
||||||
{
|
{
|
||||||
this.rawHandle = new RawSspiHandle();
|
this.rawHandle = new RawSspiHandle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets whether the handle is invalid.
|
||||||
|
/// </summary>
|
||||||
public override bool IsInvalid
|
public override bool IsInvalid
|
||||||
{
|
{
|
||||||
get { return IsClosed || this.rawHandle.IsZero(); }
|
get { return IsClosed || this.rawHandle.IsZero(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Marks the handle as no longer being in use.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||||
protected override bool ReleaseHandle()
|
protected override bool ReleaseHandle()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi
|
namespace NSspi
|
||||||
{
|
{
|
||||||
@@ -14,6 +10,9 @@ namespace NSspi
|
|||||||
[StructLayout( LayoutKind.Sequential )]
|
[StructLayout( LayoutKind.Sequential )]
|
||||||
public struct TimeStamp
|
public struct TimeStamp
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the calendar date and time corresponding a zero timestamp.
|
||||||
|
/// </summary>
|
||||||
public static readonly DateTime Epoch = new DateTime( 1601, 1, 1, 0, 0, 0, DateTimeKind.Utc );
|
public static readonly DateTime Epoch = new DateTime( 1601, 1, 1, 0, 0, 0, DateTimeKind.Utc );
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
BIN
NSspi/nsspi key.snk
Normal file
BIN
NSspi/nsspi key.snk
Normal file
Binary file not shown.
2
NsspiDemo/.gitignore
vendored
Normal file
2
NsspiDemo/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
bin
|
||||||
|
obj
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<startup>
|
<startup>
|
||||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
|
||||||
</startup>
|
</startup>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
<RootNamespace>NsspiDemo</RootNamespace>
|
<RootNamespace>NsspiDemo</RootNamespace>
|
||||||
<AssemblyName>NsspiDemo</AssemblyName>
|
<AssemblyName>NsspiDemo</AssemblyName>
|
||||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||||
<FileAlignment>512</FileAlignment>
|
<FileAlignment>512</FileAlignment>
|
||||||
<TargetFrameworkProfile />
|
<TargetFrameworkProfile />
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
@@ -31,6 +32,7 @@
|
|||||||
<DefineConstants>TRACE</DefineConstants>
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
|
|||||||
@@ -16,10 +16,10 @@ namespace NSspi
|
|||||||
|
|
||||||
private static void CredTest( string packageName )
|
private static void CredTest( string packageName )
|
||||||
{
|
{
|
||||||
ClientCredential clientCred = null;
|
ClientCurrentCredential clientCred = null;
|
||||||
ClientContext client = null;
|
ClientContext client = null;
|
||||||
|
|
||||||
ServerCredential serverCred = null;
|
ServerCurrentCredential serverCred = null;
|
||||||
ServerContext server = null;
|
ServerContext server = null;
|
||||||
|
|
||||||
byte[] clientToken;
|
byte[] clientToken;
|
||||||
@@ -30,8 +30,8 @@ namespace NSspi
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
clientCred = new ClientCredential( packageName );
|
clientCred = new ClientCurrentCredential( packageName );
|
||||||
serverCred = new ServerCredential( packageName );
|
serverCred = new ServerCurrentCredential( packageName );
|
||||||
|
|
||||||
Console.Out.WriteLine( clientCred.PrincipleName );
|
Console.Out.WriteLine( clientCred.PrincipleName );
|
||||||
|
|
||||||
@@ -47,7 +47,6 @@ namespace NSspi
|
|||||||
ContextAttrib.Delegate
|
ContextAttrib.Delegate
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
server = new ServerContext(
|
server = new ServerContext(
|
||||||
serverCred,
|
serverCred,
|
||||||
ContextAttrib.MutualAuth |
|
ContextAttrib.MutualAuth |
|
||||||
@@ -75,7 +74,6 @@ namespace NSspi
|
|||||||
if( serverStatus != SecurityStatus.ContinueNeeded && clientStatus != SecurityStatus.ContinueNeeded ) { break; }
|
if( serverStatus != SecurityStatus.ContinueNeeded && clientStatus != SecurityStatus.ContinueNeeded ) { break; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Console.Out.WriteLine( "Server authority: " + server.AuthorityName );
|
Console.Out.WriteLine( "Server authority: " + server.AuthorityName );
|
||||||
Console.Out.WriteLine( "Server context user: " + server.ContextUserName );
|
Console.Out.WriteLine( "Server context user: " + server.ContextUserName );
|
||||||
|
|
||||||
@@ -117,10 +115,8 @@ namespace NSspi
|
|||||||
throw new Exception();
|
throw new Exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
using( server.ImpersonateClient() )
|
using( server.ImpersonateClient() )
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cipherText = client.MakeSignature( plainText );
|
cipherText = client.MakeSignature( plainText );
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
// General Information about an assembly is controlled through the following
|
||||||
|
|||||||
4
NsspiDemo/Properties/Resources.Designer.cs
generated
4
NsspiDemo/Properties/Resources.Designer.cs
generated
@@ -1,7 +1,7 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// <auto-generated>
|
// <auto-generated>
|
||||||
// This code was generated by a tool.
|
// This code was generated by a tool.
|
||||||
// Runtime Version:4.0.30319.18444
|
// Runtime Version:4.0.30319.42000
|
||||||
//
|
//
|
||||||
// Changes to this file may cause incorrect behavior and will be lost if
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
// the code is regenerated.
|
// the code is regenerated.
|
||||||
@@ -19,7 +19,7 @@ namespace NsspiDemo.Properties {
|
|||||||
// class via a tool like ResGen or Visual Studio.
|
// class via a tool like ResGen or Visual Studio.
|
||||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
// with the /str option, or rebuild your VS project.
|
// with the /str option, or rebuild your VS project.
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
internal class Resources {
|
internal class Resources {
|
||||||
|
|||||||
4
NsspiDemo/Properties/Settings.Designer.cs
generated
4
NsspiDemo/Properties/Settings.Designer.cs
generated
@@ -1,7 +1,7 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// <auto-generated>
|
// <auto-generated>
|
||||||
// This code was generated by a tool.
|
// This code was generated by a tool.
|
||||||
// Runtime Version:4.0.30319.18444
|
// Runtime Version:4.0.30319.42000
|
||||||
//
|
//
|
||||||
// Changes to this file may cause incorrect behavior and will be lost if
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
// the code is regenerated.
|
// the code is regenerated.
|
||||||
@@ -12,7 +12,7 @@ namespace NsspiDemo.Properties {
|
|||||||
|
|
||||||
|
|
||||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.7.0.0")]
|
||||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||||
|
|
||||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||||
|
|||||||
70
Readme.txt
70
Readme.txt
@@ -1,70 +0,0 @@
|
|||||||
This projects provides a C# / .Net interface to the Windows Integrated Authentication API,
|
|
||||||
better known as SSPI (Security Service Provider Interface).
|
|
||||||
|
|
||||||
The project is provided as a .Net 4.0 assembly, but can just as easily be upgraded to .Net 4.5
|
|
||||||
or later. The solution file can be opened by Visual Studio 2010 SP1, Visual Studio 2012, or
|
|
||||||
later Visual Studio editions.
|
|
||||||
|
|
||||||
The SSPI API provides an interface for real authentication protocols, such as Kerberos or
|
|
||||||
NTLM, to be invoked transparently by client and server code in order to perform authentication
|
|
||||||
and message manipulation. These authentication protocols are better known as 'security packages'.
|
|
||||||
|
|
||||||
The SSPI API exposes these packages using a common API, and so a program may invoke one or the
|
|
||||||
other with only minor changes in implementation. SSPI also supports the 'negotiate' 'meta'
|
|
||||||
package, that allows a client and server to decide dynamically which real security provider to
|
|
||||||
use, and then itself provides a passthrough interface to the real package.
|
|
||||||
|
|
||||||
==== Usage ====
|
|
||||||
|
|
||||||
Typically, a client acquires some form of a credential, either from the currently logged on
|
|
||||||
user's security context, by acquiring a username and password from the user, or by some other
|
|
||||||
means. The server acquires a credential in a similar manner. Each uses their credentials to
|
|
||||||
identify themselves to each other.
|
|
||||||
|
|
||||||
A client and a server each start with uninitialized security contexts. They exchange negotiation
|
|
||||||
and authentication tokens to perform authentication, and if all succeeds, they create a shared
|
|
||||||
security context in the form of a client's context and a server's context. The effectively shared
|
|
||||||
context agrees on the security package to use (kerberos, NTLM), and what parameters to use
|
|
||||||
for message passing. Every new client that authenticates with a server creates a new security
|
|
||||||
context specific to that client-server pairing.
|
|
||||||
|
|
||||||
From the software perspective, a client security context initializes itself by exchanging
|
|
||||||
authentication tokens with a server; the server initializes itself by exchanging authentication
|
|
||||||
tokens with the client.
|
|
||||||
|
|
||||||
This API provides raw access to the authentication tokens created during the negotiation and
|
|
||||||
authentication process. In this manner, any application can integrate SSPI-based authentication
|
|
||||||
by deciding for themselves how to integrate the tokens into their application protocol.
|
|
||||||
|
|
||||||
The project is broken up into 3 chunks:
|
|
||||||
|
|
||||||
* The NSspi library, which provides safe, managed access to the SSPI API.
|
|
||||||
* NsspiDemo, a quick demo program to show how to exercise the features of NSspi locally.
|
|
||||||
* UI demo programs TestClient and TestServer (that have a common dependency on TestProtocol) that
|
|
||||||
may be run on separate machines, that show how one might integrate SSPI into a custom
|
|
||||||
application.
|
|
||||||
|
|
||||||
==== More information ====
|
|
||||||
|
|
||||||
If you would like to understand the SSPI API, feel free to browse the following references:
|
|
||||||
|
|
||||||
MSDN documentation on the SSPI API
|
|
||||||
http://msdn.microsoft.com/en-us/library/windows/desktop/aa374731(v=vs.85).aspx
|
|
||||||
|
|
||||||
MSDN article on SSPI along with a sample Managed C++ SSPI library and UI client/servers.
|
|
||||||
http://msdn.microsoft.com/en-us/library/ms973911.aspx
|
|
||||||
|
|
||||||
Relevant StackOverflow questions:
|
|
||||||
"Client-server authentication - using SSPI?"
|
|
||||||
- http://stackoverflow.com/questions/17241365/
|
|
||||||
|
|
||||||
"Validate Windows Identity Token"
|
|
||||||
- http://stackoverflow.com/questions/11238141/
|
|
||||||
|
|
||||||
"How to deal with allocations in constrained execution regions?"
|
|
||||||
- http://stackoverflow.com/questions/24442209/
|
|
||||||
|
|
||||||
"AcquireCredentialsHandle returns massive expiration time"
|
|
||||||
- http://stackoverflow.com/questions/24478056/
|
|
||||||
|
|
||||||
|
|
||||||
2
TestClient/.gitignore
vendored
Normal file
2
TestClient/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
bin
|
||||||
|
obj
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<startup>
|
<startup>
|
||||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
|
||||||
</startup>
|
</startup>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|||||||
8
TestClient/ClientForm.Designer.cs
generated
8
TestClient/ClientForm.Designer.cs
generated
@@ -148,6 +148,7 @@
|
|||||||
this.sendTextbox.Location = new System.Drawing.Point(6, 19);
|
this.sendTextbox.Location = new System.Drawing.Point(6, 19);
|
||||||
this.sendTextbox.Multiline = true;
|
this.sendTextbox.Multiline = true;
|
||||||
this.sendTextbox.Name = "sendTextbox";
|
this.sendTextbox.Name = "sendTextbox";
|
||||||
|
this.sendTextbox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
|
||||||
this.sendTextbox.Size = new System.Drawing.Size(302, 298);
|
this.sendTextbox.Size = new System.Drawing.Size(302, 298);
|
||||||
this.sendTextbox.TabIndex = 7;
|
this.sendTextbox.TabIndex = 7;
|
||||||
//
|
//
|
||||||
@@ -190,6 +191,7 @@
|
|||||||
this.receiveTextbox.Location = new System.Drawing.Point(3, 16);
|
this.receiveTextbox.Location = new System.Drawing.Point(3, 16);
|
||||||
this.receiveTextbox.Multiline = true;
|
this.receiveTextbox.Multiline = true;
|
||||||
this.receiveTextbox.Name = "receiveTextbox";
|
this.receiveTextbox.Name = "receiveTextbox";
|
||||||
|
this.receiveTextbox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
|
||||||
this.receiveTextbox.Size = new System.Drawing.Size(308, 338);
|
this.receiveTextbox.Size = new System.Drawing.Size(308, 338);
|
||||||
this.receiveTextbox.TabIndex = 10;
|
this.receiveTextbox.TabIndex = 10;
|
||||||
//
|
//
|
||||||
@@ -231,7 +233,7 @@
|
|||||||
this.disconnectButton.Text = "Disconnect";
|
this.disconnectButton.Text = "Disconnect";
|
||||||
this.disconnectButton.UseVisualStyleBackColor = true;
|
this.disconnectButton.UseVisualStyleBackColor = true;
|
||||||
//
|
//
|
||||||
// Form1
|
// ClientForm
|
||||||
//
|
//
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
@@ -244,8 +246,8 @@
|
|||||||
this.Controls.Add(this.serverTextBox);
|
this.Controls.Add(this.serverTextBox);
|
||||||
this.Controls.Add(this.label2);
|
this.Controls.Add(this.label2);
|
||||||
this.Controls.Add(this.label1);
|
this.Controls.Add(this.label1);
|
||||||
this.Name = "Form1";
|
this.Name = "ClientForm";
|
||||||
this.Text = "Form1";
|
this.Text = "Client - SSPI Demo";
|
||||||
((System.ComponentModel.ISupportInitialize)(this.portNumeric)).EndInit();
|
((System.ComponentModel.ISupportInitialize)(this.portNumeric)).EndInit();
|
||||||
this.groupBox1.ResumeLayout(false);
|
this.groupBox1.ResumeLayout(false);
|
||||||
this.groupBox1.PerformLayout();
|
this.groupBox1.PerformLayout();
|
||||||
|
|||||||
@@ -1,12 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Data;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using NSspi;
|
using NSspi;
|
||||||
using NSspi.Contexts;
|
using NSspi.Contexts;
|
||||||
@@ -20,7 +14,7 @@ namespace TestClient
|
|||||||
public partial class ClientForm : Form
|
public partial class ClientForm : Form
|
||||||
{
|
{
|
||||||
private ClientContext context;
|
private ClientContext context;
|
||||||
private ClientCredential cred;
|
private ClientCurrentCredential cred;
|
||||||
|
|
||||||
private CustomConnection connection;
|
private CustomConnection connection;
|
||||||
|
|
||||||
@@ -48,7 +42,7 @@ namespace TestClient
|
|||||||
this.FormClosing += Form1_FormClosing;
|
this.FormClosing += Form1_FormClosing;
|
||||||
|
|
||||||
// --- SSPI ---
|
// --- SSPI ---
|
||||||
this.cred = new ClientCredential( PackageNames.Negotiate );
|
this.cred = new ClientCurrentCredential( PackageNames.Negotiate );
|
||||||
|
|
||||||
this.context = new ClientContext(
|
this.context = new ClientContext(
|
||||||
cred,
|
cred,
|
||||||
@@ -107,7 +101,6 @@ namespace TestClient
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +109,6 @@ namespace TestClient
|
|||||||
this.connection.Stop();
|
this.connection.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void encryptButton_Click( object sender, EventArgs e )
|
private void encryptButton_Click( object sender, EventArgs e )
|
||||||
{
|
{
|
||||||
byte[] plaintext;
|
byte[] plaintext;
|
||||||
|
|||||||
@@ -1,18 +1,15 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace TestClient
|
namespace TestClient
|
||||||
{
|
{
|
||||||
static class Program
|
internal static class Program
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The main entry point for the application.
|
/// The main entry point for the application.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[STAThread]
|
[STAThread]
|
||||||
static void Main()
|
private static void Main()
|
||||||
{
|
{
|
||||||
Application.EnableVisualStyles();
|
Application.EnableVisualStyles();
|
||||||
Application.SetCompatibleTextRenderingDefault( false );
|
Application.SetCompatibleTextRenderingDefault( false );
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
// General Information about an assembly is controlled through the following
|
||||||
|
|||||||
4
TestClient/Properties/Resources.Designer.cs
generated
4
TestClient/Properties/Resources.Designer.cs
generated
@@ -1,7 +1,7 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// <auto-generated>
|
// <auto-generated>
|
||||||
// This code was generated by a tool.
|
// This code was generated by a tool.
|
||||||
// Runtime Version:4.0.30319.18444
|
// Runtime Version:4.0.30319.42000
|
||||||
//
|
//
|
||||||
// Changes to this file may cause incorrect behavior and will be lost if
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
// the code is regenerated.
|
// the code is regenerated.
|
||||||
@@ -19,7 +19,7 @@ namespace TestClient.Properties {
|
|||||||
// class via a tool like ResGen or Visual Studio.
|
// class via a tool like ResGen or Visual Studio.
|
||||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
// with the /str option, or rebuild your VS project.
|
// with the /str option, or rebuild your VS project.
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
internal class Resources {
|
internal class Resources {
|
||||||
|
|||||||
4
TestClient/Properties/Settings.Designer.cs
generated
4
TestClient/Properties/Settings.Designer.cs
generated
@@ -1,7 +1,7 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// <auto-generated>
|
// <auto-generated>
|
||||||
// This code was generated by a tool.
|
// This code was generated by a tool.
|
||||||
// Runtime Version:4.0.30319.18444
|
// Runtime Version:4.0.30319.42000
|
||||||
//
|
//
|
||||||
// Changes to this file may cause incorrect behavior and will be lost if
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
// the code is regenerated.
|
// the code is regenerated.
|
||||||
@@ -12,7 +12,7 @@ namespace TestClient.Properties {
|
|||||||
|
|
||||||
|
|
||||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.7.0.0")]
|
||||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||||
|
|
||||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
<RootNamespace>TestClient</RootNamespace>
|
<RootNamespace>TestClient</RootNamespace>
|
||||||
<AssemblyName>TestClient</AssemblyName>
|
<AssemblyName>TestClient</AssemblyName>
|
||||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||||
<FileAlignment>512</FileAlignment>
|
<FileAlignment>512</FileAlignment>
|
||||||
<TargetFrameworkProfile />
|
<TargetFrameworkProfile />
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
@@ -31,6 +32,7 @@
|
|||||||
<DefineConstants>TRACE</DefineConstants>
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
|
|||||||
2
TestProtocol/.gitignore
vendored
Normal file
2
TestProtocol/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
bin
|
||||||
|
obj
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<startup>
|
<startup>
|
||||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
|
||||||
</startup>
|
</startup>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using NSspi;
|
using NSspi;
|
||||||
|
|
||||||
@@ -97,10 +93,7 @@ namespace TestProtocol
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if( this.Disconnected != null )
|
this.Disconnected?.Invoke();
|
||||||
{
|
|
||||||
this.Disconnected();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{ }
|
{ }
|
||||||
@@ -112,7 +105,10 @@ namespace TestProtocol
|
|||||||
byte[] readBuffer = new byte[65536];
|
byte[] readBuffer = new byte[65536];
|
||||||
|
|
||||||
ProtocolOp operation;
|
ProtocolOp operation;
|
||||||
int length;
|
int messageLength;
|
||||||
|
int remaining;
|
||||||
|
int chunkLength;
|
||||||
|
int position;
|
||||||
|
|
||||||
while( this.running )
|
while( this.running )
|
||||||
{
|
{
|
||||||
@@ -121,7 +117,6 @@ namespace TestProtocol
|
|||||||
// |--4 bytes--|--4 bytes--|---N--|
|
// |--4 bytes--|--4 bytes--|---N--|
|
||||||
// Every command is a TLV - | Operation | Length | Data |
|
// Every command is a TLV - | Operation | Length | Data |
|
||||||
|
|
||||||
|
|
||||||
// Read the operation.
|
// Read the operation.
|
||||||
this.socket.Receive( readBuffer, 4, SocketFlags.None );
|
this.socket.Receive( readBuffer, 4, SocketFlags.None );
|
||||||
|
|
||||||
@@ -132,18 +127,32 @@ namespace TestProtocol
|
|||||||
|
|
||||||
// Read the length
|
// Read the length
|
||||||
this.socket.Receive( readBuffer, 4, SocketFlags.None );
|
this.socket.Receive( readBuffer, 4, SocketFlags.None );
|
||||||
length = ByteWriter.ReadInt32_BE( readBuffer, 0 );
|
messageLength = ByteWriter.ReadInt32_BE( readBuffer, 0 );
|
||||||
|
|
||||||
|
if( readBuffer.Length < messageLength )
|
||||||
|
{
|
||||||
|
readBuffer = new byte[messageLength];
|
||||||
|
}
|
||||||
|
|
||||||
// Read the data
|
// Read the data
|
||||||
this.socket.Receive( readBuffer, length, SocketFlags.None );
|
// Keep in mind that Socket.Receive may return less data than asked for.
|
||||||
|
remaining = messageLength;
|
||||||
|
chunkLength = 0;
|
||||||
|
position = 0;
|
||||||
|
while( remaining > 0 )
|
||||||
|
{
|
||||||
|
chunkLength = this.socket.Receive( readBuffer, position, remaining, SocketFlags.None );
|
||||||
|
remaining -= chunkLength;
|
||||||
|
position += chunkLength;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch( SocketException e )
|
catch( SocketException e )
|
||||||
{
|
{
|
||||||
if( e.SocketErrorCode == SocketError.ConnectionAborted ||
|
if( e.SocketErrorCode == SocketError.ConnectionAborted ||
|
||||||
e.SocketErrorCode == SocketError.Interrupted ||
|
e.SocketErrorCode == SocketError.Interrupted ||
|
||||||
e.SocketErrorCode == SocketError.OperationAborted ||
|
e.SocketErrorCode == SocketError.OperationAborted ||
|
||||||
e.SocketErrorCode == SocketError.Shutdown )
|
e.SocketErrorCode == SocketError.Shutdown ||
|
||||||
|
e.SocketErrorCode == SocketError.ConnectionReset )
|
||||||
{
|
{
|
||||||
// Shutting down.
|
// Shutting down.
|
||||||
break;
|
break;
|
||||||
@@ -158,18 +167,17 @@ namespace TestProtocol
|
|||||||
|
|
||||||
if( this.Received != null )
|
if( this.Received != null )
|
||||||
{
|
{
|
||||||
byte[] dataCopy = new byte[length];
|
byte[] dataCopy = new byte[messageLength];
|
||||||
Array.Copy( readBuffer, 0, dataCopy, 0, length );
|
Array.Copy( readBuffer, 0, dataCopy, 0, messageLength );
|
||||||
Message message = new Message( operation, dataCopy );
|
Message message = new Message( operation, dataCopy );
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.Received( message );
|
this.Received( message );
|
||||||
}
|
}
|
||||||
catch( Exception e )
|
catch( Exception )
|
||||||
{ }
|
{ }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace TestProtocol
|
|
||||||
{
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using NSspi;
|
using NSspi;
|
||||||
|
|
||||||
|
namespace TestProtocol
|
||||||
|
{
|
||||||
public class CustomServer
|
public class CustomServer
|
||||||
{
|
{
|
||||||
private Thread receiveThread;
|
private Thread receiveThread;
|
||||||
@@ -149,7 +139,9 @@ namespace TestProtocol
|
|||||||
byte[] readBuffer = new byte[65536];
|
byte[] readBuffer = new byte[65536];
|
||||||
|
|
||||||
ProtocolOp operation;
|
ProtocolOp operation;
|
||||||
int length;
|
int messageLength;
|
||||||
|
int position;
|
||||||
|
int remaining;
|
||||||
|
|
||||||
while( this.running )
|
while( this.running )
|
||||||
{
|
{
|
||||||
@@ -157,7 +149,7 @@ namespace TestProtocol
|
|||||||
{
|
{
|
||||||
// |--4 bytes--|--4 bytes--|---N--|
|
// |--4 bytes--|--4 bytes--|---N--|
|
||||||
// Every command is a TLV - | Operation | Length | Data |
|
// Every command is a TLV - | Operation | Length | Data |
|
||||||
|
int chunkLength;
|
||||||
|
|
||||||
// Read the operation.
|
// Read the operation.
|
||||||
this.readSocket.Receive( readBuffer, 4, SocketFlags.None );
|
this.readSocket.Receive( readBuffer, 4, SocketFlags.None );
|
||||||
@@ -169,11 +161,24 @@ namespace TestProtocol
|
|||||||
|
|
||||||
// Read the length
|
// Read the length
|
||||||
this.readSocket.Receive( readBuffer, 4, SocketFlags.None );
|
this.readSocket.Receive( readBuffer, 4, SocketFlags.None );
|
||||||
length = ByteWriter.ReadInt32_BE( readBuffer, 0 );
|
messageLength = ByteWriter.ReadInt32_BE( readBuffer, 0 );
|
||||||
|
|
||||||
|
if( readBuffer.Length < messageLength )
|
||||||
|
{
|
||||||
|
readBuffer = new byte[messageLength];
|
||||||
|
}
|
||||||
|
|
||||||
// Read the data
|
// Read the data
|
||||||
this.readSocket.Receive( readBuffer, length, SocketFlags.None );
|
// Keep in mind that Socket.Receive may return less data than asked for.
|
||||||
|
remaining = messageLength;
|
||||||
|
chunkLength = 0;
|
||||||
|
position = 0;
|
||||||
|
while( remaining > 0 )
|
||||||
|
{
|
||||||
|
chunkLength = this.readSocket.Receive( readBuffer, position, remaining, SocketFlags.None );
|
||||||
|
remaining -= chunkLength;
|
||||||
|
position += chunkLength;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch( SocketException e )
|
catch( SocketException e )
|
||||||
{
|
{
|
||||||
@@ -196,8 +201,8 @@ namespace TestProtocol
|
|||||||
|
|
||||||
if( this.Received != null )
|
if( this.Received != null )
|
||||||
{
|
{
|
||||||
byte[] dataCopy = new byte[length];
|
byte[] dataCopy = new byte[messageLength];
|
||||||
Array.Copy( readBuffer, 0, dataCopy, 0, length );
|
Array.Copy( readBuffer, 0, dataCopy, 0, messageLength );
|
||||||
Message message = new Message( operation, dataCopy );
|
Message message = new Message( operation, dataCopy );
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -207,7 +212,6 @@ namespace TestProtocol
|
|||||||
catch( Exception )
|
catch( Exception )
|
||||||
{ }
|
{ }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -220,5 +224,4 @@ namespace TestProtocol
|
|||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace TestProtocol
|
namespace TestProtocol
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
// General Information about an assembly is controlled through the following
|
||||||
|
|||||||
4
TestProtocol/Properties/Resources.Designer.cs
generated
4
TestProtocol/Properties/Resources.Designer.cs
generated
@@ -1,7 +1,7 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// <auto-generated>
|
// <auto-generated>
|
||||||
// This code was generated by a tool.
|
// This code was generated by a tool.
|
||||||
// Runtime Version:4.0.30319.18444
|
// Runtime Version:4.0.30319.42000
|
||||||
//
|
//
|
||||||
// Changes to this file may cause incorrect behavior and will be lost if
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
// the code is regenerated.
|
// the code is regenerated.
|
||||||
@@ -19,7 +19,7 @@ namespace TestProtocol.Properties {
|
|||||||
// class via a tool like ResGen or Visual Studio.
|
// class via a tool like ResGen or Visual Studio.
|
||||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
// with the /str option, or rebuild your VS project.
|
// with the /str option, or rebuild your VS project.
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
internal class Resources {
|
internal class Resources {
|
||||||
|
|||||||
4
TestProtocol/Properties/Settings.Designer.cs
generated
4
TestProtocol/Properties/Settings.Designer.cs
generated
@@ -1,7 +1,7 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// <auto-generated>
|
// <auto-generated>
|
||||||
// This code was generated by a tool.
|
// This code was generated by a tool.
|
||||||
// Runtime Version:4.0.30319.18444
|
// Runtime Version:4.0.30319.42000
|
||||||
//
|
//
|
||||||
// Changes to this file may cause incorrect behavior and will be lost if
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
// the code is regenerated.
|
// the code is regenerated.
|
||||||
@@ -12,7 +12,7 @@ namespace TestProtocol.Properties {
|
|||||||
|
|
||||||
|
|
||||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.7.0.0")]
|
||||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||||
|
|
||||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace TestProtocol
|
namespace TestProtocol
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
<RootNamespace>TestProtocol</RootNamespace>
|
<RootNamespace>TestProtocol</RootNamespace>
|
||||||
<AssemblyName>TestProtocol</AssemblyName>
|
<AssemblyName>TestProtocol</AssemblyName>
|
||||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||||
<FileAlignment>512</FileAlignment>
|
<FileAlignment>512</FileAlignment>
|
||||||
<TargetFrameworkProfile />
|
<TargetFrameworkProfile />
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
@@ -31,6 +32,7 @@
|
|||||||
<DefineConstants>TRACE</DefineConstants>
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<StartupObject />
|
<StartupObject />
|
||||||
|
|||||||
2
TestServer/.gitignore
vendored
Normal file
2
TestServer/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
bin
|
||||||
|
obj
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<startup>
|
<startup>
|
||||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
|
||||||
</startup>
|
</startup>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|||||||
@@ -1,18 +1,15 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace TestServer
|
namespace TestServer
|
||||||
{
|
{
|
||||||
static class Program
|
internal static class Program
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The main entry point for the application.
|
/// The main entry point for the application.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[STAThread]
|
[STAThread]
|
||||||
static void Main()
|
private static void Main()
|
||||||
{
|
{
|
||||||
Application.EnableVisualStyles();
|
Application.EnableVisualStyles();
|
||||||
Application.SetCompatibleTextRenderingDefault( false );
|
Application.SetCompatibleTextRenderingDefault( false );
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
// General Information about an assembly is controlled through the following
|
||||||
|
|||||||
4
TestServer/Properties/Resources.Designer.cs
generated
4
TestServer/Properties/Resources.Designer.cs
generated
@@ -1,7 +1,7 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// <auto-generated>
|
// <auto-generated>
|
||||||
// This code was generated by a tool.
|
// This code was generated by a tool.
|
||||||
// Runtime Version:4.0.30319.18444
|
// Runtime Version:4.0.30319.42000
|
||||||
//
|
//
|
||||||
// Changes to this file may cause incorrect behavior and will be lost if
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
// the code is regenerated.
|
// the code is regenerated.
|
||||||
@@ -19,7 +19,7 @@ namespace TestServer.Properties {
|
|||||||
// class via a tool like ResGen or Visual Studio.
|
// class via a tool like ResGen or Visual Studio.
|
||||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
// with the /str option, or rebuild your VS project.
|
// with the /str option, or rebuild your VS project.
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
internal class Resources {
|
internal class Resources {
|
||||||
|
|||||||
4
TestServer/Properties/Settings.Designer.cs
generated
4
TestServer/Properties/Settings.Designer.cs
generated
@@ -1,7 +1,7 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// <auto-generated>
|
// <auto-generated>
|
||||||
// This code was generated by a tool.
|
// This code was generated by a tool.
|
||||||
// Runtime Version:4.0.30319.18444
|
// Runtime Version:4.0.30319.42000
|
||||||
//
|
//
|
||||||
// Changes to this file may cause incorrect behavior and will be lost if
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
// the code is regenerated.
|
// the code is regenerated.
|
||||||
@@ -12,7 +12,7 @@ namespace TestServer.Properties {
|
|||||||
|
|
||||||
|
|
||||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.7.0.0")]
|
||||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||||
|
|
||||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||||
|
|||||||
23
TestServer/ServerForm.Designer.cs
generated
23
TestServer/ServerForm.Designer.cs
generated
@@ -38,13 +38,13 @@
|
|||||||
this.label2 = new System.Windows.Forms.Label();
|
this.label2 = new System.Windows.Forms.Label();
|
||||||
this.serverUsernameTextbox = new System.Windows.Forms.TextBox();
|
this.serverUsernameTextbox = new System.Windows.Forms.TextBox();
|
||||||
this.groupBox2 = new System.Windows.Forms.GroupBox();
|
this.groupBox2 = new System.Windows.Forms.GroupBox();
|
||||||
|
this.impersonateButton = new System.Windows.Forms.Button();
|
||||||
this.signButton = new System.Windows.Forms.Button();
|
this.signButton = new System.Windows.Forms.Button();
|
||||||
this.encryptButton = new System.Windows.Forms.Button();
|
this.encryptButton = new System.Windows.Forms.Button();
|
||||||
this.sendTextbox = new System.Windows.Forms.TextBox();
|
this.sendTextbox = new System.Windows.Forms.TextBox();
|
||||||
this.groupBox3 = new System.Windows.Forms.GroupBox();
|
this.groupBox3 = new System.Windows.Forms.GroupBox();
|
||||||
this.receivedTextbox = new System.Windows.Forms.TextBox();
|
this.receivedTextbox = new System.Windows.Forms.TextBox();
|
||||||
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
|
||||||
this.impersonateButton = new System.Windows.Forms.Button();
|
|
||||||
((System.ComponentModel.ISupportInitialize)(this.portNumeric)).BeginInit();
|
((System.ComponentModel.ISupportInitialize)(this.portNumeric)).BeginInit();
|
||||||
this.groupBox1.SuspendLayout();
|
this.groupBox1.SuspendLayout();
|
||||||
this.groupBox2.SuspendLayout();
|
this.groupBox2.SuspendLayout();
|
||||||
@@ -168,6 +168,16 @@
|
|||||||
this.groupBox2.TabStop = false;
|
this.groupBox2.TabStop = false;
|
||||||
this.groupBox2.Text = "Send a message to the client";
|
this.groupBox2.Text = "Send a message to the client";
|
||||||
//
|
//
|
||||||
|
// impersonateButton
|
||||||
|
//
|
||||||
|
this.impersonateButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
|
this.impersonateButton.Location = new System.Drawing.Point(262, 356);
|
||||||
|
this.impersonateButton.Name = "impersonateButton";
|
||||||
|
this.impersonateButton.Size = new System.Drawing.Size(116, 23);
|
||||||
|
this.impersonateButton.TabIndex = 4;
|
||||||
|
this.impersonateButton.Text = "Test impersonation";
|
||||||
|
this.impersonateButton.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
// signButton
|
// signButton
|
||||||
//
|
//
|
||||||
this.signButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
this.signButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
@@ -196,6 +206,7 @@
|
|||||||
this.sendTextbox.Location = new System.Drawing.Point(6, 19);
|
this.sendTextbox.Location = new System.Drawing.Point(6, 19);
|
||||||
this.sendTextbox.Multiline = true;
|
this.sendTextbox.Multiline = true;
|
||||||
this.sendTextbox.Name = "sendTextbox";
|
this.sendTextbox.Name = "sendTextbox";
|
||||||
|
this.sendTextbox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
|
||||||
this.sendTextbox.Size = new System.Drawing.Size(400, 323);
|
this.sendTextbox.Size = new System.Drawing.Size(400, 323);
|
||||||
this.sendTextbox.TabIndex = 0;
|
this.sendTextbox.TabIndex = 0;
|
||||||
//
|
//
|
||||||
@@ -216,6 +227,7 @@
|
|||||||
this.receivedTextbox.Location = new System.Drawing.Point(3, 16);
|
this.receivedTextbox.Location = new System.Drawing.Point(3, 16);
|
||||||
this.receivedTextbox.Multiline = true;
|
this.receivedTextbox.Multiline = true;
|
||||||
this.receivedTextbox.Name = "receivedTextbox";
|
this.receivedTextbox.Name = "receivedTextbox";
|
||||||
|
this.receivedTextbox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
|
||||||
this.receivedTextbox.Size = new System.Drawing.Size(407, 370);
|
this.receivedTextbox.Size = new System.Drawing.Size(407, 370);
|
||||||
this.receivedTextbox.TabIndex = 0;
|
this.receivedTextbox.TabIndex = 0;
|
||||||
//
|
//
|
||||||
@@ -236,15 +248,6 @@
|
|||||||
this.tableLayoutPanel1.Size = new System.Drawing.Size(838, 395);
|
this.tableLayoutPanel1.Size = new System.Drawing.Size(838, 395);
|
||||||
this.tableLayoutPanel1.TabIndex = 7;
|
this.tableLayoutPanel1.TabIndex = 7;
|
||||||
//
|
//
|
||||||
// impersonateButton
|
|
||||||
//
|
|
||||||
this.impersonateButton.Location = new System.Drawing.Point(262, 350);
|
|
||||||
this.impersonateButton.Name = "impersonateButton";
|
|
||||||
this.impersonateButton.Size = new System.Drawing.Size(116, 23);
|
|
||||||
this.impersonateButton.TabIndex = 4;
|
|
||||||
this.impersonateButton.Text = "Test impersonation";
|
|
||||||
this.impersonateButton.UseVisualStyleBackColor = true;
|
|
||||||
//
|
|
||||||
// ServerForm
|
// ServerForm
|
||||||
//
|
//
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||||
|
|||||||
@@ -1,25 +1,21 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.IO;
|
||||||
using System.ComponentModel;
|
using System.Security.Principal;
|
||||||
using System.Data;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using NSspi;
|
||||||
|
using NSspi.Contexts;
|
||||||
|
using NSspi.Credentials;
|
||||||
using TestProtocol;
|
using TestProtocol;
|
||||||
|
|
||||||
namespace TestServer
|
namespace TestServer
|
||||||
{
|
{
|
||||||
using System.IO;
|
|
||||||
using NSspi;
|
|
||||||
using NSspi.Contexts;
|
|
||||||
using NSspi.Credentials;
|
|
||||||
using Message = TestProtocol.Message;
|
using Message = TestProtocol.Message;
|
||||||
|
|
||||||
public partial class ServerForm : Form
|
public partial class ServerForm : Form
|
||||||
{
|
{
|
||||||
private ServerCredential serverCred;
|
private ServerCurrentCredential serverCred;
|
||||||
|
|
||||||
private ServerContext serverContext;
|
private ServerContext serverContext;
|
||||||
|
|
||||||
@@ -35,7 +31,7 @@ namespace TestServer
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.serverCred = new ServerCredential( PackageNames.Negotiate );
|
this.serverCred = new ServerCurrentCredential( PackageNames.Negotiate );
|
||||||
|
|
||||||
this.serverContext = new ServerContext(
|
this.serverContext = new ServerContext(
|
||||||
serverCred,
|
serverCred,
|
||||||
@@ -44,7 +40,8 @@ namespace TestServer
|
|||||||
ContextAttrib.SequenceDetect |
|
ContextAttrib.SequenceDetect |
|
||||||
ContextAttrib.MutualAuth |
|
ContextAttrib.MutualAuth |
|
||||||
ContextAttrib.Delegate |
|
ContextAttrib.Delegate |
|
||||||
ContextAttrib.Confidentiality
|
ContextAttrib.Confidentiality,
|
||||||
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
this.server = new CustomServer();
|
this.server = new CustomServer();
|
||||||
@@ -129,7 +126,11 @@ namespace TestServer
|
|||||||
{
|
{
|
||||||
MessageBox.Show( "Starting impersonation: " + Environment.UserName );
|
MessageBox.Show( "Starting impersonation: " + Environment.UserName );
|
||||||
|
|
||||||
FileStream stream = File.Create( Environment.GetFolderPath( Environment.SpecialFolder.DesktopDirectory) + @"\test.txt" );
|
var directory = Environment.GetFolderPath( Environment.SpecialFolder.DesktopDirectory );
|
||||||
|
|
||||||
|
Directory.CreateDirectory( directory );
|
||||||
|
|
||||||
|
FileStream stream = File.Create( directory + @"\test.txt" );
|
||||||
StreamWriter writer = new StreamWriter( stream, Encoding.UTF8 );
|
StreamWriter writer = new StreamWriter( stream, Encoding.UTF8 );
|
||||||
|
|
||||||
writer.WriteLine( "Hello world." );
|
writer.WriteLine( "Hello world." );
|
||||||
@@ -150,7 +151,6 @@ namespace TestServer
|
|||||||
this.signButton.Enabled = this.connected;
|
this.signButton.Enabled = this.connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void server_Received( Message message )
|
private void server_Received( Message message )
|
||||||
{
|
{
|
||||||
if( message.Operation == ProtocolOp.ClientToken )
|
if( message.Operation == ProtocolOp.ClientToken )
|
||||||
@@ -171,13 +171,38 @@ namespace TestServer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void InitComplete()
|
||||||
|
{
|
||||||
|
UpdateButtons();
|
||||||
|
this.clientUsernameTextBox.Text = serverContext.ContextUserName;
|
||||||
|
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
var remoteId = this.serverContext.GetRemoteIdentity();
|
||||||
|
|
||||||
|
builder.AppendLine( "Client identity information:" );
|
||||||
|
builder.AppendLine( " - Name: " + remoteId.Name );
|
||||||
|
|
||||||
|
var windowsId = remoteId as WindowsIdentity;
|
||||||
|
|
||||||
|
if( windowsId != null )
|
||||||
|
{
|
||||||
|
builder.AppendLine( " - User SID: " + windowsId.User.Value );
|
||||||
|
|
||||||
|
foreach( var claim in windowsId.Claims )
|
||||||
|
{
|
||||||
|
builder.AppendLine( " - " + claim.ToString() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.receivedTextbox.AppendText( builder.ToString() );
|
||||||
|
}
|
||||||
|
|
||||||
private void server_Disconnected()
|
private void server_Disconnected()
|
||||||
{
|
{
|
||||||
this.running = false;
|
this.running = true;
|
||||||
this.initializing = true;
|
this.initializing = true;
|
||||||
this.connected = false;
|
this.connected = false;
|
||||||
|
|
||||||
|
|
||||||
this.serverContext.Dispose();
|
this.serverContext.Dispose();
|
||||||
this.serverContext = new ServerContext(
|
this.serverContext = new ServerContext(
|
||||||
serverCred,
|
serverCred,
|
||||||
@@ -196,7 +221,6 @@ namespace TestServer
|
|||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void HandleInit( Message message )
|
private void HandleInit( Message message )
|
||||||
{
|
{
|
||||||
byte[] nextToken;
|
byte[] nextToken;
|
||||||
@@ -218,11 +242,7 @@ namespace TestServer
|
|||||||
this.initializing = false;
|
this.initializing = false;
|
||||||
this.connected = true;
|
this.connected = true;
|
||||||
|
|
||||||
this.Invoke( (Action)delegate()
|
this.Invoke( (Action)InitComplete );
|
||||||
{
|
|
||||||
UpdateButtons();
|
|
||||||
this.clientUsernameTextBox.Text = serverContext.ContextUserName;
|
|
||||||
} );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -232,7 +252,6 @@ namespace TestServer
|
|||||||
MessageBox.Show( "Failed to accept token from client. Sspi error code: " + status );
|
MessageBox.Show( "Failed to accept token from client. Sspi error code: " + status );
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,6 +292,5 @@ namespace TestServer
|
|||||||
MessageBox.Show( "Received unexpected message from server. Message type: " + message.Operation );
|
MessageBox.Show( "Received unexpected message from server. Message type: " + message.Operation );
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
<RootNamespace>TestServer</RootNamespace>
|
<RootNamespace>TestServer</RootNamespace>
|
||||||
<AssemblyName>TestServer</AssemblyName>
|
<AssemblyName>TestServer</AssemblyName>
|
||||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||||
<FileAlignment>512</FileAlignment>
|
<FileAlignment>512</FileAlignment>
|
||||||
<TargetFrameworkProfile />
|
<TargetFrameworkProfile />
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
@@ -31,6 +32,7 @@
|
|||||||
<DefineConstants>TRACE</DefineConstants>
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
|
|||||||
59
readme.md
Normal file
59
readme.md
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
## Downloads ##
|
||||||
|
|
||||||
|
The latest release of NSspi is v0.3.1, released 5-Aug-2019.
|
||||||
|
|
||||||
|
Version 0.3.1 adds support to obtain an IIdentity/WindowsPrinciple representing the remote connection. This is useful for servers that wish to query the properties on the principle, such as claims.
|
||||||
|
|
||||||
|
* [Source](https://github.com/antiduh/nsspi/archive/0.3.1.zip)
|
||||||
|
* [Nuget package](https://www.nuget.org/packages/NSspi)
|
||||||
|
|
||||||
|
You can also browse the list of [releases](https://github.com/antiduh/nsspi/releases).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Introduction ##
|
||||||
|
This project provides a C# / .Net interface to the Windows Integrated Authentication API, better known as SSPI (Security Service Provider Interface). This allows a custom client / server system to authenticate users using their existing logon credentials. This allows a developer to provide Single-Sign-On in their application.
|
||||||
|
|
||||||
|
## Overview ##
|
||||||
|
The API provides raw access to authentication tokens so that authentication can be easily integrated into any networking system - you can send the tokens over a socket, a remoting interface, or heck even a serial port if you want; they're just bytes. Clients and servers may exchange encrypted and signed messages, and the server can perform client impersonation.
|
||||||
|
|
||||||
|
The project is provided as a .Net 4.0 assembly, but can just as easily be upgraded to .Net 4.5 or later. The solution file can be opened by Visual Studio 2010 SP1, Visual Studio 2012, or later Visual Studio editions.
|
||||||
|
|
||||||
|
The SSPI API provides an interface for real authentication protocols, such as Kerberos or NTLM, to be invoked transparently by client and server code in order to perform authentication and message manipulation. These authentication protocols are better known as 'security packages'.
|
||||||
|
|
||||||
|
The SSPI API exposes these packages using a common API, and so a program may invoke one or the other with only minor changes in implementation. SSPI also supports the 'negotiate' 'meta' package, that allows a client and server to decide dynamically which real security provider to use, and then itself provides a passthrough interface to the real package.
|
||||||
|
|
||||||
|
## Usage ##
|
||||||
|
|
||||||
|
Typically, a client acquires some form of a credential, either from the currently logged on user's security context, by acquiring a username and password from the user, or by some other means. The server acquires a credential in a similar manner. Each uses their credentials to identify themselves to each other.
|
||||||
|
|
||||||
|
A client and a server each start with uninitialized security contexts. They exchange negotiation and authentication tokens to perform authentication, and if all succeeds, they create a shared security context in the form of a client's context and a server's context. The effectively shared context agrees on the security package to use (kerberos, NTLM), and what parameters to use for message passing. Every new client that authenticates with a server creates a new security context specific to that client-server pairing.
|
||||||
|
|
||||||
|
From the software perspective, a client security context initializes itself by exchanging authentication tokens with a server; the server initializes itself by exchanging authentication tokens with the client.
|
||||||
|
|
||||||
|
This API provides raw access to the authentication tokens created during the negotiation and authentication process. In this manner, any application can integrate SSPI-based authentication by deciding for themselves how to integrate the tokens into their application protocol.
|
||||||
|
|
||||||
|
The project is broken up into 3 chunks:
|
||||||
|
|
||||||
|
* The NSspi library, which provides safe, managed access to the SSPI API.
|
||||||
|
* NsspiDemo, a quick demo program to show how to exercise the features of NSspi locally.
|
||||||
|
* UI demo programs TestClient and TestServer (that have a common dependency on TestProtocol) that
|
||||||
|
may be run on separate machines, that show how one might integrate SSPI into a custom
|
||||||
|
application.
|
||||||
|
|
||||||
|
## More information ##
|
||||||
|
|
||||||
|
If you would like to understand the SSPI API, feel free to browse the following references:
|
||||||
|
|
||||||
|
MSDN documentation on the SSPI API:<br/>
|
||||||
|
[http://msdn.microsoft.com/en-us/library/windows/desktop/aa374731(v=vs.85).aspx](http://msdn.microsoft.com/en-us/library/windows/desktop/aa374731\(v=vs.85\).aspx)
|
||||||
|
|
||||||
|
MSDN article on SSPI along with a sample Managed C++ SSPI library and UI client/servers.<br/>
|
||||||
|
[http://msdn.microsoft.com/en-us/library/ms973911.aspx](http://msdn.microsoft.com/en-us/library/ms973911.aspx)
|
||||||
|
|
||||||
|
Relevant StackOverflow questions:
|
||||||
|
|
||||||
|
* [Client-server authentication - using SSPI?](http://stackoverflow.com/questions/17241365/)
|
||||||
|
* [Validate Windows Identity Token](http://stackoverflow.com/questions/11238141/)
|
||||||
|
* [How to deal with allocations in constrained execution regions?](http://stackoverflow.com/questions/24442209/)
|
||||||
|
* [AcquireCredentialsHandle returns massive expiration time](http://stackoverflow.com/questions/24478056/)
|
||||||
Reference in New Issue
Block a user