How do I get (external) data into CakePHP with Security on? - php

I'm implementing the Rabo OmniKassa (which is a bit like Paypal) into a CakePHP application. I've read the Rabo manual, I tested it on an 'empty' project (without Security) and it all worked perfectly.
Now I'm implementing it in the actual application, and there are some problems with the data the Rabo OmniKassa sends back to my application -- which are caused by the Security component.
The Security component blocks the POST data the RaboKassa sends me, because it might be a threat to the application (external server inserting data etc...). It's returning a black hole.
When I just load the page without the redirect from the RaboKassa, it obviously loads, but since it has no POST data, it doesn't really do anything.
I've tried quite a few options I found on the internet like
$this->Components->disable('Security');
and
$this->Security->csrfCheck = false;
and
$this->Security->unlockedActions = array(
'kassareturn' // which is the function the RaboKassa has to return to
);
but none of them seem to work.
I can't seem to solve this problem, so is there anyone who's tried this or something similar before?
I can't alter the RaboKassa, so I have to receive the POST data...
I'm using CakePHP 2.1.3.

I'd recommend to always check the official docs first before you start trying stuff you find somewhere on the internet.
POST data validation needs to be disabled too
Besides the CSRF check there's also POST data validation. When receiving POST data from external sources you'll have to disable both checks.
$this->Security->csrfCheck = false;
$this->Security->validatePost = false;
And don't forget to make sure that you're disabling this only for your specific action!
public function beforeFilter() {
parent::beforeFilter();
if($this->request->params['action'] === 'kassareturn') {
$this->Security->csrfCheck = false;
$this->Security->validatePost = false;
}
}
See also
http://book.cakephp.org/.../core-libraries/components/security-component.html#usage
http://book.cakephp.org/.../security-component.html#SecurityComponent::$csrfCheck
http://book.cakephp.org/.../security-component.html#SecurityComponent::$validatePost
SecurityComponent::$unlockedActions as of CakePHP 2.3
I think you'll notice that using SecurityComponent::$unlockedActions will magically start working once you've updated your CakePHP installation to at least 2.3.x, as this feature is only available as of CakePHP 2.3
See also http://book.cakephp.org/...disabling-csrf-and-post-data-validation-for-specific-actions

Related

Laravel - Problem Of How To Tune Strange Behavior With Sending Text Message

I have a very special problem and I don't know how to deal with it.
I have web App in Laravel, when i open index page, I receive text message to my mobile phone.
Problem is, sometimes I receive 2 messages or 3, sometimes 1.
Is there a tool how to debug this strange behavior which is not always the same?
A few words about my code:
user opens the page, and because its first visit Session doesn't have attribute message_sent and SendTextMessage::SendMessage($phoneNumber, $id_message, $smsCode, $newDateFormat); is executed. After that Session has message_sent and can't be sent again, for example if I refresh the page.
SendTextMessage::SendMessage() is Class in Laravel Helpers.
controller code:
public function index($url_attribute, $id_message, Request $request)
{
if(!Session::has('message_sent'))
{
$user = User::where('id_message', $id_message)->first()->toArray();
$phoneNumber = $user['mobile_phone'];
$smsCode = $user['sms_code'];
$newDateFormat = date("d.m.yy", strtotime($smsExpirationTime));
$request->session()->flash('message', 'Text message sended.' );
SendTextMessage::SendMessage($phoneNumber,$id_message, $smsCode, $newDateFormat);
Session::put('message_sent', true);
}
return view('login');
}
SendTextMessage Class:
class SendTextMessage
{
public static function SendMessage($phoneNumber, $id_message, $smsCode, $newDateFormat)
{
$sms = new Connect();
$sms->Create("user","pass",Connect::AUTH_PLAIN);
$sms->Send_SMS($phoneNumber,"Message");
$sms->Logout();
}
}
Many thanks for any tip or help.
UPDATE:
problem is only in Chrome.
Edge and internet explorer are fine.
As this script runs on server-side the browser shouldn't be an issue. Based on your code provided, there is no clear answer to give here.
Please try the following in order to debug your problem:
Log messages at each stage of the script in order to see which part was called how often. That will help you to locate the problem. You can use \Log::error("Message") to do that.
Once you know where the problem might be, try to log "decision" making / mission critical variables to logile as well. E.g. \Log::error($session) so that you can understand why that problem might occur. One reason could be that you have a bad configured session caching or your cookies might be messed up. At some point there is probably a piece of data not the way you expect it to be.
You should maybe try to change the way you use Laravel Session.
You indicated that it was working fine on some browsers, that means your server-side code is correct so far, but there is someting messing with Chrome… From there,
if you take a quick look at the Laravel Session doc, you'll see that Session can be stored in cookies, and I bet that this is your actual setup (check in your .env file the SESSION_DRIVER constant, or in your config/session.php file).
If so, to confirm that this cookies-based session setting is the culprit, you might want to change the Session config to make it browser-independent: any other option than cookies will work, the database or file options might be the easier to setup… And if it works I would strongly encourage you to keep using this no-cookie setting to make your code browser-safe.

