Module: Azure::ARM::WindowsCredentials

Includes:
ReadCred, Chef::Mixin::WideString
Defined in:
lib/azure/resource_management/windows_credentials.rb

Constant Summary

Constants included from ReadCred

ReadCred::CRED_TYPE_DOMAIN_CERTIFICATE, ReadCred::CRED_TYPE_DOMAIN_PASSWORD, ReadCred::CRED_TYPE_DOMAIN_VISIBLE_PASSWORD, ReadCred::CRED_TYPE_GENERIC

Instance Method Summary collapse

Instance Method Details

#latest_credential_target(targets) ⇒ Object



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/azure/resource_management/windows_credentials.rb', line 157

def latest_credential_target(targets)
  case targets.size
  when 0
    raise "No Target was found for windows credentials"
  when 1
    targets.first.gsub("Target:", "").strip
  else
    latest_target = ""
    max_expiry_time = Time.new(0)

    # Using expiry_time to determine the latest credential
    targets.each do |target|
      target_obj = target.split("::")
      expiry_time_obj = target_obj.select { |obj| obj.include? "expiresOn" }
      expiry_time = expiry_time_obj[0].split("expiresOn:")[1].delete("\\")
      if Time.parse(expiry_time) > max_expiry_time
        latest_target = target
        max_expiry_time = Time.parse(expiry_time)
      end
    end

    latest_target.gsub("Target:", "").strip
  end
end

#target_nameObject

Todo: For getting the complete refreshToken, both credentials (ending with –0-2 and –1-2) have to be read



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/azure/resource_management/windows_credentials.rb', line 123

def target_name
  # cmdkey command is used for accessing windows credential manager.
  # Multiple credentials get created in windows credential manager for a single Azure account in xplat-cli
  # One of them is for common tanent id, which can't be used
  # Others end with --0-x,--1-x,--2-x etc, where x represents the total no. of credentails across which the token is divided
  # The one ending with --0-x has the complete accessToken in the credentialBlob.
  # Refresh Token is split across both credentials (ending with --0-x and --1-x).
  # Xplat splits the credentials based on the number of bytes of the tokens.
  # Hence the access token is always found in the one which start with --0-
  # So selecting the credential on the basis of --0-
  xplat_creds_cmd = Mixlib::ShellOut.new('cmdkey /list | findstr AzureXplatCli | findstr \--0- | findstr -v common')
  result = xplat_creds_cmd.run_command
  target_names = []

  if result.stdout.empty?
    Chef::Log.debug("Unable to find a credential with --0- and falling back to looking for any credential.")
    xplat_creds_cmd = Mixlib::ShellOut.new("cmdkey /list | findstr AzureXplatCli | findstr -v common")
    result = xplat_creds_cmd.run_command

    if result.stdout.empty?
      raise "Azure Credentials not found. Please run xplat's 'azure login' command"
    else
      target_names = result.stdout.split("\n")
    end
  else
    target_names = result.stdout.split("\n")
  end

  # If "azure login" is run for multiple users, there will be multiple credentials
  # Picking up the latest logged in user's credentials
  latest_target = latest_credential_target target_names
  latest_target
end

#token_details_from_WCMObject



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/azure/resource_management/windows_credentials.rb', line 80

def token_details_from_WCM
  target = target_name

  if target && !target.empty?
    target_pointer = wstring(target)
    info_ptr = FFI::MemoryPointer.new(:pointer)
    cred = CREDENTIAL_OBJECT.new info_ptr
    cred_result = CredReadW(target_pointer, CRED_TYPE_GENERIC, 0, cred)
    translated_cred = CREDENTIAL_OBJECT.new(info_ptr.read_pointer)

    target_obj = translated_cred[:TargetName].read_wstring.split("::") if translated_cred[:TargetName].read_wstring
    cred_blob = translated_cred[:CredentialBlob].get_bytes(0, translated_cred[:CredentialBlobSize]).split("::")

    tokentype = target_obj.select { |obj| obj.include? "tokenType" }
    user = target_obj.select { |obj| obj.include? "userId" }
    clientid = target_obj.select { |obj| obj.include? "clientId" }
    expiry_time = target_obj.select { |obj| obj.include? "expiresOn" }
    access_token = cred_blob.select { |obj| obj.include? "a:" }
    refresh_token = cred_blob.select { |obj| obj.include? "r:" }

    credential = {}
    credential[:tokentype] = tokentype[0].split(":")[1]
    credential[:user] = user[0].split(":")[1]
    credential[:token] = access_token[0].split(":")[1]
    # TODO: refresh_token is not complete currently
    # target_name method needs to be modified for that
    credential[:refresh_token] = refresh_token[0].split(":")[1]
    credential[:clientid] = clientid[0].split(":")[1]
    credential[:expiry_time] = expiry_time[0].split("expiresOn:")[1].delete("\\")

    # Free memory pointed by info_ptr
    info_ptr.free
  else
    raise "TargetName Not Found"
  end
  credential
rescue => error
  ui.error("#{error.message}")
  Chef::Log.debug("#{error.backtrace.join("\n")}")
  exit
end