Azure / azure-storage-python

Microsoft Azure Storage Library for Python
https://azure-storage.readthedocs.io
MIT License
338 stars 240 forks source link

Server failed to authenticate the request #498

Closed ghost closed 6 years ago

ghost commented 6 years ago

Which service(blob, file, queue) does this issue concern?

BLOB

Which version of the SDK was used? Please provide the output of pip freeze.

latest

What problem was encountered?

I wrote some app to copy blobs between storage accounts, when i'm run it from local VM everything works fine when I try to run it from docker i'm getting this issue.

Client-Request-ID=3fd7aa82-b044-11e8-8a4b-0242ac110002 Retry policy did not allow for a retry: Server-Timestamp=Tue, 04 Sep 2018 13:13:00 GMT, Server-Request-ID=205bfc1c-e01e-007c-4f51-4480e7000000, HTTP status code=403, Exception=Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. ErrorCode: AuthenticationFailed<?xml version="1.0" encoding="utf-8"?>AuthenticationFailedServer failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.RequestId:205bfc1c-e01e-007c-4f51-4480e7000000Time:2018-09-04T13:13:01.0660872ZThe MAC signature found in the HTTP request 'x7XuEX2O63nDYKJwezmgh70SI328U7OpJDq/j8JVe34=' is not the same as any computed signature. Server used following string to sign: 'GETx-ms-client-request-id:3fd7aa82-b044-11e8-8a4b-0242ac110002x-ms-date:Tue, 04 Sep 2018 13:13:01 GMTx-ms-version:2018-03-28//:listrestype:container'.

Have you found a mitigation/solution?

NOPE

Note: for table service, please post the issue here instead: https://github.com/Azure/azure-cosmosdb-python.

ghost commented 6 years ago

import time
import uuid
from datetime import datetime, timedelta
import flask
from flask import Flask, request #import main Flask class and request object

from azure.storage.blob import (
    BlockBlobService,
    ContainerPermissions,
    BlobPermissions,
    PublicAccess,
)
from azure.storage.common import (
    AccessPolicy,
    ResourceTypes,
    AccountPermissions,
)

def create_container(contName, accName, accKey):
  account = BlobService(account_name = accName, account_key = accKey)
  account.create_container(contName)

def list_blobs(blockBlobService,contName):
  print("\nList blobs in the container")
  blobList = blockBlobService.list_blobs(contName)
  print(str(blobList))
  return blobList

def copy (accFromName, accToName, accFromKey, accToKey, contFromName, contToName, blobName):

  blockBlobServiceFrom = BlockBlobService(account_name=accFromName, account_key=accFromKey)
  sasToken = blockBlobServiceFrom.generate_container_shared_access_signature(contFromName,ContainerPermissions.READ, datetime.utcnow() + timedelta(hours=1))
  blockBloberviceTo = BlockBlobService(account_name=accToName, account_key=accToKey)

  sourceBlob = blockBlobServiceFrom.make_blob_url(contFromName, blobName, sas_token=sasToken)
  print("###################################>"+sourceBlob)
  copied = blockBloberviceTo.copy_blob(contToName, blobName, sourceBlob)
  count=0
  while copied.status != 'success':
    if count > 5:
      print('Timed out waiting for async copy to complete.')
    time.sleep(30)
    copied = blockBloberviceTo.get_blob_properties(contToName, blobName).properties.copy

  if copied.status == 'success':
    blockBlobServiceFrom.delete_blob(contFromName, blobName)
    print("Copy blob: "+blobName+" success! ")
    return("Blob "+blobName+" copied!")
  else:
    print("Copy blob: "+blobName+" failed! "+str(copied.status))
    return("Blob "+blobName+" not copied! "+str(copied.status))

app = Flask(__name__) #create the Flask app

@app.route('/ping')
def ping():
    version = flask.__version__
    return 'Server version: '+ version

@app.route('/copy', methods = ['POST'])
def postJsonHandler():
  print (request.is_json)
  content = request.get_json()
  print (content)
  blockBlobServiceFrom = BlockBlobService(account_name=content['storageFromName'], account_key=content['storageFromKey'])
  try:
    blobList = list_blobs(blockBlobServiceFrom,content['containerFromName'])
    for blob in blobList:
      message =  copy(content['storageFromName'],content['storageToName'],content['storageFromKey'],content['storageToKey'],content['containerFromName'],content['containerToName'],blob.name)
  except:
    message = "Epty list of blobs!"

  return "Copy ended!"

if __name__ == '__main__':
    app.run(debug=False, port=5000) #run app in debug mode on port 5000```
Fra-nk commented 6 years ago

Well, you already posted the error:

HTTP status code=403, Exception=Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.

You have to be wary of handling URL-quoting correctly when supplying the account key.

Add some debug output and run your copy function directly and via Flask to see the differences.

zezha-msft commented 6 years ago

Hi @adamsem, thanks for reaching out!

And thanks @Fra-nk for responding!

I agree that logging the credentials out and debug it that way will help narrowing down the problem.

ghost commented 6 years ago

I'm using the same python code (posted as comment) from my VM and from Docker. i'm not changing anything. And from VM works and from Docker is not working. I'm getting only this logs what I posted in ticket. It's some problem with MAC signature in headers. But i'm wondering what is different between VM and docker.

zezha-msft commented 6 years ago

Hi @adamsem, the error log shows that authentication failed for the list blob call. The "MAC signature" is just another way of saying the authentication header. Most often, an authentication failure is caused by using the wrong key to sign the request. It is also possible that there's a bug in the SDK, but since you said the script worked outside of Docker, it sounds unlikely in this case.

To confirm, is this problem reproducible? If yes, could you please log out the account name and key that your postJsonHandler is getting when running inside Docker? If you can confirm that the credentials used are indeed valid, that would really help in my investigation.

ghost commented 6 years ago

HI @zezha-msft , I solved the problem. That was problem in Flask itself. I change docker image from python 3.5 to python 3.6, after this everything is working fine. Thanks for support.

zezha-msft commented 6 years ago

@adamsem glad to hear that you solved it!