Facebook GraphAPI via another webpage php?

First: please forgive me - Im a bit of a novice as some of this...
I have a working test site which is running the php facebook SDK to perform some simple graphAPI requests successfully. Namely read a group's feed, which the user is a member of, and process this and display it back on a webpage.
This all works fine, the problem I have encountered is when trying to perform the same request via a php curl POST to another webpage (on the same domain). It seems that the SDK does not carry the expected session to another page when a post request is formed (see "AUTH ERROR2" in code)...this works fine when the following file is included via a "require_once" but not when a curl is made.
I would much rather do a "curl" as Im finding when a "require_once" is done from a page in a different directory level, Im getting php errors of the page not being found - which is expected.
I may just be tackling this problem all wrong...there may be a simpler way to make sure when files are includes, their correct directly level remains intact, or there may be a way to send over the currently authorised facebook sdk session via a curl post. All of which I have tried to no avail, and I would really appreciate any help or advise on this.
Thank you for your time.
//readGroupPosts.inc.php
function readGroupPosts($postVars)
{
//$access_token = $postVars[0];
// ^-- I'm presuming I need this? I have been experimenting appending it to
// the graphAPI request to no success...
$groupID = $postVars[1];
$limit = $postVars[2];
require_once("authFb.inc.php"); //link to the facebookSDK & other stuff
if ($user) {
try {
$groupFeed = $facebook->api("/$groupID/feed?limit=$limit"); //limit=0 returns all;
$groupFeed = $groupFeed['data']; //removes first tier of array for simpler access
$postArray;
for($i=0; $i<count($groupFeed); $i++)
{
$postArray[$i] = array($groupFeed[$i]['from']['name'], $groupFeed[$i]['message'], $groupFeed[$i]['updated_time'], count($groupFeed[$i]['likes']['data']));
}
return $postArray;
} catch (FacebookApiException $e) {
error_log($e);
$user = null;
return "AUTH ERROR1"; //for testing..
}
}
else
{
return "AUTH ERROR2"; //no user is authenticated i.e. $user == null..
}
}
I would much rather do a "curl" as Im finding when a "require_once" is done from a page in a different directory level, Im getting php errors of the page not being found - which is expected.
I may just be tackling this problem all wrong...
Definitively.
Using cURL as a “workaround” just because you’re not able to find your way around your server’s file system is an outrageous idea. Don’t do it. Stop even thinking about it. Now.
there may be a simpler way to make sure when files are includes, their correct directly level remains intact
Yes – for example, to use absolute paths instead of relative ones. Prefixing the path with the value of $_SERVER['DOCUMENT_ROOT'] for example – that way, once you’ve given the path correctly in respect to this “base path”, it does not matter where you’re requiring the file from, because an absolute path is the same no matter from where you look at it.
(And since this is not a Facebook-related problem at all, but just concerns basics of PHP and server-side programming, I’ll edit the tags.)

dojo crashes ie6 when using Zend Framework

