LiveIdentity 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ecd029a77435438d0ac1dc51726532316a09891c
4
- data.tar.gz: f305c2c6fa46c66ba3bc7e26042a3d986d344a71
3
+ metadata.gz: 06a790b64a525efc4d3fe7bcb41d778570450749
4
+ data.tar.gz: fd6c4ce77fe2157ce34e6826ff7005b78dc42ebb
5
5
  SHA512:
6
- metadata.gz: 71890b9398e59af0b8ab21555a0c1b6f927509a14aaf6c0f7441a0e15ce4ab56440c93789d9b71d575c1f3dfd14b08d7a770c8e26ce1538d75b19e3e9ff0ff1e
7
- data.tar.gz: a47a8e61a5801d5c2ad84c7ccff47c67790f647e6a319d7274736501200e2be2fcba7ebd77e4c6ee731a7d69ded9148424f395a3e8c36066c45716c96e994905
6
+ metadata.gz: 5f77cb827bf85c0971c392dd7654821af43985468c5c53a4f21fa19b41b7bec74aa6389b1d0f0698e53e320fd40c9e35b1e5cdd2a6114e8d92c13682a29e9657
7
+ data.tar.gz: 9a03403518f82876987e2b67816db3cfb84027b79e11af3049e639a1dbe59aef4646241e0b01480272c485887b2513b6f768acc806dda7ca18175c38ce55d726
@@ -1,26 +1,10 @@
1
1
  require 'win_common'
2
+ require 'timeout'
3
+ require 'nokogiri'
2
4
 
3
5
  require_relative 'live_identity/version'
4
6
  require_relative 'live_identity/idcrl'
5
7
 
6
- def getStringLength(data)
7
- length = 0
8
- count = 0
9
- offset = 0
10
- previous = nil
11
- while count < 2
12
- data.get_bytes(offset, 100).each_byte do |byte|
13
- length = length + 1
14
- count = count + 1 if byte.zero? and previous.zero?
15
- previous = byte
16
- return length - 2 if count >= 2
17
- end
18
- offset += 100
19
- break if offset >= 10000
20
- end
21
- length
22
- end
23
-
24
8
  class LiveIdentity
25
9
  class LiveIdentityError < WinCommon::Errors::HRESULTError; end
26
10
 
@@ -28,31 +12,58 @@ class LiveIdentity
28
12
  WinCommon::Errors::HRESULT::IsError?(hr)
29
13
  end
30
14
 
31
- def initialize(guid, version, flags, options)
32
- guidClientApplication = IDCRL::GUID.new
33
- guidClientApplication.from_str(guid)
34
- lPPCRLVersion = version
35
- dwFlags = flags
36
- dwOptions = options.count
15
+ def self.processOptions(options)
37
16
  pOptions = nil
38
- if dwOptions > 0
39
- pOptions = FFI::MemoryPointer.new(IDCRL::IDCRL_OPTION, dwOptions)
17
+ if options.count > 0
18
+ pOptions = FFI::MemoryPointer.new(IDCRL::IDCRL_OPTION, options.count)
40
19
  i = 0
41
20
  options.each do |id, value|
42
21
  option = IDCRL::IDCRL_OPTION.new(pOptions + i * IDCRL::IDCRL_OPTION.size)
43
22
  option[:dwId] = id
44
23
  option[:pValue] = FFI::MemoryPointer.new(:pointer)
45
24
  if value.is_a?(String)
46
- data = [value.encode('UTF-16LE')].pack('a*xx')
25
+ data = StringToWSTR(value)
47
26
  option[:pValue].write_string(data)
48
27
  option[:cbValue] = data.bytesize
28
+ elsif value.is_a?(Fixnum)
29
+ option[:pValue].write_int(data)
30
+ option[:cbValue] = 4
49
31
  else
50
- # TODO
32
+ raise "Uknown value type #{value.inspect}"
51
33
  end
52
34
  i += 1
53
35
  end
54
36
  end
37
+ pOptions
38
+ end
55
39
 
