2

I'm using CakePHP as backend and AngularJS as frontend, whereas front- & backend are in different domains so this is basically a CORS-situation.

Basically I'm trying to send the contents of a form to a Cake-API (later this is meant to do authentication part - but I'm failing earlier) via $http.post. So here is the code:

aeapBackend.login = function(username, password) {
    return $http.post(
        API_URL + 'api_mobile_user/login', {
            test: username,
            test2: password
        }
    );
};

Whereas the corresponding API in CakePHP looks like this:

function beforeFilter() {
    parent::beforeFilter();
    $this->Auth->allow(array('login'));
}

public function login() {
    $this->response->header(array(
            'Access-Control-Allow-Origin' => '*',
            'Access-Control-Allow-Headers' => 'Content-Type'
        )
    );

    $this->autoRender = false;
}

What happens next is that the preflight OPTIONS request ist done - which looks quite good to me:

Request Headers:

OPTIONS /api_mobile_user/login HTTP/1.1
Host: aeap.localhost
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: http://asf.localhost
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X; en-us) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53
Access-Control-Request-Headers: accept, content-type
Accept: */*
Referer: http://asf.localhost/?username_input=hjk&password_input=hjgk&login_button=
Accept-Encoding: gzip,deflate,sdch
Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4

Response headers:

HTTP/1.1 200 OK
Date: Wed, 05 Nov 2014 15:29:00 GMT
Server: Apache/2.4.10 (Win32) OpenSSL/1.0.1i PHP/5.5.15
X-Powered-By: PHP/5.5.15
Set-Cookie: CAKEPHP=j6st0hnq8ear2cc6psg56d6eu3; expires=Wed, 05-Nov-2014 19:29:00 GMT; Max-Age=14400; path=/; HttpOnly
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type
Content-Length: 0
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=UTF-8

But when the actual POST-request is done I get an status code 403:

XMLHttpRequest cannot load http://aeap.localhost/api_mobile_user/login. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://asf.localhost' is therefore not allowed access. The response had HTTP status code 403. 

How can I avoid this? In my opinion I already enabled CORS support for Cake ['Access-Control-Allow-Origin']. It seems to me that AngularJS posts some additional informations whioch are not checked during the preflight and then rejected by the backend.

Used versions: CakePHP 2.5.3, AngularJS: 1.3.0

icc97
  • 11,395
  • 8
  • 76
  • 90
Nikel Weis
  • 724
  • 10
  • 27
  • 2
    I have 0 experience in CakePHP, but can it be your server code to add the headers is only ran when an "OPTIONS" (preflight) comes in? Also, which headers are you sending? are they all in the list of "default HTTP headers" or your explicitly configured "content-type"? – Marvin Smit Nov 05 '14 at 15:43
  • @MarvinSmit: "content-type" is explictly set ('Access-Control-Allow-Headers' => 'Content-Type') otherwise the preflight would fail. When I use $http.get I've no difficulties getting data from the backend so I assume that the headers are not just set during the preflight. Thanks for the remark anyway - I'll double check this. – Nikel Weis Nov 05 '14 at 15:48
  • 1
    What i meant with the headers is that; A good CORS implementation will return a 401/403 if a header is send with the POST which is not in it's 'valid headers for CORS' list. The preflight allows you to see if the headers you will send with the actual POST are allowed (using the "request-headers" ->responded to by CORS implementation with "allowed-headers"). Any header send in the post outside the "allowed-headers" or "default HTTP headers" (according to CORS spec) should cause a 'deny access'. – Marvin Smit Nov 05 '14 at 15:59

2 Answers2

2

Thanks to Marvin Smit I was able to determine the reason for the behavior which was not connected to CORS are the headers. I set 'Access-Control-Allow-Origin' => '*'on web-server level so I was able to get a response which pointed to the security component of CakePHP.

I basically tried to send a POST-Reuqest to an API which did not expect that data should be posted to it. Therefore the access was denied. So I had to add $this->Security->csrfCheck = false to the beforeFilter:

function beforeFilter() {
    parent::beforeFilter();
    $this->Auth->allow(array('login'));
    $this->Security->csrfCheck = false;
}
Nikel Weis
  • 724
  • 10
  • 27
0

For what it's worth, the proper way to do this for Cakephp 3 is as follows

public function beforeFilter() {
    parent::beforeFilter();
    $this->Auth->allow(array('login'));
    $this->eventManager()->off($this->Csrf);
}

Although, this is not recommended for AJAX requests. The following doc can help you more. CSRF And AJAX

T73 Biz
  • 1
  • 1