I'm having issues with a application that I am writing that uses Dojo and Zend Framework. The issue only effects Internet Explorer 6, other versions of IE, ff, chrome and safari work fine with no issues.
When IE6 lands on the login page it crashes with the send details to microsoft dialog box. The login script uses dojo to provide some validation for the users to ensure that their passwords are formatted correctly etc.
I've seen on some forums that addOnLoad() function call in dojo could be the cause and a window.setTimeout() would help. http://www.dojotoolkit.org/forum/dojo-core-dojo-0-9/dojo-core-support/dom-manipulation-addonload-crashes-ie6
The problem I have is how to manipulate the dojo header that we have in the layout.phtml in the application. We currently have in the file this code in the header.
<?php
$this->dojo()->setLocalPath($this->baseUrl().'/javascript/dojo/dojo.js');
$this->dojo()->addStylesheetModule('dijit.themes.tundra');
echo $this->dojo();
?>
This produces the following in the html.
dojo.require("dijit.form.ValidationTextBox");
dojo.require("dijit.form.Button");
dojo.require("dojo.parser");
dojo.addOnLoad(function() {
dojo.forEach(zendDijits, function(info) {
var n = dojo.byId(info.id);
if (null != n) {
dojo.attr(n, dojo.mixin({ id: info.id }, info.params));
}
});
dojo.parser.parse();
});
var zendDijits = [{"id":"username","params":{"regExp":"[a-z0-9_\\+-]+(\\.[a-z0-9_\\+-]+)*#[a-z0-9-]+(\\.[a-z0-9-]+)*\\.([a-z]{2,4})$","invalidMessage":"Please enter a valid email address","trim":"true","required":"true","dojoType":"dijit.form.ValidationTextBox"}},{"id":"password1","params":{"trim":"true","lowercase":"true","regExp":"^.*(?=.{6,})(?=.*\\d)(?=.*[a-zA-Z]).*$","invalidMessage":"Invalid Password. Password must be at least 6 alphanumeric characters","required":"true","dojoType":"dijit.form.ValidationTextBox"}},{"id":"submit","params":{"label":"Login","dojoType":"dijit.form.Button"}}];
How can I change this to try and add the fixes mentioned in the link, or is there another way to write this without IE6 crashing all the time?? I would prefer to fix this than remove all the client validation, just in case the client is using IE6.
thanks...
Can you reduce it down until you find what is crashing IE6? Save off your output as static html, confirm it still crashes IE and start removing code. Take that addOnLoad out altogether - does it still crash? if not, take out the forEach, and so on. Start removing elements from zendDijits array - is there one in particular that causes the trouble?
Is this a stock IE6? Any plugins/addons?
Your php there should be producing a script element to pull dojo.js. You've got soemthing wierd going on - that Zend code is known to work so we need all the information if you want to solve this.

How do I implement Direct Identity based OpenID authentication with Zend OpenID

