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 +4 -4
- data/lib/live_identity.rb +491 -73
- data/lib/live_identity/idcrl.rb +141 -91
- data/lib/live_identity/idcrl/constants.rb +13 -6
- data/lib/live_identity/idcrl/enums.rb +14 -9
- data/lib/live_identity/idcrl/hresult.rb +174 -12
- data/lib/live_identity/idcrl/structs.rb +220 -8
- data/lib/live_identity/version.rb +1 -1
- data/live_identity.gemspec +5 -1
- metadata +59 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 06a790b64a525efc4d3fe7bcb41d778570450749
|
4
|
+
data.tar.gz: fd6c4ce77fe2157ce34e6826ff7005b78dc42ebb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5f77cb827bf85c0971c392dd7654821af43985468c5c53a4f21fa19b41b7bec74aa6389b1d0f0698e53e320fd40c9e35b1e5cdd2a6114e8d92c13682a29e9657
|
7
|
+
data.tar.gz: 9a03403518f82876987e2b67816db3cfb84027b79e11af3049e639a1dbe59aef4646241e0b01480272c485887b2513b6f768acc806dda7ca18175c38ce55d726
|
data/lib/live_identity.rb
CHANGED
@@ -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
|
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
|
39
|
-
pOptions = FFI::MemoryPointer.new(IDCRL::IDCRL_OPTION,
|
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 =
|
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
|
-
#
|
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 =
|
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(
|
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 =
|
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 =
|
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
|
-
|
103
|
-
pwszPropertyValue.
|
399
|
+
propertyValue = read_wide_string(pwszPropertyValue.read_pointer)
|
400
|
+
LiveIdentity::FreeMemory(pwszPropertyValue.read_pointer)
|
401
|
+
propertyValue
|
104
402
|
end
|
105
403
|
|
106
|
-
def
|
107
|
-
|
108
|
-
|
109
|
-
|
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
|
114
|
-
|
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(:
|
128
|
-
pdwError = FFI::MemoryPointer.new(:
|
129
|
-
pszErrorBlob = FFI::MemoryPointer.new(:
|
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
|
-
|
137
|
-
|
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(
|
145
|
-
@Token =
|
146
|
-
@ResultFlags =
|
147
|
-
@SessionKey =
|
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
|