Magento REST API, User given admin role but only granted Guest access
Asked Answered
B

2

7

I'm writing an app in python that accesses a Magento server using OAuth/REST etc.

The OAuth authentication has been completed, I have the two consumer tokens & the 2 access tokens. Within Magento itself I've followed the configuration steps outlined in numerous blogs - setting up the REST Roles, Attributes & Consumers, and the User Permissions & Roles. I've been over it 500 times (it feels that way!) and can't see any errors, the user's using the REST consumer which has authorized tokens, the user's role is Administrator, so on & so forth.

I noticed something was wrong when, after completing the OAuth process, I tried to post a product to Magento (its database is empty) and received a 403 Access Denied. A Get attempt received the same. I enabled REST API access for Guest, and now the Get receives an empty json array and of course the Post still has the 403 - this tells me that Magento isn't looking at the OAuth tokens and logging me in.

It seems that Magento is refusing to accept the consumer/access tokens that it generated during the OAuth authentication process.

Is there a configuration step I've missed, or any info at all that'll provide a way past this roadblock?

Edit: Code snippet added below showing the method I'm using to query Magento:-

from rauth.session import OAuth1Session
session = OAuth1Session(consumer_key, consumer_secret, access_key, access_secret)
headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
r = session.get('http://mysite.com/api/rest/products', headers=headers)
print r.json()

Outputs: {u'messages': {u'error': [{u'message': u'Access denied', u'code': 403}]}}

Beetner answered 9/8, 2013 at 13:45 Comment(0)
B
4

I was unable to find a solution using the rauth library as shown in the example above, but was able to get it working using oauthlib/requests_oauthlib as follows:-

from requests_oauthlib import OAuth1 as OAuth
import requests
oauth = OAuth(client_key=consumer_key, client_secret=consumer_secret, resource_owner_key=access_key, resource_owner_secret=access_secret)
h = {'Content-Type': 'application/json', 'Accept': 'application/json'}
r = requests.get(url='http://mysite.com/api/rest/products', headers=h, auth=oauth)
print r
print r.content

print r produces "< Response [200] >", and r.content contains the json-formatted list of products.

I'm surmising that rauth was incorrectly calculating the nonce value or perhaps the encoding was off - something in the request it produced was upsetting Magento, which was therefore refusing to grant access.

Beetner answered 10/8, 2013 at 6:45 Comment(0)
H
5

After hours of pondering over this problem i finally realized why some of us get the following error:

Invalid auth/bad request (got a 403, expected HTTP/1.1 20X or a redirect) 
{"messages":{"error":[{"code":403,"message":"Access denied"}]}}

Even after successfully authorizing admin/customer.

The problem unfortunately is not with Magento but could very likely be your server configuration.

I started looking into the Magento Api2 code and realized that they were making use of Zend_Controller_Request_Http method "getHeader" to check for the oAuth authorization.

The following is the code for "getHeader()"

public function getHeader($header)
{
    if (empty($header)) {
        #require_once 'Zend/Controller/Request/Exception.php';
        throw new Zend_Controller_Request_Exception('An HTTP header name is required');
    }

    // Try to get it from the $_SERVER array first
    $temp = 'HTTP_' . strtoupper(str_replace('-', '_', $header));
    if (isset($_SERVER[$temp])) {
        return $_SERVER[$temp];
    }

    // This seems to be the only way to get the Authorization header on
    // Apache
    if (function_exists('apache_request_headers')) {
        $headers = apache_request_headers();
        if (isset($headers[$header])) {
            return $headers[$header];
        }
        $header = strtolower($header);
        foreach ($headers as $key => $value) {
            if (strtolower($key) == $header) {
                return $value;
            }
        }
    }

    return false;
}

Passed to this function by Magento class "Mage_Api2_Model_Auth_Adapter_Oauth" is:

public function isApplicableToRequest(Mage_Api2_Model_Request $request)
{
    $headerValue = $request->getHeader('Authorization');

    return $headerValue && 'oauth' === strtolower(substr($headerValue, 0, 5));
}

Since "$request->getHeader('Authorization') is being called, that means the $header var in the getHeader function is "Authorization"

// Try to get it from the $_SERVER array first
$temp = 'HTTP_' . strtoupper(str_replace('-', '_', $header));
if (isset($_SERVER[$temp])) {
    return $_SERVER[$temp];
}

The Zend class then converts "Authorization" to "HTTP_AUTHORIZATION" and looks for it in the $_SERVER array, this is where the problem lies because in that array the Authorization values are located in "$_SERVER['Authorization']" not "$_SERVER['HTTP_AUTHORIZATION"]", they do this because other variables such as CONTENT_TYPE is stored as HTTP_CONTENT_TYPE, except Authorization.

However, it seems as though Zend is aware of this and hence they've written the following code:

// This seems to be the only way to get the Authorization header on
// Apache
if (function_exists('apache_request_headers')) {
    $headers = apache_request_headers();
    if (isset($headers[$header])) {
        return $headers[$header];
    }
    $header = strtolower($header);
    foreach ($headers as $key => $value) {
        if (strtolower($key) == $header) {
            return $value;
        }
    }
}

The problem here is that many servers out there do not enable "apache_request_headers", if you are facing this problem it is likely that your hosting company has "apache_request_headers" disabled.

There are 2 solutions here:

  1. Contact your host and ask them to enable "apache_request_headers".
  2. Modify the getHeader($header) function in Zend_Controller_Request_Http class

Replace:

$temp = 'HTTP_' . strtoupper(str_replace('-', '_', $header));

With:

$temp = ($header == 'Authorization') ? $header : 'HTTP_' . strtoupper(str_replace('-', '_', $header));
Haft answered 5/9, 2013 at 4:23 Comment(1)
This is golden! 7 years later I still had the same issue, was getting 403 Forbidden from the Magento REST API out of nowhere and this has solved it for me, thanks!Shanklin
B
4

I was unable to find a solution using the rauth library as shown in the example above, but was able to get it working using oauthlib/requests_oauthlib as follows:-

from requests_oauthlib import OAuth1 as OAuth
import requests
oauth = OAuth(client_key=consumer_key, client_secret=consumer_secret, resource_owner_key=access_key, resource_owner_secret=access_secret)
h = {'Content-Type': 'application/json', 'Accept': 'application/json'}
r = requests.get(url='http://mysite.com/api/rest/products', headers=h, auth=oauth)
print r
print r.content

print r produces "< Response [200] >", and r.content contains the json-formatted list of products.

I'm surmising that rauth was incorrectly calculating the nonce value or perhaps the encoding was off - something in the request it produced was upsetting Magento, which was therefore refusing to grant access.

Beetner answered 10/8, 2013 at 6:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.