Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shopware REST Api - Invalid or missing auth

I'm trying to access the REST api of Shopware. I'm using version 5.1.3 of Shopware. I'm using the code of the documentation.

I always get a http code 400 (Invalid or missing auth) back.

When I try to access the API via Google Chrome it works after login with http authentication, so the credentials should be OK.

I guess the Authentication header Chrome sends differs from the one I send with PHP curl.

With Chrome:

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip, deflate, sdch
Accept-Language:nl-NL,nl;q=0.8,en-US;q=0.6,en;q=0.4
Authorization:Digest username="demo", realm="Shopware REST-API", nonce="7aa6aa7e8089c60e5930cb45ead39197", uri="/api/articles", algorithm=MD5, response="cee77e425508605dfbcf2deda8f83938", opaque="d75db7b160fe72d1346d2bd1f67bfd10", qop=auth, nc=0000001e, cnonce="8b5121e862c4fce1"
Cache-Control:max-age=0
Connection:keep-alive
Cookie:session-1=2d0cb2941684d2767e76ffeb48c7337706cba39c
Host:shopware.example.com
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36

With PHP Curl

GET /api/articles? HTTP/1.1\r\n
Host: shopware.example.com\r\n
Authorization: Digest username="demo",realm="",nonce="806c9770a53bf2f82b87734a9d8eb98c",uri="/api/articles?",cnonce="60e6c8db046db8f4e63fece37e38f92e",nc=00000001,algorithm=MD5,response="299069d4659af386a4ec7058796267c2",qop="auth",opaque="d75db7b160fe72d1346d2bd1f67bfd10"\r\n
User-Agent: Shopware shopwareApiClient\r\n
Accept: */*\r\n
Content-Type: application/json; charset=utf-8\r\n
Content-Length: 2\r\n

Extra PHP curl directives to get header information:

curl_setopt($this->cURL, CURLINFO_HEADER_OUT, true);
print_r(curl_getinfo($this->cURL, CURLINFO_HEADER_OUT ));

The code I use:

<?php

namespace App;

class shopwareApiClient
{

    const METHOD_GET = 'GET';
    const METHOD_PUT = 'PUT';
    const METHOD_POST = 'POST';
    const METHOD_DELETE = 'DELETE';

    protected $validMethods = array(
        self::METHOD_GET,
        self::METHOD_PUT,
        self::METHOD_POST,
        self::METHOD_DELETE
    );
    protected $apiUrl;
    protected $cURL;

    public function __construct($apiUrl, $username, $apiKey)
    {
        $this->apiUrl = rtrim($apiUrl, '/') . '/';
        //Initializes the cURL instance
        $this->cURL = curl_init();
        curl_setopt($this->cURL, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($this->cURL, CURLOPT_FOLLOWLOCATION, false);
        curl_setopt($this->cURL, CURLOPT_USERAGENT, 'Shopware shopwareApiClient');
        curl_setopt($this->cURL, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
        curl_setopt($this->cURL, CURLOPT_USERPWD, $username . ':' . $apiKey);
        curl_setopt($this->cURL, CURLOPT_HTTPHEADER, array(
            'Content-Type: application/json; charset=utf-8',
        ));
        curl_setopt($this->cURL, CURLINFO_HEADER_OUT, true);
    }

    public function call($url, $method = self::METHOD_GET, $data = array(), $params = array())
    {
        if (!in_array($method, $this->validMethods))
        {
            throw new Exception('Invalid HTTP-Methode: ' . $method);
        }
        $queryString = '';
        if (!empty($params))
        {
            $queryString = http_build_query($params);
        }
        $url = rtrim($url, '?') . '?';
        $url = $this->apiUrl . $url . $queryString;
        $dataString = json_encode($data);
        curl_setopt($this->cURL, CURLOPT_URL, $url);
        curl_setopt($this->cURL, CURLOPT_CUSTOMREQUEST, $method);
        curl_setopt($this->cURL, CURLOPT_POSTFIELDS, $dataString);
        $result = curl_exec($this->cURL);
        dd(curl_getinfo($this->cURL, CURLINFO_HEADER_OUT ));
        $httpCode = curl_getinfo($this->cURL, CURLINFO_HTTP_CODE);
        return $this->prepareResponse($result, $httpCode);
    }

    public function get($url, $params = array())
    {
        return $this->call($url, self::METHOD_GET, array(), $params);
    }

    public function post($url, $data = array(), $params = array())
    {
        return $this->call($url, self::METHOD_POST, $data, $params);
    }

    public function put($url, $data = array(), $params = array())
    {
        return $this->call($url, self::METHOD_PUT, $data, $params);
    }

    public function delete($url, $params = array())
    {
        return $this->call($url, self::METHOD_DELETE, array(), $params);
    }

    protected function prepareResponse($result, $httpCode)
    {
        echo "<h2>HTTP: $httpCode</h2>";
        if (null === $decodedResult = json_decode($result, true))
        {
            $jsonErrors = array(
                JSON_ERROR_NONE => 'No error occurred',
                JSON_ERROR_DEPTH => 'The maximum stack depth has been reached',
                JSON_ERROR_CTRL_CHAR => 'Control character issue, maybe wrong encoded',
                JSON_ERROR_SYNTAX => 'Syntaxerror',
            );
            echo "<h2>Could not decode json</h2>";
            echo "json_last_error: " . $jsonErrors[json_last_error()];
            echo "<br>Raw:<br>";
            echo "<pre>" . print_r($result, true) . "</pre>";
            return;
        }
        if (!isset($decodedResult['success']))
        {
            echo "Invalid Response";
            return;
        }
        if (!$decodedResult['success'])
        {
            echo "<h2>No Success</h2>";
            echo "<p>" . $decodedResult['message'] . "</p>";
            return;
        }
        echo "<h2>Success</h2>";
        if (isset($decodedResult['data']))
        {
            echo "<pre>" . print_r($decodedResult['data'], true) . "</pre>";
        }
        return $decodedResult;
    }
}

Edit: Found a php bug report which states there is a bug in PHP with Windows on version 5.6 and above. I'm using XAMP on Windows. I'm going to try it on linux to see if it does work.

like image 418
blablabla Avatar asked Sep 25 '22 05:09

blablabla


1 Answers

The bug report was correct. I was using XAMP with PHP 5.6 on Windows.

After putting my PHP code on a linux machine, the code works.

Quote bug report:

[2015-07-19 09:51 UTC] roeycohen at gmail dot com

Description:

trying to use curl_exec with digest authentication does not work properly. running the test script always fails to pass the security challenge. using the browser or wget directly works perfectly.

also, trying to run the same test on another server of mine, works from an amazon linux with php 5.5.21 but does not work from my windows 7 x64 machine with php 5.6.11.

trying to run the test with php 5.5 or 5.4 using CLI on several windows machines caused a complete crush of the php executable.

it seems like bug #69088 is related, but this bug also happens on linux (5.5).

Test script:

<?
$curl = curl_init();

$curl_options = [
    CURLOPT_HTTPAUTH => CURLAUTH_ANY,

    CURLOPT_USERPWD => 'test_user:password',
    CURLOPT_URL => 'http://test_user:[email protected]/digest-auth/auth/user/password',
    CURLOPT_HEADER => true,
];
curl_setopt_array($curl, $curl_options);

curl_exec($curl);
curl_close($curl);

Expected result:

{
  "authenticated": true, 
  "user": "user"
}

Actual result:

"Authentication failed" (with header 401)

[2015-12-28 16:33 UTC] gohel at basicguru dot de

I have the same problem with PHP-clients/scripts and the CalDAV/SabreDAV-framework (also included in Owncloud, Baikal, etc.) on my Apache 2.4.17 (Win32/VC11 from Apachelounge on Win7/64).

I've played a little bit with different versions of the PHP 5.6.x releases and found the following:

  • php_curl.dll <= v5.6.4 - no problems
  • php_curl.dll v5.6.5/v5.6.6 - crash with Auth_Digest
  • php_curl.dll => v5.6.7 - Auth_Digest failed

The bug is also in the PHP 5.5 release and PHP 5.4 (last stable PHP_CURL.DLL I've found in v5.4.36)

like image 50
blablabla Avatar answered Nov 15 '22 11:11

blablabla