Search code examples
pythonrestpowershellurllib2

Base64 Encoding issue - Python vs Powershell


I am trying to encode an auth token and pass it to a REST API, this works fine with powershell but applying the same method to python script throws 'unauthorized' exception.

I suspect there is a problem in encoded value. Not able to figure out the solution. Any ideas ?

The rest endpoint is IBM uDeploy.

Powershell

$tokenEncoded = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes( "PasswordIsAuthToken:{`"token`":`"$pass`"}" ))
$basicAuthValue = "Basic $tokenEncoded"
$headers = @{}
$headers.Add("Authorization", $basicAuthValue)
$response = Invoke-RestMethod -Method Put -Headers $headers -Uri $requestUri -Body $jsonRequest

Python

epass = base64.b64encode("PasswordIsAuthToken:{\"token\":\"$password\"}")
print 'base64 encoded: ' + epass
opener = urllib2.build_opener(urllib2.HTTPHandler)
req = urllib2.Request(reqUrl,json.dumps(json_data))
req.add_header('Authorization', 'Basic '+epass)
req.get_method = lambda: 'PUT'
resp = opener.open(req)

Solution

  • You are sending the literal string $password as the token, not the contents of a variable named password.

    You only need to include the PasswordIsAuthToken and your token in a Basic Auth HTTP header (PasswordIsAuthToken forms the username, and token the password):

    epass = base64.b64encode("PasswordIsAuthToken:" + password)
    opener = urllib2.build_opener(urllib2.HTTPHandler)
    req = urllib2.Request(reqUrl,json.dumps(json_data))
    req.add_header('Authorization', 'Basic ' + epass)
    

    If you reall need to wrap the token in a JSON-like structure then you'd need to use string formatting (which the Powershell code also does, but you omitted):

    epass = base64.b64encode('PasswordIsAuthToken:{"token":"%s"}' % password)
    

    or you could use the json module:

    epass = base64.b64encode('PasswordIsAuthToken:' + json.dumps({'token': password}))
    

    However, I believe the system should accept the token unwrapped.

    I strongly recommend you use the requests library instead, which makes using a REST API vastly cleaner:

    import requests
    
    auth = ('PasswordIsAuthToken', password)
    # or alternatively
    # auth = ('PasswordIsAuthToken', '{"token":"%s"}' % password)
    response = requests.put(json=json_data, auth=auth)
    

    Note that there is no need to encode the JSON body yourself, nor do you have to encode the Basic Auth header.