I didn't track it to the exact patch, but one of the pre v4.1 Update 1 patches added detection for "Possible Cross-Site Request Forgery"
I setup my mob to run over http, did some network captures, and determined that the following needed to be included:
1. Session cookie
2. Hidden form / value for 'vmware-session-nonce'
I'm not a python guru, so if you have a better way to do what I've done, please contribute back to this thread.
The following code is working for me (at least post-install, I'll trying during scripted installation shortly).
I sure hope this helps somebody else, as it was a challenge to resolve.
Enjoy!
import sys,re,os,urllib,urllib2,base64
### Define Variables ###
print 'Begin executing join domain script'
# mob url
url = "https://localhost/mob/?moid=ha-ad-auth&method=joinDomain"
# mob login credentials -- use password = "" for build scripting
username = "root"
password = ""
# which domain to join, and associated OU
domainname = "my.domain.com/VMWare Server OU"
# Active Directory credentials with rights to join a computer to the domain
# create encoded password with the command: python -c "import base64; print base64.b64encode('mypassword')"
# note: escape special characters in your password with a \
# Feel free to improve this solution, but it at least keeps cleartext out of the file.
ad_username = "user@my.domain.com"
encodedpassword = "cGFzc3dvcmQ="
ad_password = base64.b64decode(encodedpassword)
# Create global variables
global passman,authhandler,opener,req,page,page_content,nonce,headers,cookie,params,e_params
# Code to build opener with HTTP Basic Authentication
try:
passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
passman.add_password(None,url,username,password)
authhandler = urllib2.HTTPBasicAuthHandler(passman)
opener = urllib2.build_opener(authhandler)
urllib2.install_opener(opener)
except IOError, e:
if hasattr(e, 'reason'):
print 'FAIL: HTTP Authentication'
print 'Reason: ', e.reason
sys.exit(1)
elif hasattr(e, 'code'):
print 'FAIL: HTTP Authentication'
print 'Error code: ', e.code
sys.exit(1)
else:
print 'SUCCESS: Build HTTP Basic Authentication Handler'
### Code to capture required page data and cookie required for post back to meet CSRF requirements ###
try:
req = urllib2.Request(url)
page = urllib2.urlopen(req)
page_content= page.read()
except IOError, e:
if hasattr(e, 'reason'):
print 'FAIL: MOB Page Request'
print 'Reason: ', e.reason
sys.exit(1)
elif hasattr(e, 'code'):
print 'FAIL: MOB Page Request'
print 'Error code: ', e.code
sys.exit(1)
else:
print 'SUCCESS: Request MOB page data'
# regex to get the vmware-session-nonce value from the hidden form entry
reg = re.compile('name="vmware-session-nonce" type="hidden" value="?([^\s^"]+)"')
nonce = reg.search(page_content).group(1)
# get the page headers to capture the cookie
headers = page.info()
cookie = headers.get("Set-Cookie")
# Code to join the domain
try:
params = {'vmware-session-nonce':nonce,'domainName':domainname,'userName':ad_username,'password':ad_password}
e_params = urllib.urlencode(params)
req = urllib2.Request(url, e_params, headers={"Cookie":cookie})
page = urllib2.urlopen(req).read()
except IOError, e:
if hasattr(e, 'reason'):
print 'FAIL: MOB Page Request'
print 'Reason: ', e.reason
sys.exit(1)
elif hasattr(e, 'code'):
print 'FAIL: MOB Page Request'
print 'Error code: ', e.code
sys.exit(1)
else:
print 'SUCCESS: Host joined to the domain'
Hi klich,
Thanks for sharing this information, I've gone ahead and updated my original log post with your modified code - http://www.virtuallyghetto.com/2011/02/automating-active-directory-domain-join.html
Marko,
I'm not sure what is different in your configuration that is requiring you to create the computer object first, but in our deployment this step it is not required.
The only additional step we required was to grant the AD account that we use in the script the ability to create computer objects in the domain.
There are several ways to accomplish that, but for those looking for an example, look at: http://kb.vmware.com/kb/1007697
Regards,
klich
I've been updating my scripted install forESXi 5 and couldn't get the domain join script to work. It seems that ESXi 5 now requires the root password included at the start of the script.
I amended the existing lines:
# mob url
url = "https://localhost/mob/?moid=ha-ad-auth&method=joinDomain"
# mob login credentials -- use password = "" for build scripting
username = "root"
password = ""
To the below (using an encoded password - Details on how to create this are mentioned in the code)
# mob url
url = "https://localhost/mob/?moid=ha-ad-auth&method=joinDomain"
# mob login credentials -- use password = "" for build scripting
username = "root"
encodedlocalpassword = "%ENCODEDPASSWORD%"
password = base64.b64decode(encodedlocalpassword)
Once I made this change the ESXi 5 build successfully joined to the domain.