40
+ def self.processRSTParams(params)
41
+ pRSTParams = nil
42
+ if params.count > 0
43
+ pRSTParams = FFI::MemoryPointer.new(IDCRL::RSTParams, params.count)
44
+ params.each_index do |i|
45
+ IDCRL::RSTParams.build(params[i], pRSTParams + i * IDCRL::RSTParams.size)
46
+ end
47
+ end
48
+ pRSTParams
49
+ end
50
+
51
+ def self.waitFor(pr, errorText, time = 20, wait = 0.2)
52
+ Timeout::timeout(time) do
53
+ while !pr.call do sleep(wait) end
54
+ end
55
+ rescue Timeout::Error
56
+ yield
57
+ raise errorText
58
+ end
59
+
60
+ def initialize(guid, version, flags, options)
61
+ guidClientApplication = IDCRL::GUID.new
62
+ guidClientApplication.from_str(guid)
63
+ lPPCRLVersion = version
64
+ dwFlags = flags
65
+ dwOptions = options.count
66
+ pOptions = LiveIdentity::processOptions(options)
56
67
  hr = IDCRL.InitializeEx(guidClientApplication, lPPCRLVersion, dwFlags, pOptions, dwOptions)
57
68
  raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
58
69
  ObjectSpace.define_finalizer( self, self.class.finalize() )
@@ -62,22 +73,147 @@ class LiveIdentity
62
73
  Proc.new { IDCRL.Uninitialize() }
63
74
  end
64
75
 
76
+ def self.FreeMemory(pMemoryToFree)
77
+ hr = IDCRL.PassportFreeMemory(pMemoryToFree)
78
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
79
+ end
80
+
81
+ def self.VerifyCertificate(certSet, minTTL)
82
+ dwMinTTL = FFI::MemoryPointer.new(:DWORD)
83
+ dwMinTTL.write_uint(minTTL)
84
+ pCACertContext = FFI::MemoryPointer.new(:PCERT_CONTEXT)
85
+ hr = IDCRL.VerifyCertificate(certSet[:pCertContext], dwMinTTL, certSet[:pbPOP], certSet[:cbPOP], pCACertContext)
86
+ certSet[:pCACertContext] = pCACertContext.read_pointer
87
+ certSet.CACertContext
88
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
89
+ end
90
+
91
+ def SetExtendedProperty(property, value)
92
+ wszPropertyName = StringToWSTR(property)
93
+ wszPropertyValue = StringToWSTR(value)
94
+ hr = IDCRL.SetExtendedProperty(wszPropertyName, wszPropertyValue)
95
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
96
+ end
97
+
98
+ def GetExtendedProperty(property)
99
+ wszPropertyName = StringToWSTR(property)
100
+ wszPropertyValue = FFI::MemoryPointer.new(:PLPWSTR)
101
+ hr = IDCRL.GetExtendedProperty(wszPropertyName, wszPropertyValue)
102
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
103
+ propertyValue = read_wide_string(wszPropertyValue.read_pointer)
104
+ LiveIdentity::FreeMemory(wszPropertyValue.read_pointer)
105
+ propertyValue
106
+ end
107
+
108
+ def self.GetServiceConfig(valueName)
109
+ wszValueName = StringToWSTR(valueName)
110
+ szUrlValue = FFI::MemoryPointer.new(:PLPWSTR)
111
+ hr = IDCRL.GetServiceConfig(wszValueName, szUrlValue)
112
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
113
+ return nil if szUrlValue.read_pointer.null?
114
+ urlValue = read_wide_string(szUrlValue.read_pointer)
115
+ LiveIdentity::FreeMemory(szUrlValue.read_pointer)
116
+ urlValue
117
+ end
118
+
119
+ def SetIdcrlOptions(options, flags)
120
+ dwOptions = options.count
121
+ pOptions = LiveIdentity::processOptions(options)
122
+ dwFlags = flags
123
+ hr = IDCRL.SetIdcrlOptions(pOptions, dwOptions, dwFlags)
124
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
125
+ end
126
+
127
+ def SetUserExtendedProperty(userName, name, value)
128
+ szUserName = StringToWSTR(userName)
129
+ szPropertyName = StringToWSTR(name)
130
+ szPropertyValue = StringToWSTR(value)
131
+ hr = IDCRL.SetUserExtendedProperty(szUserName, szPropertyName, szPropertyValue)
132
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
133
+ end
134
+
135
+ def GetUserExtendedProperty(userName, name)
136
+ szUserName = StringToWSTR(userName)
137
+ szPropertyName = StringToWSTR(name)
138
+ szPropertyValue = FFI::MemoryPointer.new(:PLPWSTR)
139
+ hr = IDCRL.GetUserExtendedProperty(szUserName, szPropertyName, szPropertyValue)
140
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
141
+ propertyValue = read_wide_string(szPropertyValue.read_pointer)
142
+ LiveIdentity::FreeMemory(szPropertyValue.read_pointer)
143
+ propertyValue
144
+ end
145
+
146
+ def SetChangeNotificationCallback(virtualApp, callBackFunction)
147
+ szVirtualApp = StringToWSTR(virtualApp)
148
+ hr = IDCRL.SetChangeNotificationCallback(szVirtualApp, nil, callBackFunction)
149
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
150
+ end
151
+
152
+ def RemoveChangeNotificationCallback()
153
+ hr = IDCRL.RemoveChangeNotificationCallback()
154
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
155
+ end
156
+
157
+ def GetIdentities(cachedCredType)
158
+ Identities.new(cachedCredType)
159
+ end
160
+
65
161
  def GetIdentity(memberName, flags)
