4

Please see the error below I am getting when trying to send a REST API PUT call to Azure.

{"error":{"code":"AuthenticationFailed","message":"Authentication failed. The 'Authorization' header is missing."}}

Here is my code for authorization.

def authorized():
    if request.args.get('state') != session.get("state"):
        return redirect(url_for("index"))  # No-OP. Goes back to Index page
    if "error" in request.args:  # Authentication/Authorization failure
        return render_template("auth_error.html", result=request.args)
    if request.args.get('code'):
        cache = _load_cache()
        result = _build_msal_app(cache=cache).acquire_token_by_authorization_code(
            request.args['code'],
            scopes=app_config.SCOPE,  # Misspelled scope would cause an HTTP 400 error here
            redirect_uri=url_for("authorized", _external=True))
        if "error" in result:
            return render_template("auth_error.html", result=result)
        session["user"] = result.get("id_token_claims")
        _save_cache(cache)
    return redirect(url_for("index"))

def _load_cache():
    cache = msal.SerializableTokenCache()
    if session.get("token_cache"):
        cache.deserialize(session["token_cache"])
    return cache

def _save_cache(cache):
    if cache.has_state_changed:
        session["token_cache"] = cache.serialize()

def _build_msal_app(cache=None, authority=None):
    return msal.ConfidentialClientApplication(
        app_config.CLIENT_ID, authority=authority or app_config.AUTHORITY,
        client_credential=app_config.CLIENT_SECRET, token_cache=cache)

def _build_auth_url(authority=None, scopes=None, state=None):
    return _build_msal_app(authority=authority).get_authorization_request_url(
        scopes or [],
        state=state or str(uuid.uuid4()),
        redirect_uri=url_for("authorized", _external=True))

def _get_token_from_cache(scope=None):
    cache = _load_cache()  # This web app maintains one cache per session
    cca = _build_msal_app(cache=cache)
    accounts = cca.get_accounts()
    if accounts:  # So all account(s) belong to the current signed-in user
        result = cca.acquire_token_silent(scope, account=accounts[0])
        _save_cache(cache)
        return result

Here is where the code is that includes the http request.

@app.route('/storageaccountcreate', methods = ['POST', 'PUT'])
def storageaccountcreate():
    name = request.form['storageaccountname']
    resourcegroup = request.form['resourcegroup']
    subscriptionId = request.form['subscriptionId']
    location = request.form['location']
    sku = request.form['sku']

    url = f'https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourcegroup}/providers/Microsoft.Storage/storageAccounts/{name}?api-version=2019-06-01'
    r = requests.put((url))
    print(r.text)
    return r.text

Also note I have already registered the application with Azure AD, and I've already set up my application to authenticate with Azure AD, and I can log in to the application using the Azure AD authentication. I am also receiving the token at login and it's being stored in cache.

1 Answer 1

3

If you want to create Azure storage account with Azure rest API, we need to call the Azure rest API with Azure AD access token. For more details, please refer to the official document and the blog

for example

REST API

PUT https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Storage/storageAccounts/{accountName}?api-version=2019-06-01

Authorization: Bearer <access token>
content-type: application/json


{
  "sku": {
    "name": "Standard_GRS"
  },
  "kind": "Storage",
  "location": "eastus"

}

python code

import json
@app.route("/storageaccountcreate")
def graphcall():
    token = _get_token_from_cache(["https://management.azure.com/user_impersonation"])
    if not token:
        return redirect(url_for("login"))
    headers={'Authorization': 'Bearer ' + token['access_token'],
             'Content-Type': 'application/json'

    }
    payload={
            "sku": {
                "name": "Standard_GRS"
            },
            "kind": "Storage",
            "location": "eastus"}
    payload=json.dumps(payload)
    name = request.form['storageaccountname']
    resourcegroup = request.form['resourcegroup']
    subscriptionId = request.form['subscriptionId']
    location = request.form['location']
    sku = request.form['sku']

    url = f'https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourcegroup}/providers/Microsoft.Storage/storageAccounts/{name}?api-version=2019-06-01'

    response = requests.request("PUT", url, headers=headers, data = payload)
    print(response.text)
    return response.text

Sign up to request clarification or add additional context in comments.

5 Comments

So with your code, and adding the methods to the app route I was able to get it to run with no errors BUT no resource is actually being created and I'm getting this as my response 127.0.0.1 - - [08/Apr/2020 22:57:05] "?[32mPOST /storageaccountcreate HTTP/1.1?[0m" 302 - Any Ideas?
Actually I was wrong - I wasn't paying attention and actually it's taking me back tot he login page so I'm guessing it's not taking the token or something.
127.0.0.1 - - [08/Apr/2020 23:30:41] "?[32mPOST /storageaccountcreate HTTP/1.1?[0m" 302 - 127.0.0.1 - - [08/Apr/2020 23:30:41] "?[37mGET /login HTTP/1.1?[0m" 200 - This is what happens when I run it the way you have it above. It redirects me to /login because as the code says if not token: return redirect(url_for("login")) But how can that be possible if token = _get_token_from_cache(["https://management.azure.com/user_impersonation"]) And I did check the app registration and it does have the user_impersonation role assigned to it.
@KyleMonteagudo could you please try to use print(token) to print token and copy access token and analyze it via jwt.ms?
I finally got it working! I realized part of my issue was within the SCOPE. After updating the scope and using the code you provided it worked. Thank so much!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.