Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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}]}}

like image 880
Andrew Sumner Avatar asked Aug 09 '13 13:08

Andrew Sumner


1 Answers

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));
like image 140
Vivek Manglani Avatar answered Nov 12 '22 06:11

Vivek Manglani