66
162
  Identity.new(memberName, flags)
67
163
  end
68
164
 
165
+ class Identities
166
+ attr_reader :peihEnumHandle
167
+ def initialize(cachedCredType)
168
+ @peihEnumHandle = nil
169
+ szCachedCredType = nil
170
+ szCachedCredType = StringToWSTR(cachedCredType) if cachedCredType
171
+ peihEnumHandle = FFI::MemoryPointer.new(:PassportEnumIdentitiesHandlePointer)
172
+ hr = IDCRL.EnumIdentitiesWithCachedCredentials(szCachedCredType, peihEnumHandle)
173
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
174
+ @peihEnumHandle = peihEnumHandle.read_ulong
175
+ ObjectSpace.define_finalizer(self, self.class.finalize(@peihEnumHandle))
176
+ end
177
+
178
+ def self.finalize(peihEnumHandle)
179
+ Proc.new do
180
+ hr = IDCRL.CloseEnumIdentitiesHandle(peihEnumHandle)
181
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
182
+ end
183
+ end
184
+
185
+ def GetNextIdentityName
186
+ wszMemberName = FFI::MemoryPointer.new(:PLPWSTR)
187
+ hr = IDCRL.NextIdentity(@peihEnumHandle, wszMemberName)
188
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
189
+ return nil if hr == IDCRL::HRESULT::PPCRL_S_NO_MORE_IDENTITIES
190
+ memberName = read_wide_string(wszMemberName.read_pointer)
191
+ LiveIdentity::FreeMemory(wszMemberName.read_pointer)
192
+ memberName
193
+ end
194
+
195
+ def GetAllIdentityNames
196
+ identityNames = []
197
+ loop do
198
+ identityName = GetNextIdentityName()
199
+ break unless identityName
200
+ identityNames << identityName
201
+ end
202
+ identityNames
203
+ end
204
+ end
205
+
69
206
  class Identity
70
207
  attr_reader :hIdentity
71
208
  def initialize(memberName, flags)
72
209
  @hIdentity = nil
73
- wszMemberName = [memberName.encode('UTF-16LE')].pack('a*xx')
210
+ wszMemberName = StringToWSTR(memberName)
74
211
  dwflags = flags
75
-
76
- pihIdentity = FFI::MemoryPointer.new(:pointer)
212
+ pihIdentity = FFI::MemoryPointer.new(:PassportIdentityHandlePointer)
77
213
  hr = IDCRL.CreateIdentityHandle(wszMemberName, dwflags, pihIdentity)
78
214
  raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
79
215
  @hIdentity = pihIdentity.read_ulong
80
- ObjectSpace.define_finalizer( self, self.class.finalize(@hIdentity) )
216
+ ObjectSpace.define_finalizer(self, self.class.finalize(@hIdentity))
81
217
  end
82
218
 
83
219
  def self.finalize(hIdentity)
@@ -87,83 +223,365 @@ class LiveIdentity
87
223
  end
88
224
  end
89
225
 
226
+ def SetCredential(type, value)
227
+ wszCredType = StringToWSTR(type)
228
+ wszCredValue = StringToWSTR(value)
229
+ hr = IDCRL.SetCredential(@hIdentity, wszCredType, wszCredValue)
230
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
231
+ end
232
+
233
+ def GetProperty(property)
234
+ ipProperty = property
235
+ pwszPropertyValue = FFI::MemoryPointer.new(:PLPWSTR)
236
+ hr = IDCRL.GetIdentityProperty(@hIdentity, ipProperty, pwszPropertyValue)
237
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
238
+ propertyValue = read_wide_string(pwszPropertyValue.read_pointer)
239
+ LiveIdentity::FreeMemory(pwszPropertyValue.read_pointer)
240
+ propertyValue
241
+ end
242
+
90
243
  def SetProperty(property, value)
91
244
  ipProperty = property
92
- wszPropertyValue = [value.encode('UTF-16LE')].pack('a*xx')
245
+ wszPropertyValue = StringToWSTR(value)
93
246
  hr = IDCRL.SetIdentityProperty(@hIdentity, ipProperty, wszPropertyValue)
94
247
  raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
95
248
  end
