knife-azure 2.0.10 → 2.0.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/azure/resource_management/windows_credentials.rb +135 -133
- data/lib/chef/knife/azurerm_base.rb +5 -5
- data/lib/knife-azure/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f6de7af42a6cf8184a9f2b57ad1556034f129f49812c9c3573a70a22cf95c6fe
|
4
|
+
data.tar.gz: c1aac2ac6eb7c5e0127d8971a3de4fd5fdb085f4521a6c414c857259e20a825e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 215f6a9ebf1f3339e589c48bd86ddf0c762426b26a05972b0660c541f7caedcaa695ed8f38da63fe354eff53af2a2a2caa50f3a2959d268d2e8f2e2cb75d488d
|
7
|
+
data.tar.gz: 3d3ee631a0e3a68fd3af1c50298ceecf7ac04978b1928be79f552e0405bff167cd92793aa4e90e9344ead46cc4518ab359a4eb391a4b1a3b45f6e5602f7c32ea
|
@@ -23,159 +23,161 @@ require "mixlib/shellout"
|
|
23
23
|
require "ffi"
|
24
24
|
require "chef/win32/api"
|
25
25
|
|
26
|
-
module Azure
|
26
|
+
module Azure
|
27
|
+
module ARM
|
27
28
|
|
28
|
-
|
29
|
+
module ReadCred
|
29
30
|
|
30
|
-
|
31
|
-
|
31
|
+
extend Chef::ReservedNames::Win32::API
|
32
|
+
extend FFI::Library
|
32
33
|
|
33
|
-
|
34
|
+
ffi_lib "Advapi32"
|
34
35
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
36
|
+
CRED_TYPE_GENERIC = 1
|
37
|
+
CRED_TYPE_DOMAIN_PASSWORD = 2
|
38
|
+
CRED_TYPE_DOMAIN_CERTIFICATE = 3
|
39
|
+
CRED_TYPE_DOMAIN_VISIBLE_PASSWORD = 4
|
39
40
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
end
|
45
|
-
|
46
|
-
# Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/aa374790(v=vs.85).aspx
|
47
|
-
class CREDENTIAL_ATTRIBUTE < FFI::Struct
|
48
|
-
layout :Keyword, :LPTSTR,
|
49
|
-
:Flags, :DWORD,
|
50
|
-
:ValueSize, :DWORD,
|
51
|
-
:Value, :LPBYTE
|
52
|
-
end
|
53
|
-
|
54
|
-
# Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/aa374788(v=vs.85).aspx
|
55
|
-
class CREDENTIAL_OBJECT < FFI::Struct
|
56
|
-
layout :Flags, :DWORD,
|
57
|
-
:Type, :DWORD,
|
58
|
-
:TargetName, :LPTSTR,
|
59
|
-
:Comment, :LPTSTR,
|
60
|
-
:LastWritten, FILETIME,
|
61
|
-
:CredentialBlobSize, :DWORD,
|
62
|
-
:CredentialBlob, :LPBYTE,
|
63
|
-
:Persist, :DWORD,
|
64
|
-
:AttributeCount, :DWORD,
|
65
|
-
:Attributes, CREDENTIAL_ATTRIBUTE,
|
66
|
-
:TargetAlias, :LPTSTR,
|
67
|
-
:UserName, :LPTSTR
|
41
|
+
# Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284(v=vs.85).aspx
|
42
|
+
class FILETIME < FFI::Struct
|
43
|
+
layout :dwLowDateTime, :DWORD,
|
44
|
+
:dwHighDateTime, :DWORD
|
68
45
|
end
|
69
46
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
include Chef::Mixin::WideString
|
77
|
-
include ReadCred
|
78
|
-
|
79
|
-
def token_details_from_WCM
|
80
|
-
target = target_name
|
81
|
-
|
82
|
-
if target && !target.empty?
|
83
|
-
target_pointer = wstring(target)
|
84
|
-
info_ptr = FFI::MemoryPointer.new(:pointer)
|
85
|
-
cred = CREDENTIAL_OBJECT.new info_ptr
|
86
|
-
cred_result = CredReadW(target_pointer, CRED_TYPE_GENERIC, 0, cred)
|
87
|
-
translated_cred = CREDENTIAL_OBJECT.new(info_ptr.read_pointer)
|
88
|
-
|
89
|
-
target_obj = translated_cred[:TargetName].read_wstring.split("::") if translated_cred[:TargetName].read_wstring
|
90
|
-
cred_blob = translated_cred[:CredentialBlob].get_bytes(0, translated_cred[:CredentialBlobSize]).split("::")
|
91
|
-
|
92
|
-
tokentype = target_obj.select { |obj| obj.include? "tokenType" }
|
93
|
-
user = target_obj.select { |obj| obj.include? "userId" }
|
94
|
-
clientid = target_obj.select { |obj| obj.include? "clientId" }
|
95
|
-
expiry_time = target_obj.select { |obj| obj.include? "expiresOn" }
|
96
|
-
access_token = cred_blob.select { |obj| obj.include? "a:" }
|
97
|
-
refresh_token = cred_blob.select { |obj| obj.include? "r:" }
|
98
|
-
|
99
|
-
credential = {}
|
100
|
-
credential[:tokentype] = tokentype[0].split(":")[1]
|
101
|
-
credential[:user] = user[0].split(":")[1]
|
102
|
-
credential[:token] = access_token[0].split(":")[1]
|
103
|
-
# Todo: refresh_token is not complete currently
|
104
|
-
# target_name method needs to be modified for that
|
105
|
-
credential[:refresh_token] = refresh_token[0].split(":")[1]
|
106
|
-
credential[:clientid] = clientid[0].split(":")[1]
|
107
|
-
credential[:expiry_time] = expiry_time[0].split("expiresOn:")[1].delete("\\")
|
108
|
-
|
109
|
-
# Free memory pointed by info_ptr
|
110
|
-
info_ptr.free
|
111
|
-
else
|
112
|
-
raise "TargetName Not Found"
|
47
|
+
# Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/aa374790(v=vs.85).aspx
|
48
|
+
class CREDENTIAL_ATTRIBUTE < FFI::Struct
|
49
|
+
layout :Keyword, :LPTSTR,
|
50
|
+
:Flags, :DWORD,
|
51
|
+
:ValueSize, :DWORD,
|
52
|
+
:Value, :LPBYTE
|
113
53
|
end
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
54
|
+
|
55
|
+
# Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/aa374788(v=vs.85).aspx
|
56
|
+
class CREDENTIAL_OBJECT < FFI::Struct
|
57
|
+
layout :Flags, :DWORD,
|
58
|
+
:Type, :DWORD,
|
59
|
+
:TargetName, :LPTSTR,
|
60
|
+
:Comment, :LPTSTR,
|
61
|
+
:LastWritten, FILETIME,
|
62
|
+
:CredentialBlobSize, :DWORD,
|
63
|
+
:CredentialBlob, :LPBYTE,
|
64
|
+
:Persist, :DWORD,
|
65
|
+
:AttributeCount, :DWORD,
|
66
|
+
:Attributes, CREDENTIAL_ATTRIBUTE,
|
67
|
+
:TargetAlias, :LPTSTR,
|
68
|
+
:UserName, :LPTSTR
|
69
|
+
end
|
70
|
+
|
71
|
+
# Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/aa374804(v=vs.85).aspx
|
72
|
+
safe_attach_function :CredReadW, %i{LPCTSTR DWORD DWORD pointer}, :BOOL
|
119
73
|
end
|
120
74
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
75
|
+
module WindowsCredentials
|
76
|
+
|
77
|
+
include Chef::Mixin::WideString
|
78
|
+
include ReadCred
|
79
|
+
|
80
|
+
def token_details_from_WCM
|
81
|
+
target = target_name
|
82
|
+
|
83
|
+
if target && !target.empty?
|
84
|
+
target_pointer = wstring(target)
|
85
|
+
info_ptr = FFI::MemoryPointer.new(:pointer)
|
86
|
+
cred = CREDENTIAL_OBJECT.new info_ptr
|
87
|
+
cred_result = CredReadW(target_pointer, CRED_TYPE_GENERIC, 0, cred)
|
88
|
+
translated_cred = CREDENTIAL_OBJECT.new(info_ptr.read_pointer)
|
89
|
+
|
90
|
+
target_obj = translated_cred[:TargetName].read_wstring.split("::") if translated_cred[:TargetName].read_wstring
|
91
|
+
cred_blob = translated_cred[:CredentialBlob].get_bytes(0, translated_cred[:CredentialBlobSize]).split("::")
|
92
|
+
|
93
|
+
tokentype = target_obj.select { |obj| obj.include? "tokenType" }
|
94
|
+
user = target_obj.select { |obj| obj.include? "userId" }
|
95
|
+
clientid = target_obj.select { |obj| obj.include? "clientId" }
|
96
|
+
expiry_time = target_obj.select { |obj| obj.include? "expiresOn" }
|
97
|
+
access_token = cred_blob.select { |obj| obj.include? "a:" }
|
98
|
+
refresh_token = cred_blob.select { |obj| obj.include? "r:" }
|
99
|
+
|
100
|
+
credential = {}
|
101
|
+
credential[:tokentype] = tokentype[0].split(":")[1]
|
102
|
+
credential[:user] = user[0].split(":")[1]
|
103
|
+
credential[:token] = access_token[0].split(":")[1]
|
104
|
+
# Todo: refresh_token is not complete currently
|
105
|
+
# target_name method needs to be modified for that
|
106
|
+
credential[:refresh_token] = refresh_token[0].split(":")[1]
|
107
|
+
credential[:clientid] = clientid[0].split(":")[1]
|
108
|
+
credential[:expiry_time] = expiry_time[0].split("expiresOn:")[1].delete("\\")
|
109
|
+
|
110
|
+
# Free memory pointed by info_ptr
|
111
|
+
info_ptr.free
|
112
|
+
else
|
113
|
+
raise "TargetName Not Found"
|
114
|
+
end
|
115
|
+
credential
|
116
|
+
rescue => error
|
117
|
+
ui.error("#{error.message}")
|
118
|
+
Chef::Log.debug("#{error.backtrace.join("\n")}")
|
119
|
+
exit
|
120
|
+
end
|
121
|
+
|
122
|
+
# Todo: For getting the complete refreshToken, both credentials (ending with --0-2 and --1-2) have to be read
|
123
|
+
def target_name
|
124
|
+
# cmdkey command is used for accessing windows credential manager.
|
125
|
+
# Multiple credentials get created in windows credential manager for a single Azure account in xplat-cli
|
126
|
+
# One of them is for common tanent id, which can't be used
|
127
|
+
# Others end with --0-x,--1-x,--2-x etc, where x represents the total no. of credentails across which the token is divided
|
128
|
+
# The one ending with --0-x has the complete accessToken in the credentialBlob.
|
129
|
+
# Refresh Token is split across both credentials (ending with --0-x and --1-x).
|
130
|
+
# Xplat splits the credentials based on the number of bytes of the tokens.
|
131
|
+
# Hence the access token is always found in the one which start with --0-
|
132
|
+
# So selecting the credential on the basis of --0-
|
133
|
+
xplat_creds_cmd = Mixlib::ShellOut.new('cmdkey /list | findstr AzureXplatCli | findstr \--0- | findstr -v common')
|
139
134
|
result = xplat_creds_cmd.run_command
|
135
|
+
target_names = []
|
140
136
|
|
141
137
|
if result.stdout.empty?
|
142
|
-
|
138
|
+
Chef::Log.debug("Unable to find a credential with --0- and falling back to looking for any credential.")
|
139
|
+
xplat_creds_cmd = Mixlib::ShellOut.new("cmdkey /list | findstr AzureXplatCli | findstr -v common")
|
140
|
+
result = xplat_creds_cmd.run_command
|
141
|
+
|
142
|
+
if result.stdout.empty?
|
143
|
+
raise "Azure Credentials not found. Please run xplat's 'azure login' command"
|
144
|
+
else
|
145
|
+
target_names = result.stdout.split("\n")
|
146
|
+
end
|
143
147
|
else
|
144
148
|
target_names = result.stdout.split("\n")
|
145
149
|
end
|
146
|
-
else
|
147
|
-
target_names = result.stdout.split("\n")
|
148
|
-
end
|
149
150
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
151
|
+
# If "azure login" is run for multiple users, there will be multiple credentials
|
152
|
+
# Picking up the latest logged in user's credentials
|
153
|
+
latest_target = latest_credential_target target_names
|
154
|
+
latest_target
|
155
|
+
end
|
155
156
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
157
|
+
def latest_credential_target(targets)
|
158
|
+
case targets.size
|
159
|
+
when 0
|
160
|
+
raise "No Target was found for windows credentials"
|
161
|
+
when 1
|
162
|
+
targets.first.gsub("Target:", "").strip
|
163
|
+
else
|
164
|
+
latest_target = ""
|
165
|
+
max_expiry_time = Time.new(0)
|
166
|
+
|
167
|
+
# Using expiry_time to determine the latest credential
|
168
|
+
targets.each do |target|
|
169
|
+
target_obj = target.split("::")
|
170
|
+
expiry_time_obj = target_obj.select { |obj| obj.include? "expiresOn" }
|
171
|
+
expiry_time = expiry_time_obj[0].split("expiresOn:")[1].delete("\\")
|
172
|
+
if Time.parse(expiry_time) > max_expiry_time
|
173
|
+
latest_target = target
|
174
|
+
max_expiry_time = Time.parse(expiry_time)
|
175
|
+
end
|
174
176
|
end
|
175
|
-
end
|
176
177
|
|
177
|
-
|
178
|
+
latest_target.gsub("Target:", "").strip
|
179
|
+
end
|
178
180
|
end
|
179
181
|
end
|
180
|
-
|
182
|
+
end
|
181
183
|
end
|
@@ -28,11 +28,6 @@ class Chef
|
|
28
28
|
## Manager (WCM) usage for authentication credentials storage purpose ##
|
29
29
|
XPLAT_VERSION_WITH_WCM_DEPRECATED ||= "0.10.5".freeze
|
30
30
|
|
31
|
-
if Chef::Platform.windows?
|
32
|
-
require_relative "../../azure/resource_management/windows_credentials"
|
33
|
-
include Azure::ARM::WindowsCredentials
|
34
|
-
end
|
35
|
-
|
36
31
|
def self.included(includer)
|
37
32
|
includer.class_eval do
|
38
33
|
deps do
|
@@ -42,6 +37,11 @@ class Chef
|
|
42
37
|
require "chef/mixin/shell_out"
|
43
38
|
require "time"
|
44
39
|
require "json"
|
40
|
+
|
41
|
+
if Chef::Platform.windows?
|
42
|
+
require_relative "../../azure/resource_management/windows_credentials"
|
43
|
+
include Azure::ARM::WindowsCredentials
|
44
|
+
end
|
45
45
|
end
|
46
46
|
|
47
47
|
option :azure_resource_group_name,
|
data/lib/knife-azure/version.rb
CHANGED