I'm using the Zend framework and the openid selector from http://code.google.com/p/openid-selector/ - however I find I can't login using sites like Google and Yahoo as they use direct identity based login system whereby one is just redirected to a url as opposed to entering a unique url of their own for authentication.
I've checked out many options and hacks but none of them seem to work. How can i get this to work here btw - how is it implemented at stack overflow? I could really use all the help here guys..
Edit
Well the issue here is that from what I have noticed is that the Zend OpenID class doesn't support OpenID 2.0 the thing is that a typical open ID providor gives you a unique url such as your-name.openid-providor.com or openid-providor.com/your-name and the Zend OpenId class just parses through that url and then redirects you to the providor website where upon authentication you are redirected back.
In the case of Yahoo and google - you don't enter a unique url instead you are redirected to the providors login site and upon login and authentication you are redirected back - so basically whats happeining is that the zend_openID object when it parses to tell who the providor is it fails to tell from the general url itself. Like when you click on teh Google link it redirects you to https://www.google.com/accounts/o8/id
Its more an issue with the zend openid object here and there isn't any help on zend related forums - so I was wondering if someone had already hacked or had an alteration I could make to the class to accomplish this. Sorry if I'm missing something but I'm kinda new to this and programming with open ID and have just started to get my feet wet.
Thanks for the follow up - I did check into RPX a while back and they do have a php class but I wasnt able to check it out plus I really just want to for now get the code selector used as on stackoverflow to work with Yahoo and Google authentication. There has to be some kind of way to tweak the parsing which the Zend OpenID class uses as it runs a series of regular expression checks to make a discovery.
Little late to the game but I was able to get this working with some hacks I found around the interwebs.
First. Yahoo. To get Yahoo working all I had to do was change the JavaScript to use me.yahoo.com instead of just yahoo.com and it worked perfectly with the version of the Zend Framework I'm using. Unfortunately Google still wasn't, so some hacking was in order.
All of these changes go in Zend/OpenId/Consumer.php
First, in the _discovery method add the following on the series of preg_match checks that starts at around line 740.
} else if (preg_match('/<URI>([^<]+)<\/URI>/i', $response, $r)) {
$version = 2.0;
$server = $r[1];
I added this right before the return false; statement that's in the else {} block.
Second, in the _checkId method you'll need to add 3 new blocks (I haven't dug around enough to know what causes each of these three cases to be called, so I covered all to be on the safe side.
Inside the $version <= 2.0 block, you'll find an if/else if/else block. In the first if statement ($this->_session !== null) add this to the end:
if ($server == 'https://www.google.com/accounts/o8/ud') {
$this->_session->identity = 'http://specs.openid.net/auth/2.0/identifier_select';
$this->_session->claimed_id = 'http://specs.openid.net/auth/2.0/identifier_select';
}
In the else if (defined('SID') block add this to the end:
if ($server == 'https://www.google.com/accounts/o8/ud') {
$_SESSION['zend_openid']['identity'] = 'http://specs.openid.net/auth/2.0/identifier_select';
$_SESSION['zend_openid']['claimed_id'] = 'http://specs.openid.net/auth/2.0/identifier_select';
}
And then after the else block (so outside the if/else if/else block all together, but still inside the $version <= 2.0 block) add this:
if ($server == 'https://www.google.com/accounts/o8/ud') {
$params['openid.identity'] = 'http://specs.openid.net/auth/2.0/identifier_select';
$params['openid.claimed_id'] = 'http://specs.openid.net/auth/2.0/identifier_select';
}
Link to the bug in Zend Framework Issue Tracker
I need to use Google's OpenID stuff, and I tried Steven's code and couldn't get it to work as-is. I've made some modifications.
The _discovery change method is still the same:
Zend/OpenId/Consumer.php, line 765, add:
} else if (preg_match('/<URI>([^<]+)<\/URI>/i', $response, $r)) {
$version = 2.0;
$server = $r[1];
The rest is different, though:
Zend/OpenId/Consumer.php, line 859 (after making the above change), add:
if (stristr($server, 'https://www.google.com/') !== false) {
$id = 'http://specs.openid.net/auth/2.0/identifier_select';
$claimedId = 'http://specs.openid.net/auth/2.0/identifier_select';
}
This is right before:
$params['openid.identity'] = $id;
$params['openid.claimed_id'] = $claimedId;
And to get it to return the ID, once authorized:
Zend/Auth/Adapter/OpenId.php, line 278:
if(isset($_REQUEST['openid_identity']))
{
$this->_id = $_REQUEST['openid_identity'];
$id = $this->_id;
}
This is right before:
return new Zend_Auth_Result(
Zend_Auth_Result::SUCCESS,
$id,
array("Authentication successful"));
Note that I have not thoroughly tested this code. The code below is even more shakey.
I have spent more time and I've gotten it to work with my Google Apps domain with the following changes, in addition to the above:
Zend/OpenId/Consumer.php, line 734
$discovery_url = $id;
if(strpos($discovery_url, '/', strpos($discovery_url, '//')+2) !== false) {
$discovery_url = substr($discovery_url, 0, strpos($discovery_url, '/', strpos($discovery_url, '//')+2));
}
$discovery_url .= '/.well-known/host-meta';
$response = $this->_httpRequest($discovery_url, 'GET', array(), $status);
if ($status === 200 && is_string($response)) {
if (preg_match('/Link: <([^><]+)>/i', $response, $r)) {
$id = $r[1];
}
}
This is right after:
/* TODO: OpenID 2.0 (7.3) XRI and Yadis discovery */
I believe that was the only change I had to make. I'm pretty sure there's supposed to be some checking involved with the above for security reasons, but I haven't looked far enough into it to see what they would be.
Going over all the advice provided - I've decided to ditch using the zend_openid class [ sorry about that zend ] and instead I've switched to using JanRains OpenID library. Its taken a few hours to get it up and running with my project but atleast its working like a breeze. Had to make a lot of hacking and a bit of code spill over to get it working but its worth it.
I couldn't use any of Zend adapters with Zend-Auth to settle this new code library in as the library did the authentication on its own. SO I hacked and made a generic adapter that just returned a filled zend_result set to the Auth object thus I authenticate using my library and merely store the result in the Auth object pulling a bit of a fast one one the Zend-Auth object rather than have to rewrite my code again.
The library is available at http://openidenabled.com/php-openid/
Thanks for all the help guys.
I'm dealing with similar issues. I'm planning on using RPX now with Zend Framework. Maybe I'll write an adapter. Just to let you know.
Info: 'RPS now' provides an all-in-one interface and UI for user registration with
facebook
Google
Yahoo
mySpaceID
Windows LiveID
OpenID
aol
I'm pretty sure that Yahoo only works with OpenID 2.0. If you want to support Yahoo users, you're going to have to upgrade to a library with 2.0 support. That's going to be a matter of more than tweaking some parsing.
Did you check out the manual -- Zend_OpenId_Consumer basics? Check out 38.2.2 on that page and let me know if this helps, because it should.
Specifically, I don't know if Google offers OpenID. I know that Yahoo worked because I've tried it a while back.
Thanks for the information. I started by using JanRain's library, but I have problems with getting Simple Registration to work: I have not succeeded in getting any data that way. And there is no documentation on using Attribute Exchange. :(
So, I found and was trying Zend/OpenId, but had the same problem as you: no Yahoo!, Google and who knows what else support. Reading this, it seems I'll have to get back to JanRain; RPX is not an option in my case as it's a third party service.

How can I implement jquery in my Zend Framework application in a custom manner?

How can I implement jquery in my Zend Framework application in a custom manner.
appending jquery.js ok
appending script ok
send POST data to controller ok
process POSTed data ok
send 'AjaxContext' respond to client now ok (thanks)
I'm using jquery for the first time, what am I doing wrong?
Early on, the best practice to get Zend to respond to ajax requests without the full layout was to check a variable made available via request headers. According to the documentation many client side libraries including jQuery, Prototype, Yahoo UI, MockiKit all send the the right header for this to work.
if($this->_request->isXmlHttpRequest())
{
//The request was made with via ajax
}
However, modern practice, and what you're likely looking for, is now to use one of two new helpers:
ContextSwitcher
AjaxContent
Which make the process considerably more elegant.
class CommentController extends Zend_Controller_Action
{
public function init()
{
$ajaxContext = $this->_helper->getHelper('AjaxContext');
$ajaxContext->addActionContext('view', 'html')
->initContext();
}
public function viewAction()
{
// Pull a single comment to view.
// When AjaxContext detected, uses the comment/view.ajax.phtml
// view script.
}
Please Note: This modern approach requires that you request a format in order for the context to be triggered. It's not made very obvious in the documentation and is somewhat confusing when you end up just getting strange results in the browser.
/url/path?format=html
Hopefully there's a workaround we can discover. Check out the full documentation for more details.
Make sure your using $(document).ready() for any jQuery events that touch the DOM. Also, check the javascript/parser error console. In Firefox it's located in Tools->Error Console. And if you don't already have it installed, I would highly recommend Firebug.
This should have been a comment, can't, yet...
It has nothing to do with ZF+Jquery combination.
First try a proto of what you need with a simple php file. No framework, just Jquery and straight forward, dirty php.
Oh, and don't forget to track what happens with FireBug.

Categories