Skip to content

Commit a3b4c11

Browse files
authored
Merge pull request #18 from IvanoG/windowsA
Powershell - REST-API with Integrated Windows Authentication
2 parents 51bd719 + db27d30 commit a3b4c11

File tree

2 files changed

+399
-0
lines changed

2 files changed

+399
-0
lines changed
Lines changed: 381 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,381 @@
1+
Param([parameter(Mandatory=$true,
2+
HelpMessage="Enter server url [ -server <server url> ]")]
3+
$serverUrl
4+
)
5+
if(!$serverUrl){
6+
return "Enter server url [ -server <server url> ]"
7+
}
8+
function GetBigFixToken {
9+
[CmdletBinding()]
10+
param($PN)
11+
$Signature = @"
12+
13+
public enum SecBufferType
14+
{
15+
SECBUFFER_VERSION = 0,
16+
SECBUFFER_EMPTY = 0,
17+
SECBUFFER_DATA = 1,
18+
SECBUFFER_TOKEN = 2
19+
}
20+
21+
[StructLayout(LayoutKind.Sequential)]
22+
public struct SECURITY_INTEGER
23+
{
24+
public uint LowPart;
25+
public int HighPart;
26+
public SECURITY_INTEGER(int dummy)
27+
{
28+
LowPart = 0;
29+
HighPart = 0;
30+
}
31+
};
32+
33+
[StructLayout(LayoutKind.Sequential)]
34+
public struct SecBuffer : IDisposable
35+
{
36+
public int cbBuffer;
37+
public int BufferType;
38+
public IntPtr pvBuffer;
39+
40+
41+
public SecBuffer(int bufferSize)
42+
{
43+
cbBuffer = bufferSize;
44+
BufferType = (int)SecBufferType.SECBUFFER_TOKEN;
45+
pvBuffer = Marshal.AllocHGlobal(bufferSize);
46+
}
47+
48+
public SecBuffer(byte[] secBufferBytes)
49+
{
50+
cbBuffer = secBufferBytes.Length;
51+
BufferType = (int)SecBufferType.SECBUFFER_TOKEN;
52+
pvBuffer = Marshal.AllocHGlobal(cbBuffer);
53+
Marshal.Copy(secBufferBytes,0,pvBuffer,cbBuffer);
54+
}
55+
56+
public SecBuffer(byte[] secBufferBytes,SecBufferType bufferType)
57+
{
58+
cbBuffer = secBufferBytes.Length;
59+
BufferType = (int)bufferType;
60+
pvBuffer = Marshal.AllocHGlobal(cbBuffer);
61+
Marshal.Copy(secBufferBytes,0,pvBuffer,cbBuffer);
62+
}
63+
64+
public void Dispose()
65+
{
66+
if(pvBuffer != IntPtr.Zero)
67+
{
68+
Marshal.FreeHGlobal(pvBuffer);
69+
pvBuffer = IntPtr.Zero;
70+
}
71+
}
72+
}
73+
74+
public struct MultipleSecBufferHelper
75+
{
76+
public byte[] Buffer;
77+
public SecBufferType BufferType;
78+
79+
public MultipleSecBufferHelper(byte[] buffer,SecBufferType bufferType)
80+
{
81+
if(buffer == null || buffer.Length == 0)
82+
{
83+
throw new ArgumentException("buffer cannot be null or 0 length");
84+
}
85+
86+
Buffer = buffer;
87+
BufferType = bufferType;
88+
}
89+
};
90+
91+
[StructLayout(LayoutKind.Sequential)]
92+
public struct SecBufferDesc : IDisposable
93+
{
94+
95+
public int ulVersion;
96+
public int cBuffers;
97+
public IntPtr pBuffers; //Point to SecBuffer
98+
99+
public SecBufferDesc(int bufferSize)
100+
{
101+
ulVersion = (int)SecBufferType.SECBUFFER_VERSION;
102+
cBuffers = 1;
103+
SecBuffer ThisSecBuffer = new SecBuffer(bufferSize);
104+
pBuffers = Marshal.AllocHGlobal(Marshal.SizeOf(ThisSecBuffer));
105+
Marshal.StructureToPtr(ThisSecBuffer,pBuffers,false);
106+
}
107+
108+
public SecBufferDesc(byte[] secBufferBytes)
109+
{
110+
ulVersion = (int)SecBufferType.SECBUFFER_VERSION;
111+
cBuffers = 1;
112+
SecBuffer ThisSecBuffer = new SecBuffer(secBufferBytes);
113+
pBuffers = Marshal.AllocHGlobal(Marshal.SizeOf(ThisSecBuffer));
114+
Marshal.StructureToPtr(ThisSecBuffer,pBuffers,false);
115+
}
116+
117+
public SecBufferDesc(MultipleSecBufferHelper[] secBufferBytesArray)
118+
{
119+
if(secBufferBytesArray == null || secBufferBytesArray.Length == 0)
120+
{
121+
throw new ArgumentException("secBufferBytesArray cannot be null or 0 length");
122+
}
123+
124+
ulVersion = (int)SecBufferType.SECBUFFER_VERSION;
125+
cBuffers = secBufferBytesArray.Length;
126+
127+
pBuffers = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SecBuffer)) * cBuffers);
128+
129+
for(int Index = 0;Index < secBufferBytesArray.Length;Index++)
130+
{
131+
SecBuffer ThisSecBuffer = new SecBuffer(secBufferBytesArray[Index].Buffer,secBufferBytesArray[Index].BufferType);
132+
133+
int CurrentOffset = Index*Marshal.SizeOf(typeof(SecBuffer));
134+
Marshal.WriteInt32(pBuffers,CurrentOffset,ThisSecBuffer.cbBuffer);
135+
Marshal.WriteInt32(pBuffers,CurrentOffset + Marshal.SizeOf(ThisSecBuffer.cbBuffer),ThisSecBuffer.BufferType);
136+
Marshal.WriteIntPtr(pBuffers,CurrentOffset + Marshal.SizeOf(ThisSecBuffer.cbBuffer)+Marshal.SizeOf(ThisSecBuffer.BufferType),ThisSecBuffer.pvBuffer);
137+
}
138+
}
139+
140+
public void Dispose()
141+
{
142+
if(pBuffers != IntPtr.Zero)
143+
{
144+
if(cBuffers == 1)
145+
{
146+
SecBuffer ThisSecBuffer = (SecBuffer)Marshal.PtrToStructure(pBuffers,typeof(SecBuffer));
147+
ThisSecBuffer.Dispose();
148+
}
149+
else
150+
{
151+
for(int Index = 0;Index < cBuffers;Index++)
152+
{
153+
int CurrentOffset = Index*Marshal.SizeOf(typeof(SecBuffer));
154+
IntPtr SecBufferpvBuffer = Marshal.ReadIntPtr(pBuffers,CurrentOffset + Marshal.SizeOf(typeof(int))+Marshal.SizeOf(typeof(int)));
155+
Marshal.FreeHGlobal(SecBufferpvBuffer);
156+
}
157+
}
158+
159+
Marshal.FreeHGlobal(pBuffers);
160+
pBuffers = IntPtr.Zero;
161+
}
162+
}
163+
164+
public byte[] GetSecBufferByteArray()
165+
{
166+
byte[] Buffer = null;
167+
168+
if(pBuffers == IntPtr.Zero)
169+
{
170+
throw new InvalidOperationException("Object has already been disposed!!!");
171+
}
172+
173+
if(cBuffers == 1)
174+
{
175+
SecBuffer ThisSecBuffer = (SecBuffer)Marshal.PtrToStructure(pBuffers,typeof(SecBuffer));
176+
177+
if(ThisSecBuffer.cbBuffer > 0)
178+
{
179+
Buffer = new byte[ThisSecBuffer.cbBuffer];
180+
Marshal.Copy(ThisSecBuffer.pvBuffer,Buffer,0,ThisSecBuffer.cbBuffer);
181+
}
182+
}
183+
else
184+
{
185+
int BytesToAllocate = 0;
186+
187+
for(int Index = 0;Index < cBuffers;Index++)
188+
{
189+
int CurrentOffset = Index*Marshal.SizeOf(typeof(SecBuffer));
190+
BytesToAllocate += Marshal.ReadInt32(pBuffers,CurrentOffset);
191+
}
192+
193+
Buffer = new byte[BytesToAllocate];
194+
195+
for(int Index = 0,BufferIndex = 0;Index < cBuffers;Index++)
196+
{
197+
int CurrentOffset = Index*Marshal.SizeOf(typeof(SecBuffer));
198+
int BytesToCopy = Marshal.ReadInt32(pBuffers,CurrentOffset);
199+
IntPtr SecBufferpvBuffer = Marshal.ReadIntPtr(pBuffers,CurrentOffset + Marshal.SizeOf(typeof(int))+Marshal.SizeOf(typeof(int)));
200+
Marshal.Copy(SecBufferpvBuffer,Buffer,BufferIndex,BytesToCopy);
201+
BufferIndex += BytesToCopy;
202+
}
203+
}
204+
205+
return(Buffer);
206+
}
207+
208+
public SecBuffer GetSecBuffer()
209+
{
210+
if(pBuffers == IntPtr.Zero)
211+
{
212+
throw new InvalidOperationException("Object has already been disposed!!!");
213+
}
214+
215+
return((SecBuffer)Marshal.PtrToStructure(pBuffers,typeof(SecBuffer)));
216+
}
217+
}
218+
219+
[StructLayout(LayoutKind.Sequential)]
220+
public struct SECURITY_HANDLE
221+
{
222+
public uint LowPart;
223+
public uint HighPart;
224+
public SECURITY_HANDLE(int dummy)
225+
{
226+
LowPart = HighPart = 0;
227+
}
228+
};
229+
230+
231+
[DllImport("secur32.dll", SetLastError=true)]
232+
static extern int AcquireCredentialsHandle(
233+
string pszPrincipal, //SEC_CHAR*
234+
string pszPackage, //SEC_CHAR* //"Kerberos","NTLM","Negotiative"
235+
int fCredentialUse,
236+
IntPtr PAuthenticationID,//_LUID AuthenticationID,//pvLogonID, //PLUID
237+
IntPtr pAuthData,//PVOID
238+
int pGetKeyFn, //SEC_GET_KEY_FN
239+
IntPtr pvGetKeyArgument, //PVOID
240+
ref SECURITY_HANDLE phCredential, //SecHandle //PCtxtHandle ref
241+
ref SECURITY_INTEGER ptsExpiry //PTimeStamp //TimeStamp ref
242+
);
243+
244+
[DllImport("secur32.dll", SetLastError=true)]
245+
static extern int InitializeSecurityContext(
246+
ref SECURITY_HANDLE phCredential,//PCredHandle
247+
IntPtr phContext, //PCtxtHandle
248+
string pszTargetName,
249+
int fContextReq,
250+
int Reserved1,
251+
int TargetDataRep,
252+
IntPtr pInput, //PSecBufferDesc SecBufferDesc
253+
int Reserved2,
254+
out SECURITY_HANDLE phNewContext, //PCtxtHandle
255+
out SecBufferDesc pOutput, //PSecBufferDesc SecBufferDesc
256+
out uint pfContextAttr, //managed ulong == 64 bits!!!
257+
out SECURITY_INTEGER ptsExpiry //PTimeStamp
258+
);
259+
260+
public static SECURITY_HANDLE phCredential;
261+
public static SECURITY_INTEGER ptsExpiry;
262+
263+
public const int ISC_REQ_DELEGATE = 0x00000001;
264+
public const int ISC_REQ_MUTUAL_AUTH = 0x00000002;
265+
public const int ISC_REQ_CONFIDENTIALITY = 0x00000010;
266+
public const int ISC_REQ_ALLOCATE_MEMORY = 0x00000100;
267+
public const int ISC_REQ_CONNECTION = 0x00000800;
268+
public const int ISC_REQ_INTEGRITY = 0x00010000;
269+
270+
271+
public const int STANDARD_CONTEXT_ATTRIBUTES = ISC_REQ_CONNECTION | ISC_REQ_MUTUAL_AUTH | ISC_REQ_DELEGATE | ISC_REQ_CONFIDENTIALITY | ISC_REQ_INTEGRITY | ISC_REQ_ALLOCATE_MEMORY ;
272+
public const int SECURITY_NETWORK_DREP = 0x00000000;
273+
274+
public const int SEC_E_OK = 0;
275+
public const int SECPKG_CRED_BOTH = 3;
276+
277+
const int MAX_TOKEN_SIZE = 12288;
278+
279+
public static SecBufferDesc ClientToken = new SecBufferDesc(MAX_TOKEN_SIZE);
280+
public static uint ContextAttributes = 0;
281+
public static SECURITY_HANDLE _hClientContext = new SECURITY_HANDLE(0);
282+
public static SECURITY_INTEGER ptsexp;
283+
284+
285+
public static int GetPrincipalName() {
286+
return AcquireCredentialsHandle(
287+
"",
288+
"Kerberos",
289+
SECPKG_CRED_BOTH,
290+
IntPtr.Zero,
291+
IntPtr.Zero,
292+
0,
293+
IntPtr.Zero,
294+
ref phCredential,
295+
ref ptsExpiry);
296+
}
297+
298+
public static string GetToken(string pn) {
299+
if( GetPrincipalName() != SEC_E_OK ) {
300+
throw new Exception("Unable to get PrincipleName");
301+
}
302+
303+
InitializeSecurityContext(
304+
ref phCredential,
305+
IntPtr.Zero,
306+
pn,
307+
STANDARD_CONTEXT_ATTRIBUTES,
308+
0,
309+
SECURITY_NETWORK_DREP,
310+
IntPtr.Zero,
311+
0,
312+
out _hClientContext,
313+
out ClientToken,
314+
out ContextAttributes,
315+
out ptsexp
316+
);
317+
318+
byte[] token_a = ClientToken.GetSecBufferByteArray();
319+
320+
return "Kerberos " + Convert.ToBase64String(token_a);
321+
}
322+
"@
323+
324+
Add-Type -MemberDefinition $Signature -Name WindowsAuthentication -Namespace Secure32
325+
[Secure32.WindowsAuthentication]::GetToken($PN)
326+
}
327+
328+
#if the server certificate is self signed we need set Powershell to skip SSL certificate checks
329+
add-type @"
330+
using System.Net;
331+
using System.Security.Cryptography.X509Certificates;
332+
public class TrustAllCertsPolicy : ICertificatePolicy {
333+
public bool CheckValidationResult(
334+
ServicePoint srvPoint, X509Certificate certificate,
335+
WebRequest request, int certificateProblem) {
336+
return true;
337+
}
338+
}
339+
"@
340+
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
341+
342+
343+
344+
345+
$PrincipleName = "";
346+
347+
#The first request is needed to retrieve the principle name. It can be skipped if you already know it.
348+
try
349+
{
350+
Invoke-WebRequest -Uri ('https://'+$serverUrl+':52311/api/login') -Headers @{'PrincipalName' = ''}
351+
}
352+
catch [System.Net.WebException]
353+
{
354+
if($_.Exception.Response.StatusCode.value__ -and $_.Exception.Response.StatusCode.value__ -eq 401){
355+
356+
$PrincipleName = $_.Exception.Response.Headers['PrincipalName']
357+
#The returned token from GetBigFixToken is already in the requested form "Kerberos <token value>"
358+
$token = GetBigFixToken $PrincipleName
359+
360+
#You can ask for a session token using the login api or you can ask directly other information
361+
# example: Invoke-WebRequest -Uri 'http://localhost:52311/api/sites' -Headers @{'Authorization' = $token}
362+
$response = Invoke-WebRequest -Uri ('https://'+$serverUrl+':52311/api/login') -Headers @{'Authorization' = $token}
363+
364+
if( $response.StatusCode -eq 200){
365+
Write-Output "Login successful. Session Token received."
366+
#We should now keep the session token returned and use it in the next requests
367+
#Write-Output ("{0} {1}" -f 'SessionToken: ', $response.Headers["SessionToken"])
368+
#Invoke-WebRequest -Uri ('https://'+$serverUrl+':52311/api/sites') -Headers @{'SessionToken' = $response.Headers["SessionToken"]} -OutFile ./result.xml
369+
370+
}
371+
else {
372+
Write-Output ("Unable to complete login.")
373+
}
374+
}
375+
else{
376+
Write-Output ("Something went wrong contacting the BigFix Server $serverUrl.")
377+
}
378+
}
379+
380+
381+

0 commit comments

Comments
 (0)