LiveIdentity 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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