96
249
 
250
+ def AuthToService(target, policy = 'HBI', flags = :SERVICE_TOKEN_FROM_CACHE, sessionKey = false)
251
+ szServiceTarget = StringToWSTR(target.to_s)
252
+ szServicePolicy = StringToWSTR(policy.to_s)
253
+ dwTokenRequestFlags = flags
254
+ szToken = FFI::MemoryPointer.new(:PLPWSTR)
255
+ pdwResultFlags = FFI::MemoryPointer.new(:PDWORD)
256
+ ppbSessionKey = nil
257
+ pcbSessionKeyLength = nil
258
+ if sessionKey
259
+ ppbSessionKey = FFI::MemoryPointer.new(:PPBYTE)
260
+ pcbSessionKeyLength = FFI::MemoryPointer.new(:PDWORD)
261
+ end
262
+ hr = IDCRL.AuthIdentityToService(@hIdentity, szServiceTarget, szServicePolicy, dwTokenRequestFlags, szToken, pdwResultFlags, ppbSessionKey, pcbSessionKeyLength)
263
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
264
+ authState = IDCRL::AuthState.new
265
+ authState[:szToken] = szToken.read_pointer
266
+ authState[:dwResultFlags] = pdwResultFlags.read_uint
267
+ authState[:pbSessionKey] = ppbSessionKey.read_pointer if sessionKey
268
+ authState[:dwSessionKeyLength] = pcbSessionKeyLength.read_uint if sessionKey
269
+ authState.Token()
270
+ authState.SessionKey()
271
+ LiveIdentity::FreeMemory(szToken.read_pointer)
272
+ LiveIdentity::FreeMemory(ppbSessionKey.read_pointer) if sessionKey
273
+ authState
274
+ end
275
+
276
+ def PersistCredential(credType)
277
+ wszCredType = StringToWSTR(credType)
278
+ hr = IDCRL.PersistCredential(@hIdentity, wszCredType)
279
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
280
+ end
281
+
282
+ def RemovePersistedCredential(credType)
283
+ wszCredType = StringToWSTR(credType)
284
+ hr = IDCRL.RemovePersistedCredential(@hIdentity, wszCredType)
285
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
286
+ end
287
+
288
+ def GetAuthState
289
+ hrAuthState = FFI::MemoryPointer.new(:PHRESULT)
290
+ hrAuthRequired = FFI::MemoryPointer.new(:PHRESULT)
291
+ hrRequestStatus = FFI::MemoryPointer.new(:PHRESULT)
292
+ wszWebFlowUrl = FFI::MemoryPointer.new(:LPWSTR)
293
+ hr = IDCRL.GetAuthState(@hIdentity, hrAuthState, hrAuthRequired, hrRequestStatus, wszWebFlowUrl)
294
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
295
+ status = IDCRL::IDCRL_STATUS_V1.new
296
+ status[:hrAuthState] = hrAuthState.read_long
297
+ status[:hrAuthRequired] = hrAuthRequired.read_long
298
+ status[:hrRequestStatus] = hrRequestStatus.read_long
299
+ status[:wszWebFlowUrl] = wszWebFlowUrl.read_pointer
300
+ status.WebFlowUrl unless status[:wszWebFlowUrl].null?
301
+ LiveIdentity::FreeMemory(status[:wszWebFlowUrl])
302
+ status
303
+ end
304
+
305
+ def LogonIdentity(policy, authFlags)
306
+ wszPolicy = StringToWSTR(policy)
307
+ dwAuthFlags = authFlags
308
+ hr = IDCRL.LogonIdentity(@hIdentity, wszPolicy, dwAuthFlags)
309
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
310
+ end
311
+
312
+ def HasPersistedCredential?(credType)
313
+ wszCredType = StringToWSTR(credType)
314
+ lpbPersisted = FFI::MemoryPointer.new(:LONG)
315
+ hr = IDCRL.HasPersistedCredential(@hIdentity, credType, lpbPersisted)
316
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
317
+ lpbPersisted.read_long == 0x00000001
318
+ end
319
+
320
+ def SetCallback(callBackData = nil, &callBackFunction)
321
+ hr = IDCRL.SetIdentityCallback(@hIdentity, callBackFunction, callBackData)
322
+ if WinCommon::Errors::HRESULT::Equal?(hr, IDCRL::HRESULT::PPCRL_E_BUSY)
323
+ sleep(0.1)
324
+ hr = IDCRL.SetIdentityCallback(@hIdentity, callBackFunction, callBackData)
325
+ end
326
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
327
+ end
328
+
329
+ def GetWebAuthUrl(targetServiceName, servicePolicy = 'HBI', additionalPostParams = nil, sourceServiceName = nil)
330
+ wszTargetServiceName = StringToWSTR(targetServiceName)
331
+ wszServicePolicy = StringToWSTR(servicePolicy)
332
+ wszAdditionalPostParams = nil
333
+ wszAdditionalPostParams = StringToWSTR(additionalPostParams) if additionalPostParams
334
+ wszSourceServiceName = nil
335
+ wszSourceServiceName = StringToWSTR(sourceServiceName) if sourceServiceName
336
+ pszMD5Url = FFI::MemoryPointer.new(:PLPWSTR)
337
+ pszPostData = FFI::MemoryPointer.new(:PLPWSTR)
338
+ hr = IDCRL.GetWebAuthUrl(@hIdentity, wszTargetServiceName, wszServicePolicy, wszAdditionalPostParams, wszSourceServiceName, pszMD5Url, pszPostData)
339
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
340
+ md5data = IDCRL::MD5Data.new
341
+ md5data[:szMD5Url] = pszMD5Url.read_pointer
342
+ md5data[:szPostData] = pszPostData.read_pointer
343
+ md5data.MD5Url
344
+ md5data.PostData
345
+ LiveIdentity::FreeMemory(pszMD5Url.read_pointer)
346
+ LiveIdentity::FreeMemory(pszPostData.read_pointer)
347
+ md5data
348
+ end
349
+
350
+ def LogonIdentityEx(authPolicy, authFlags, rstParams = [])
351
+ wszAuthPolicy = nil
352
+ wszAuthPolicy = StringToWSTR(authPolicy) if authPolicy
353
+ dwAuthFlags = authFlags
354
+ dwpcRSTParamsCount = rstParams.count
355
+ pcRSTParams = LiveIdentity::processRSTParams(rstParams)
356
+ hr = IDCRL.LogonIdentityEx(@hIdentity, wszAuthPolicy, dwAuthFlags, pcRSTParams, dwpcRSTParamsCount)
357
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
358
+ end
359
+
360
+ def AuthToServiceEx(requestFlags, rstParams)
361
+ swRequestFlags = requestFlags
362
+ dwpcRSTParamsCount = rstParams.count
363
+ pcRSTParams = LiveIdentity::processRSTParams(rstParams)
364
+ hr = IDCRL.AuthIdentityToServiceEx(@hIdentity, swRequestFlags, pcRSTParams, dwpcRSTParamsCount)
365
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
366
+ end
367
+
368
+ def GetAuthStateEx(serviceTarget, status)
369
+ wszServiceTarget = StringToWSTR(serviceTarget)
370
+ hr = IDCRL.GetAuthStateEx(@hIdentity, wszServiceTarget, status[:hrAuthState], status[:hrAuthRequired], status[:hrRequestStatus], status[:wszWebFlowUrl])
371
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
372
+ status.WebFlowUrl
373
+ LiveIdentity::FreeMemory(status[:wszWebFlowUrl])
374
+ end
375
+
376
+ def GetCertificate(rstParam, minTTL, requestFlags)
377
+ pcRSTParams = IDCRL::RSTParams.build(rstParam)
378
+ pdwMinTTL = FFI::MemoryPointer.new(:DWORD)
379
+ pdwMinTTL.write_uint(minTTL)
380
+ dwRequestFlags = requestFlags
381
+ certSet = IDCRL::CertSet.build
382
+ cbPOP = FFI::MemoryPointer.new(:DWORD)
383
+ hr = IDCRL.GetCertificate(@hIdentity, pcRSTParams, pdwMinTTL, dwRequestFlags, certSet[:pCertContext], certSet[:pbPOP], cbPOP, certSet[:pCACertContext])
384
+ certSet[:cbPOP] = cbPOP.read_uint
385
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
386
+ certSet
387
+ end
388
+
389
+ def CancelPendingRequest()
390
+ hr = IDCRL.CancelPendingRequest(@hIdentity)
391
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
392
+ end
393
+
97
394
  def GetPropertyByName(name)
