Setup and information to reproduce the problem
Symfony2.2 application
LiipFunctionalTestBundle
DoctrineFixturesBundle
FOSUserBundle
For testing enviroment I use LiipFunctionalTestBundle and generate (from DoctrineFixtures) a fake SQLite database. It's configured correctly - I've been able to succesfully test my non-secured pages.
I've created a simple secured page under /secured/test with this view:
<h2 class="username">{{ app.user.username }}</h2>
I've tried with
http://symfony.com/doc/master/cookbook/testing/http_authentication.html
And I wanted to test this action with this assertion:
$client = static::createClient(array(), array(
'PHP_AUTH_USER' => 'myUserName'
'PHP_AUTH_PW' => 'password',
));
$crawler = $client->request('GET', '/secured/test');
$count = $crawler
->filter('h2.username:contains("myUserName")')
->count();
$this->assertTrue($count > 0);
The result was Failed asserting that false is true.
I've tried with
http://symfony.com/doc/master/cookbook/testing/simulating_authentication.html
And I wanted to test this action with this assertion:
$this->logIn();
$crawler = $this->client->request('GET', '/secured/test');
$count = $crawler
->filter('h2.username:contains("myUserName")')
->count();
$this->assertTrue($count > 0);
Ofcourse I changed the logIn function to diffrent username.
The result was Failed asserting that false is true.
None of these works. Whats wrong?
I've tried many other methods, but
The solution to the problem was very simple:
In my DoctrineFixtures I've created new users.. but their accounts were not enabled.
Adding this code to fixture solved the problem:
$user->setEnabled(true);
$user->setExpired(false);
$user->setLocked(false);
(becouse my test was trying to log on not enabled account, the response to "submit login form" was redirect to login page)
Related
I'm working on a project that need to call a API to get json response, but the Guzzle client auth is not working. It always redirect to the login page.
"nasa" is the database.
Here's my code:
<?php
require_once '../composer/vendor/autoload.php';
use GuzzleHttp\Client;
$client = new Client([
'base_url' => ['http://fedview.bfountain.com/{datasource}/', ['datasource' => 'nasa']]]);
$response = $client->get('service/sbapp/goalByAgency', ['auth' => ['username', 'password']]);
echo $response->getBody();
?>
I tried:
$response = $client->get('login.do?uname=username&passcode=password');
It can log in successfully.
Can anyone help me on this? (I'm using Guzzle 5) THX!
Here is the WHY - logic of what happens I will have to leave the rest of troubleshooting for you.
1) echo $response->getBody(); // prints out the login page "It always redirect to the login page"
2) $response = $client->get('service/sbapp/goalByAgency', ['auth' => ['username', 'password']]); // your $response is a login page because you ask $client->get the login page or authenticate page
3) You need to authenticate successfully for a $client
4) Then use the $client to request data via POST method (you missed this step)
see my other post: How can I use Guzzle to send a POST request in JSON?
redo your code. you are on the right track.
Front end is 100% JS. User click on sign in button and an authResult['code'] is received and send via ajax to localhost/api/user/login which has the following content:
$code = $data['code'];
require_once 'Google/Client.php';
$client = new Google_Client();
$client->setClientId('xxxxxx');
$client->setClientSecret('xxxxx');
$client->setRedirectUri('http://localhost:8080');
$client->setScopes('email'); //Why do I need this? I already set scope in JS.
$client->authenticate($code); //It fails here. with no error. just 400 bad request.
$token = json_decode($client->getAccessToken());
$reqUrl = 'https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=' .
$token->access_token;
$req = new Google_HttpRequest($reqUrl);
$tokenInfo = json_decode(
$client::getIo()->authenticatedRequest($req)->getResponseBody());
//Check errors.
//Save user personal info in database
//Set login sessions
Why do I need to set scopes if I already set them in javascript?
Why is it failing when authenticate function is called? Im getting no erros.
Why do I need a setRedirectUri() when it is on the backend?
You don't need to set scopes in this case.
(see answer 3, but also): Check your client ID matches the one used in the Javascript, and that the client secret is exactly as in the console (no trailing/leading spaces).
Changing your redirecturi to 'postmessage' - this is the string used when the code was generated via the Javascript process.
You can also try manually constructing the URL and calling it with curl to make sure everything is as you expect: https://developers.google.com/accounts/docs/OAuth2WebServer#handlingtheresponse
I am creating a basic Facebook app, and when a user without permission visits the app, they are redirected to the authorisation page. However, the page doesn't display, and I see the following error.
This content cannot be displayed in a frame
Opening it in a new window then shows the authorisation page for my app. Clicking 'Go to App' then takes me to the App, but in it's own window, away from Facebook. Going back to FB and reloding the App page now works.
Stranger yet, when I am logged out and go to my app page, I get a Facebook 404 page (4oh4.php).
I'm guessing that I am doing this wrong somehow, so can anyone see anything obvious wrong with my script? Thanks.
To see what is happening - http://apps.facebook.com/dyne_drewett_news/
<?php
require 'fb/facebook.php';
$fbconfig['appUrl'] = 'my-app-url'; // Create An instance of our Facebook Application.
$facebook = new Facebook(array(
'appId' => 'my-app-ID', // Entered correctly in actual script
'secret' => 'me-app-secret', // Entered correctly in actual script
'cookies' => 'true',
));
// Get the app User ID
$user = $facebook->getUser();
if($user) :
try{ // If the user has been authenticated then proceed
$user_profile = $facebook->api('/me');
} catch (FacebookApiException $e){
error_log($e);
$user = null;
}
endif;
// If the user is authenticated then generate the variable for the logout URL
if($user) :
$logoutUrl = $facebook->getLogoutUrl();
?>
<!-- My HTML goes here -->
<?php
else :
$loginUrl = $facebook->getLoginUrl();
header('Location: '.$loginUrl);
endif;
?>
Because you are working in an iframe, you'll have to execute JavaScript redirects. Only that way will you be able to redirect the top most frame -
echo "<script language=javascript>";
echo "top.location.href ='".$url."';";
echo "</script>";
exit();
This is the only way to do complete redirects within a Facebook application. Any other redirect (with PHP for example) will only redirect the user within the iframe...
I can use the following code to redirect a user back to the page my app is installed on using the following code:
$facebook = new Facebook(array(
'appId' => $app_id,
'secret' => $app_secret,
'cookie' => true
));
$signed_request = $facebook->getSignedRequest();
$page = $signed_request['page'];
$page_id = $page['id'];
$page_array = $facebook->api("/$page_id");
$page_link = $page_array['page_link'];
$redirect_uri = $page_link . '?sk=app_' . $app_id
$user = $facebook->getUser();
if(!$user) {
$url = $facebook->getLoginUrl(array('redirect_uri' => $redirect_uri));
echo "<script type='text/javascript'>top.location.href = '$url';</script>";
}
This works fine for most pages but if a page has age restrictions (and I cant guarantee all the pages using my app won't) the $facebook->api("/$page_id"); returns false because from what I can gather, I need the users access token in order to get this information which I can't get unless I authenticate them! Is there any way around this paradox or am I going to have to instruct my users not to age restrict their pages?
UPDATE
I realise I can simply redirect to facebook.com/$page_id which will take the user back to the page after authentication and would save me having to make the api request for $page_link but ideally I would like them to be redirected to my apps page tab on that page no matter what the specified default landing tab is.
I'm trying to find information on securing a HTTP REST API in a Symfony project, but all I can find is information about using sfGuardPlugin. From what I can see, this plugin isn't very useful for web services. It tries to have user profile models (which aren't always that simple) and have "sign in" and "sign out" pages, which obviously are pointless for a stateless REST API. It does a lot more than I'll ever have need for and I what to keep it simple.
I want to know where to implement my own authorisation method (loosely based on Amazon S3's approach). I know how I want the authorisation method to actually work, I just don't know where I can put code in my Symfony app so that it runs before every request is processed, and lets approved requests continue but unsuccessful requests return a 403.
Any ideas? I can't imagine this is hard, I just don't know where to start looking.
There is a plugin for RESTful authentication -> http://www.symfony-project.org/plugins/sfRestfulAuthenticationPlugin
Not used it though ....
How where you planning to authenticate users ?
The jobeet tutorial uses tokens ... http://www.symfony-project.org/jobeet/1_4/Doctrine/en/15
I ended up finding what I was looking for by digging into the code for sfHttpAuthPlugin. What I was looking for was a "Filter". Some details and an example is described in the Askeet sample project.
Stick a HTTP basicAuth script in your <appname>_dev.php (Symfony 1.4 =<) between the project configuration "require" and the configuration instance creation.
Test it on your dev. If it works, put the code in your index.php (the live equivalent of <appname>_dev.php) and push it live.
Quick and dirty but it works. You may want to protect that username/password in the script though.
e.g.
$realm = 'Restricted area';
//user => password
$users = array('username' => 'password');
if (empty($_SERVER['PHP_AUTH_DIGEST'])) {
header('HTTP/1.1 401 Unauthorized');
header('WWW-Authenticate: Digest realm="'.$realm.
'",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
die('Text to send if user hits Cancel button');
}
// || !isset($users[$data['username']]
// analyze the PHP_AUTH_DIGEST variable
if (!($data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) || !isset($users[$data['username']])) {
header('HTTP/1.1 401 Unauthorized');
header('WWW-Authenticate: Digest realm="'.$realm.
'",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
die('Wrong Credentials!');
}
// generate the valid response
$A1 = md5($data['username'] . ':' . $realm . ':' . $users[$data['username']]);
$A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']);
$valid_response = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2);
if ($data['response'] != $valid_response) {
header('HTTP/1.1 401 Unauthorized');
header('WWW-Authenticate: Digest realm="'.$realm.
'",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
die('Wrong Credentials!');
}
// function to parse the http auth header
function http_digest_parse($txt)
{
// protect against missing data
$needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1);
$data = array();
$keys = implode('|', array_keys($needed_parts));
preg_match_all('#(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))#', $txt, $matches, PREG_SET_ORDER);
foreach ($matches as $m) {
$data[$m[1]] = $m[3] ? $m[3] : $m[4];
unset($needed_parts[$m[1]]);
}
return $needed_parts ? false : $data;
}
// ****************************************************************************
// ok, valid username & password.. continue...