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}]}}
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:
Replace:
$temp = 'HTTP_' . strtoupper(str_replace('-', '_', $header));
With:
$temp = ($header == 'Authorization') ? $header : 'HTTP_' . strtoupper(str_replace('-', '_', $header));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With