98
- wszPropertyName = [name.encode('UTF-16LE')].pack('a*xx')
395
+ wszPropertyName = StringToWSTR(name)
99
396
  pwszPropertyValue = FFI::MemoryPointer.new(:pointer)
100
397
  hr = IDCRL.GetIdentityPropertyByName(@hIdentity, wszPropertyName, pwszPropertyValue)
101
398
  raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
102
- pwszPropertyValue = pwszPropertyValue.read_pointer.read_bytes(getStringLength(pwszPropertyValue.read_pointer))
103
- pwszPropertyValue.force_encoding('UTF-16LE').encode('UTF-8')
399
+ propertyValue = read_wide_string(pwszPropertyValue.read_pointer)
400
+ LiveIdentity::FreeMemory(pwszPropertyValue.read_pointer)
401
+ propertyValue
104
402
  end
105
403
 
106
- def SetCredential(type, value)
107
- wszCredType = [type.encode('UTF-16LE')].pack('a*xx')
108
- wszCredValue = [value.encode('UTF-16LE')].pack('a*xx')
109
- hr = IDCRL.SetCredential(@hIdentity, wszCredType, wszCredValue)
404
+ def GetWebAuthUrlEx(webAuthFlag, targetServiceName, servicePolicy = 'HBI', additionalPostParams = nil)
405
+ dwWebAuthFlag = webAuthFlag
406
+ wszTargetServiceName = StringToWSTR(targetServiceName)
407
+ wszServicePolicy = StringToWSTR(servicePolicy)
408
+ wszAdditionalPostParams = nil
409
+ wszAdditionalPostParams = StringToWSTR(additionalPostParams) if additionalPostParams
410
+ pszSHA1Url = FFI::MemoryPointer.new(:PLPWSTR)
411
+ pszSHA1PostData = FFI::MemoryPointer.new(:PLPWSTR)
412
+ hr = IDCRL.GetWebAuthUrlEx(@hIdentity, dwWebAuthFlag, wszTargetServiceName, wszServicePolicy, wszAdditionalPostParams, pszSHA1Url, pszSHA1PostData)
413
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
414
+ sha1 = IDCRL::SHA1.new
415
+ sha1[:szSHA1Url] = pszSHA1Url.read_pointer
416
+ sha1[:szSHA1PostData] = pszSHA1PostData.read_pointer
417
+ sha1.SHA1Url
418
+ sha1.SHA1PostData
419
+ LiveIdentity::FreeMemory(pszSHA1Url.read_pointer)
420
+ LiveIdentity::FreeMemory(pszSHA1PostData.read_pointer)
421
+ sha1
422
+ end
423
+
424
+ def EncryptWithSessionKey(serviceName, algIdEncrypt, algIdHash, data)
425
+ wszServiceName = StringToWSTR(serviceName)
426
+ dwAlgIdEncrypt = algIdEncrypt
427
+ dwAlgIdHash = algIdHash
428
+ dwDataSize = data.count
429
+ pbData = FFI::MemoryPointer.new(:LPVOID)
430
+ pbData.write_string(data, dwDataSize)
431
+ pbCipher = FFI::MemoryPointer.new(:PBYTE)
432
+ pdwCipherSize = FFI::MemoryPointer.new(:PDWORD)
433
+ hr = IDCRL.EncryptWithSessionKey(@hIdentity, wszServiceName, dwAlgIdEncrypt, dwAlgIdHash, pbData, dwDataSize, pbCipher, pdwCipherSize)
110
434
  raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
435
+ cipher = pbCipher.read_string(pdwCipherSize.read_pointer.read_uint)
436
+ LiveIdentity::FreeMemory(pbCipher.read_pointer)
437
+ cipher
438
+ end
439
+
440
+ def DecryptWithSessionKey(serviceName, algIdEncrypt, algIdHash, cipher)
441
+ wszServiceName = StringToWSTR(serviceName)
442
+ dwAlgIdEncrypt = algIdEncrypt
443
+ dwAlgIdHash = algIdHash
444
+ dwCipherSize = cipher.bytesize
445
+ pbCipher = FFI::MemoryPointer.new(:LPVOID)
446
+ pbCipher.write_string(cipher, dwCipherSize)
447
+ pbData = FFI::MemoryPointer.new(:LPVOID)
448
+ pdwDataSize = FFI::MemoryPointer.new(:PDWORD)
449
+ hr = IDCRL.DecryptWithSessionKey(@hIdentity, wszServiceName, dwAlgIdEncrypt, dwAlgIdHash, pbCipher, dwCipherSize, pbData, pdwDataSize)
450
+ raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
451
+ data = pbData.read_string(pdwDataSize.read_pointer.read_uint)
452
+ LiveIdentity::FreeMemory(pbData.read_pointer)
453
+ data
454
+ end
455
+
456
+ def GetExtendedError
457
+ ExtendedError.new(self)
458
+ end
459
+
460
+ def IsAuthenticated?
461
+ state = GetAuthState()
462
+ if !state.IsAuthenticated?
463
+ if !WinCommon::Errors::HRESULT::Equal?(state.RequestStatus, [WinCommon::Errors::HRESULT::S_OK, IDCRL::HRESULT::PPCRL_AUTHREQUIRED_E_PASSWORD])
464
+ puts GetExtendedError() if WinCommon::Errors::HRESULT::Equal?(state.RequestStatus, IDCRL::HRESULT::PPCRL_REQUEST_E_AUTH_SERVER_ERROR)
465
+ raise LiveIdentityError.new(state.RequestStatus)
466
+ end
467
+ if !WinCommon::Errors::HRESULT::Equal?(state.AuthState, [WinCommon::Errors::HRESULT::S_OK, IDCRL::HRESULT::PPCRL_AUTHSTATE_E_UNAUTHENTICATED, IDCRL::HRESULT::PPCRL_AUTHSTATE_E_EXPIRED])
468
+ raise LiveIdentityError.new(state.AuthState)
469
+ end
470
+ return false
471
+ end
472
+ true
473
+ end
474
+
475
+ def Authenticate(authPolicy, authFlags)
476
+ done = false
477
+ SetCallback() do |identity, data, canContinue|
478
+ done = true
479
+ 0
480
+ end
481
+ begin
482
+ LogonIdentityEx(authPolicy, authFlags)
483
+ rescue LiveIdentityError
484
+ state = GetAuthState()
485
+ puts state
486
+ CancelPendingRequest()
487
+ puts GetExtendedError() if WinCommon::Errors::HRESULT::Equal?(state.RequestStatus, IDCRL::HRESULT::PPCRL_REQUEST_E_AUTH_SERVER_ERROR)
488
+ raise
489
+ end
490
+ LiveIdentity::waitFor(Proc.new {done}, 'Authentication Timeout!') { CancelPendingRequest() }
491
+ state = GetAuthState()
492
+ if !state.IsAuthenticated?
493
+ puts state
494
+ CancelPendingRequest()
495
+ puts GetExtendedError() if WinCommon::Errors::HRESULT::Equal?(state.RequestStatus, IDCRL::HRESULT::PPCRL_REQUEST_E_AUTH_SERVER_ERROR)
496
+ raise LiveIdentityError.new(state.RequestStatus) if LiveIdentity::IsError?(state.RequestStatus)
497
+ raise LiveIdentityError.new(state.AuthState)
498
+ end
499
+ ensure
500
+ SetCallback()
111
501
  end
112
502
 
113
- def AuthToService(target, policy, flags)
114
- Service.new(self, target, policy, flags)
503
+ def GetService(target, policy = 'HBI', flags = :SERVICE_TOKEN_FROM_CACHE, sessionKey = false)
504
+ begin
505
+ authState = AuthToService(target, policy, flags, sessionKey)
506
+ rescue LiveIdentityError => e
507
+ done = false
508
+ SetCallback() do |identity, data, canContinue|
509
+ done = true
510
+ 0
511
+ end
512
+ if WinCommon::Errors::HRESULT::Equal?(e.code, [IDCRL::HRESULT::PPCRL_E_BUSY, IDCRL::HRESULT::PPCRL_E_UNABLE_TO_RETRIEVE_SERVICE_TOKEN, IDCRL::HRESULT::PPCRL_REQUEST_E_FORCE_SIGNIN])
513
+ authState = AuthToService(target, policy, :SERVICE_TOKEN_REQUEST_TYPE_NONE, sessionKey)
514
+ LiveIdentity::waitFor(Proc.new {done}, 'Authorization Timeout!') { CancelPendingRequest() }
515
+ state = GetAuthState()
516
+ if !state.IsAuthenticated?
517
+ puts state
518
+ puts GetExtendedError() if WinCommon::Errors::HRESULT::Equal?(state.RequestStatus, IDCRL::HRESULT::PPCRL_REQUEST_E_AUTH_SERVER_ERROR)
519
+ raise LiveIdentityError.new(state.RequestStatus) if LiveIdentity::IsError?(state.RequestStatus)
520
+ raise LiveIdentityError.new(state.AuthState)
521
+ end
522
+ else
523
+ raise
524
+ end
525
+ ensure
526
+ SetCallback()
527
+ end
528
+ authState = AuthToService(target, policy, :SERVICE_TOKEN_FROM_CACHE, sessionKey) unless authState.Token()
529
+ Service.new(authState)
115
530
  end
116
531
 
117
532
  class ExtendedError
118
533
  attr_reader :Category
119
534
  attr_reader :Error
120
535
  attr_reader :ErrorBlob
536
+ attr_reader :ErrorBlobXML
121
537
  def initialize(identity)
122
538
  @Category = nil
123
539
  @Error = nil
124
540
  @ErrorBlob = nil
125
-
541
+ @ErrorBlobXML = nil
126
542
  hIdentity = identity.hIdentity
127
- pdwCategory = FFI::MemoryPointer.new(:pointer)
128
- pdwError = FFI::MemoryPointer.new(:pointer)
129
- pszErrorBlob = FFI::MemoryPointer.new(:pointer)
130
-
543
+ pdwCategory = FFI::MemoryPointer.new(:PDWORD)
544
+ pdwError = FFI::MemoryPointer.new(:PDWORD)
545
+ pszErrorBlob = FFI::MemoryPointer.new(:LPWSTR)
131
546
  hr = IDCRL.GetExtendedError(hIdentity, nil, pdwCategory, pdwError, pszErrorBlob)
132
547
  raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
548
+ @Category = pdwCategory.read_uint
549
+ @Error = pdwError.read_uint
550
+ @ErrorBlob = read_wide_string(pszErrorBlob.read_pointer)
551
+ @ErrorBlobXML = Nokogiri::XML(@ErrorBlob)
552
+ LiveIdentity::FreeMemory(pszErrorBlob.read_pointer)
133
553
  end
134
- end
135
554
 
136
- def GetExtendedError
137
- ExtendedError.new
555
+ def BlobResponse
556
+ return unless @ErrorBlobXML
557
+ @BlobResponse ||= Nokogiri::XML(@ErrorBlobXML.xpath('/IDCRLErrorInfo/Response').first.content)
558
+ end
559
+
560
+ def BlobResponseError
561
+ response = BlobResponse()
562
+ reasonText = response.xpath('//S:Fault/S:Reason/S:Text').first.content
563
+ errorValue = response.xpath('//S:Fault/S:Detail/psf:error/psf:value').first.content.strip.to_i(16)
564
+ internalError = response.xpath('//S:Fault/S:Detail/psf:error/psf:internalerror/psf:code').first.content.strip.to_i(16)
565
+ internalErrorText = response.xpath('//S:Fault/S:Detail/psf:error/psf:internalerror/psf:text').first.content.strip
566
+ "ReasonText: #{reasonText}\n" +
567
+ "ErrorValue: #{WinCommon::Errors::HRESULT::GetNameCode(errorValue)}\n" +
568
+ "InternalError: #{internalErrorText} #{WinCommon::Errors::HRESULT::GetNameCode(internalError)}\n"
569
+ end
570
+
571
+ def to_s
572
+ "Category: #{IDCRL::IDCRL_ERROR_CATEGORY.to_h[@Category]} (#{@Category})\n" +
573
+ "Error: #{WinCommon::Errors::HRESULT::GetNameCode(@Error)}\n" + BlobResponseError()
574
+ end
138
575
  end
139
576
 
140
577
  class Service
141
578
  attr_reader :Token
142
579
  attr_reader :ResultFlags
143
580
  attr_reader :SessionKey
144
- def initialize(identity, target, policy, flags, sessionKey = false)
145
- @Token = nil
146
- @ResultFlags = nil
147
- @SessionKey = nil
148
-
149
- hIdentity = identity.hIdentity
150
- szServiceTarget = [target.to_s.encode('UTF-16LE')].pack('a*xx')
151
- szServicePolicy = [policy.to_s.encode('UTF-16LE')].pack('a*xx')
152
- dwTokenRequestFlags = flags
153
-
154
- szToken = FFI::MemoryPointer.new(:pointer)
155
- pdwResultFlags = FFI::MemoryPointer.new(:pointer)
156
- ppbSessionKey = nil
157
- pcbSessionKeyLength = nil
158
- if sessionKey
159
- ppbSessionKey = FFI::MemoryPointer.new(:pointer)
160
- pcbSessionKeyLength = FFI::MemoryPointer.new(:pointer)
161
- end
162
-
163
- hr = IDCRL.AuthIdentityToService(hIdentity, szServiceTarget, szServicePolicy, dwTokenRequestFlags, szToken, pdwResultFlags, ppbSessionKey, pcbSessionKeyLength)
164
- raise LiveIdentityError.new(hr) if LiveIdentity::IsError?(hr)
165
- szToken = szToken.read_pointer.read_bytes(getStringLength(szToken.read_pointer))
166
- @Token = szToken.force_encoding('UTF-16LE').encode('UTF-8')
581
+ def initialize(authState)
582
+ @Token = authState.Token()
583
+ @ResultFlags = authState.ResultFlags()
584
+ @SessionKey = authState.SessionKey()
167
585
  end
168
586
  end
169
587
  end