Cucumber, webrat mechanize testing php/drupal application on MAMP, authentication issue - php

I've got cucumber testing my drupal application with passing tests like so:
Given /^I am authenticated as a "([^"]*)" user$/ do |role|
visit('/user')
fill_in "name", :with => "user_#{role.downcase}"
fill_in "pass", :with => "password"
click_button
visit('/') #gets around a 302 redirect issue
response_body.should contain("Log out")
end
My env.rb is like so:
require 'rspec/expectations'
require 'webrat'
require 'test/unit/assertions'
World(Test::Unit::Assertions)
Webrat.configure do |config|
config.mode = :mechanize
end
World do
session = Webrat::Session.new
session.extend(Webrat::Methods)
session.extend(Webrat::Matchers)
session.visit('http://localhost')
session
end
This passes just fine when my virtual host on MAMP is the default localhost. But when I create another virtual host, with the same document (and update the session.visit to use the new root) this test fails. It seems the session is lost.
Does anyone know how to debug this? I've looked at the html output and it shows the content as an unauthenticated user which is why I think the session is being reset.
Edit
I checked the virtual hosts and they are exactly the same. The one with failing tests tends to be an order of magnitude slower.

I eventually moved to capybara. There were versions of mechanize that had a few bugs around posting form data etc. Capybara works much better.

Related

How to restrict website accessing, if user is on remote device and not on a work computer? (work time tracker app)

I would like to make a PHP website, where employees can log in/out themselves and these logs will count as a time when they started and ended their working day. I would like to allow them to do that only on their work computer and not for example on their phone while they are still on the way, but they want to avoid "being late".
So I'm struggling with a few ideas, but any of them seems to be the right solution.
Allow using the website only for specific IP addresses. But then I realized that in our place IP address is dynamic and changing it for static costs too much in our area.
Check user location. But then I saw that when I'm checking my public IP address, the location is completely wrong! Our building isn't even close to the loaded area.
Using a COOKIE/token on a work computer. But it's very easy to set the same cookie on your own device and I'm not the only IT employee here.
Checking MAC address. As I read here it's possible only in specific cases.
Block access for mobiles. But detecting a mobile is based on browser and if the user click "Request Desktop Site" scripts will say that's a computer.
Is there another method, which I can use to achieve my goal? Am I missing something?
May I bind my app for example with some other technologies that will allow me to do that? Or maybe I should try a combination of all of them?
I couldn't find any script, which would take care of that. In the worst case it doesn't have to be "perfectly secure", but I would like to be it at least hard, annoying, or time-consuming to try to "cheat" in this system.
I would run your app in the office LAN. Nobody will be able to access it from outside except if they can do remote desktop to the office computer or if they have VPN. But if you are in the IT team you may could fix IP ranges for the office computers so that you could exclude the VPN.
In terms of security, in any case it may be better having it running in your LAN. I'm sure you've got a server somewhere and if it's not the case then you could use a NAS (Synology offers NGINX, Apache, PHP and much more) or a little Rasperry Pie or something similar.
If you haven't got a fixed IP, you could also use DynDNS and have it mapped to a sub-domain such as company-name.dyndns.org and then on your PHP app you could have a cron job that gets the IP address from the domain name and updates it every minutes (I'm sure it's quickly run). It could then store it inside a config file, this way:
<?php
define('ALLOWED_IP_FILE', 'allowed-ips.inc.php');
$ALLOWED_DOMAINS = [
'your-company.dyndns.org',
'you-at-home.dyndns.org',
];
$allowed_ips = [];
foreach ($ALLOWED_DOMAINS as $allowed_domain) {
$ip = gethostbyname($allowed_domain);
if ($ip !== $allowed_domain) {
// Store with the IP in the key and value for ease when checking the IP validity.
$allowed_ips[$ip] = $ip;
} else {
fprintf(STDERR, "ERROR: Could not find the IP of $allowed_domain!\n");
}
}
$allowed_ips_export = var_export($allowed_ips, true);
$config_file_content = <<<END_OF_CONFIG
<?php
// Don't edit! This config file is generated by cron-ip-address.php.
\$ALLOWED_IPS = $allowed_ips_export;
END_OF_CONFIG;
if (file_put_contents(ALLOWED_IP_FILE, $config_file_content) === false) {
fprintf(STDERR, 'ERROR: Could not write config file ' . ALLOWED_IP_FILE . "\n");
}
This generates a config file to include in your app. Example of content generated if you run the script I wrote above:
<?php
// Don't edit! This config file is generated by cron-ip-address.php.
$ALLOWED_IPS = array (
'142.250.203.99' => '142.250.203.99',
'23.201.250.169' => '23.201.250.169',
);
Now, in your app, just include it and test the presence of the IP in the $ALLOWED_IPS array:
<?php
include ALLOWED_IP_FILE; // If this is declared in a common config file.
// include 'allowed-ips.inc.php'; // If you haven't got a common config file.
if (!isset($ALLOWED_IPS[$_SERVER['REMOTE_ADDR']])) {
http_response_code(403);
die('Sorry, you cannot access it from here.');
}
Ideally, if what you actually want to track is when employees are in the workplace and logged on / for how long, it would be probably better to just track local machine-logins via a domain controller - a method reachable from the internet is suboptimal exactly for the reasons you mentioned.
If you have an intranet which users cannot tunnel into but can access from their work machines, I'd say hosting your login-page only inside that intranet is the easiest way to achieve what you want with the methods you suggest.
Alternatively, if employee work-machines use windows under a domain controller - you can restrict access to Windows certificate-storage, then install/push a certificate and require that to be present via your server-configuration. In that case, it doesn't matter if the website is accessible from the internet. I'm sure there are similar solutions if work-machines are not on Windows.
This admittely old question gives some pointers in the right direction on how to require client certificates from a Webserver (IIS in that case).

parse_url giving host name as stars when debugged (but can still get value)

Using PHP 5.5.12
Using CakePHP 2.6.7
Running
debug($url); // output = "http://google.co.uk"
debug(parse_url($url));
/* output = array(
'host' => '*****',
'scheme' => 'http'
)
*/
I had been using this without trouble but now copy/pasting a section of my code to have it as method (to save repeating myself) has started giving me this output. But testing it back in the same place I had it originally gives me this output too.
Can anyone explain why the hostname is stars and why the rest of the array doesn't appear (I realise all other elements should be expected to be NULL)?
Edit
Just tried it again with a url that had a path to a page after the host. The path shows up fine but the host is still starred out.
Partial Answer
Just thought to try debug(parse_url($url)['host']) and it prints the host correctly. I realised that the other elements would only be set if they exist in the url.
However, can anyone explain why printing out the array prints several stars instead of the hostname even though it is definitely stored there?
The reason this happens is because of how debug() works. Many moons ago people were not pleased that they could accidentally have their database credentials dumped out in error pages (which use the same underlying code as debug()). Because of this, debug() and Debugger::export() blacklist a set of array keys that could have database credentials. The following keys are replaced with ***'s:
password
login
host
database
port
prefix
schema

Kohana can't find template on the server, but it works fine on localhost

I'm working out the kinks in the deployment of my webapp in development, but I've finally hit one I can't figure out on my own.
I have a post-commit hook in my svn that deploys all of my commits to a staging site, to ensure nothing breaks before I push to production. Thus, assuming my local working copy has no pending commits, localhost and staging have identical files.
Right now, my localhost works perfectly fine (the codebase isn't complete, but that's an entirely separate issue). On my staging site, however, I get the following exception from Kohana framework:
View_Exception [ 0 ]: The requested view index.tpl could not be found
If I manually visit the uris for my other controllers, I get the same message, with the template filename substituted. Following the stack trace, the error is occurring in the before function of the View factory, when the framework attempts to load my template file -- as expected.
My views directory (and all the files contained therein) has the same permissions as all of the other directories in my project, so I'm not sure why PHP wouldn't be able to read the directory or the files. I've also confirmed that the files do in fact exist on the server.
My error log shows nothing; my access log shows a 500 error. The Kohana logfile shows the same information that appears on-screen.
I'm genuinely confused as to why this is happening. The framework is obviously functioning, as I'm getting Kohana's formatted exception and the Kohana log is being written to. The autoloader is finding my controller classes, because the "missing" file changes appropriately as I visit my various controllers which use different templates. But the server's behavior doesn't match my localhost, and I'm left scratching my head.
After looking at Kohana::find_file, the method that's returning false, I came to the conclusion that Kohana was looking for index.tpl.php. I added some trace debugging to confirm, and I was correct: on my localhost, Kohana is looking for views\index.tpl while on my server, it's looking for views/index.tpl.php. However, a second oddity appeared, which may explain the first. Here is the full list of files that find_file tries to look for when loading up my index page on my local machine and my server:
LOCAL: SERVER:
classes\I18n.php classes/I18n.php
classes\Kohana\I18n.php classes/Kohana/I18n.php
classes\HTTP.php classes/HTTP.php
classes\Kohana\HTTP.php classes/Kohana/HTTP.php
classes\Kohana\Exception.php classes/Kohana/Exception.php
classes\Kohana\Kohana\Exception.php classes/Kohana/Kohana/Exception.php
classes\Log.php classes/Log.php
classes\Kohana\Log.php classes/Kohana/Log.php
classes\Config.php classes/Config.php
classes\Kohana\Config.php classes/Kohana/Config.php
classes\Log\File.php classes/Log/File.php
classes\Kohana\Log\File.php classes/Kohana/Log/File.php
classes\Log\Writer.php classes/Log/Writer.php
classes\Kohana\Log\Writer.php classes/Kohana/Log/Writer.php
classes\Config\File.php classes/Config/File.php
classes\Kohana\Config\File.php classes/Kohana/Config/File.php
classes\Kohana\Config\File\Reader.php classes/Kohana/Config/File/Reader.php
classes\Kohana\Config\Reader.php classes/Kohana/Config/Reader.php
classes\Kohana\Config\Source.php classes/Kohana/Config/Source.php
classes\Route.php classes/Route.php
classes\Kohana\Route.php classes/Kohana/Route.php
classes\Cookie.php classes/Cookie.php
classes\Kohana\Cookie.php classes/Kohana/Cookie.php
classes\Session.php classes/Session.php
classes\Kohana\Session.php classes/Kohana/Session.php
classes\Request.php classes/Request.php
classes\Kohana\Request.php classes/Kohana/Request.php
classes\HTTP\Request.php classes/HTTP/Request.php
classes\Kohana\HTTP\Request.php classes/Kohana/HTTP/Request.php
classes\HTTP\Message.php classes/HTTP/Message.php
classes\Kohana\HTTP\Message.php classes/Kohana/HTTP/Message.php
classes\HTTP\Header.php classes/HTTP/Header.php
classes\Kohana\HTTP\Header.php classes/Kohana/HTTP\Header.php
classes\Request\Client\Internal.php classes/Request/Client/Internal.php
classes\Kohana\Request\Client\Internal.php classes/Kohana/Request/Client/Internal.php
classes\Request\Client.php classes/Request/Client.php
classes\Kohana\Request\Client.php classes/Kohana/Request/Client.php
classes\Arr.php classes/Arr.php
classes\Kohana\Arr.php classes/Kohana/Arr.php
classes\Response.php classes/Response.php
classes\Kohana\Response.php classes/Kohana/Response.php
classes\HTTP\Response.php classes/HTTP/Response.php
classes\Kohana\HTTP\Response.php classes/Kohana/HTTP/Response.php
classes\Profiler.php classes/Profiler.php
classes\Kohana\Profiler.php classes/Kohana/Profiler.php
classes\Controller\Home.php classes/Controller/Home.php
classes\Controller\HFTemplate.php classes/Controller/HFTemplate.php
classes\Controller\Template.php classes/Controller/Template.php
classes\Kohana\Controller\Template.php classes/Kohana/Controller/Template.php
classes\Controller.php classes/Controller.php
classes\Kohana\Controller.php classes/Kohana/Controller.php
classes\View.php classes/View.php
classes\Kohana\View.php classes/Kohana/View.php
classes\Smarty\View.php
config\smarty.php
classes\Config\Group.php
classes\Kohana\Config\Group.php
vendor\smarty/libs/Smarty.class.php
classes\URL.php
classes\Kohana\URL.php
classes\Smarty\Helper.php
classes\Kohana\Smarty\Helper.php
views\index.tpl views/index.tpl.php
classes\Auth.php
classes\Kohana\Auth.php
config\auth.php
classes\Auth\ORM.php
classes\Kohana\Auth\ORM.php
config\session.php
classes\Session\Database.php
classes\Kohana\Session\Database.php
classes\Database.php
classes\Kohana\Database.php
config\database.php
classes\Database\PDO.php
classes\Kohana\Database\PDO.php
classes\DB.php
classes\Kohana\DB.php
classes\Database\Query\Builder\Select.php
classes\Kohana\Database\Query\Builder\Select.php
classes\Database\Query\Builder\Where.php
classes\Kohana\Database\Query\Builder\Where.php
classes\Database\Query\Builder.php
classes\Kohana\Database\Query\Builder.php
classes\Database\Query.php
classes\Kohana\Database\Query.php
classes\Database\Result\Cached.php
classes\Kohana\Database\Result\Cached.php
classes\Database\Result.php
classes\Kohana\Database\Result.php
classes\ORM.php
classes\Kohana\ORM.php
classes\Model.php
classes\Kohana\Model.php
classes\Model\User.php
classes\Model\Auth\User.php
classes\Inflector.php
classes\Kohana\Inflector.php
config\inflector.php
classes\UTF8.php
classes\Kohana\UTF8.php
classes\Model\Role.php
classes\Model\Auth\Role.php
classes/View/Exception.php
classes/Kohana/View/Exception.php
classes/Debug.php
classes/Kohana/Debug.php
classes/Date.php
classes/Kohana/Date.php
views/kohana/error.php
classes/Text.php
classes/Kohana/Text.php
(page content) (exception page content)
classes\Database\Query\Builder\Update.php
classes\Kohana\Database\Query\Builder\Update.php
There is a gap where the system ought to be getting the Smarty module classes, but isn't. After seeing this, I confirmed that the Smarty module does in fact exist on the server and that it's enabled in Kohana's bootstrap. Yet it isn't being loaded. Any ideas?
As it turns out, the root of the issue was case-sensitivity on Linux. I arrived at this conclusion with the help of the module author on his GitHub repository. I assume he will fix this error in the repository in the near future, however, the fix was changing the names of 4 files:
MODPATH/smarty/classes/view.php to View.php
MODPATH/smarty/classes/Smarty/view.php to View.php
MODPATH/smarty/classes/Smarty/helper.php to Helper.php
MODPATH/smarty/classes/Kohana/Smarty/helper.php to Helper.php

PHP Check subdomain sensitive to IP address

I'm having some issue with something that seemed simple to me at first, but is now proving very difficult. Maybe I'm over thinking it - would love your help.
Overview:
I have a web application with two interfaces (1 for clients and 1 for customers). All customers get routed one way and all clients get routed another. I determine which login screen to show based on their subdomain. customers get the base domain (+www) and clients go to [clientName].example.com
Problem:
I was determining this before by doing string manipulations on env("HTTP_HOST") -- see code below. However, this now poses an issue when using local IPs (for testing with other devices/ people). My code, which looks for '.' in the host environment fails because IPs have 3 dots and 'localhost' has 0
These are the different naming parameters I've established and how I'd like the route...
CUSTOMER ----------------------------- CLIENT
xyz.example.com ------>
<------ www.example.com
<------ example.com
xyz.localhost ------>
<------ www.localhost
<------ localhost
xyz.192.168.X.X ------>
<------ www.192.168.X.X
<------ 192.168.X.X
I could be really over thinking this and am hoping there's some simple Php function like "get_subdomain()" that will do this for me. But I'm not seeing it and would really love some help.
Thanks!
Current Code:
$host = env("HTTP_HOST");
$group = null;
// if there is exactly one dot IE example[dot]com then there is no subdomain
if(substr_count($host,'.')==1){
$group = 'customer'
}else{ // there is a subdomain
$subdomain = substr($host, 0, strpos($host, "."));
if($subdomain=='www'){
$group = 'customer'
}else{
$group = 'client'
}
}
CakePhp if that helps?
I hope this answer does not seem to avoid your specific question, but it seems to me that you are inviting alternatives in your question. I do think you are over-thinking the solution, especially since it is primarily to assist you in your test environment.
What I suggest is that you define your own local domains for testing instead of using IP Addresses. So for example you could (in your hosts file or equivalent) define:
xyzclient.mylocaldomain 192.168.1.1 [or whatever your local ip is]
www.mylocaldomain 192.168.1.1
xyz.localhost 192.168.1.1
www.localhost 192.168.1.1
Then you don't need to code any differently for local or live environments. Just in case: this guide to setting up and configuring local domains may be useful.

How does one use a custom firefox profile with PHPUnit's Webdriver framework?

I know with selenium RC, I used to pass a commandline operator... -firefoxProfileTemplate and that would work. Now working with Selenium2 (Webdriver), that doesn't seem to work anymore.
Since I'm using PHPUnit for other tests, I would like to continue to use it. Anyone know how to define a custom firefox profile for it?
This does not explicitly answer the question above, however, it did help solve the immediate problem as my setup for selenium would only ever use 1 Firefox instance and not try to load them on the fly.
With that said, this would help the majority of users out there, thus the reason I'm putting it as an "Answer" here, but not selecting it as the correct one.
I found the answer here at phpunit-selenium issue queue on github. Thanks emaks.
Simply load your selenium server with the command line option
-Dwebdriver.firefox.profile=PROFILE_NAME
Note: PROFILE_NAME is the machine name located in your profiles.ini in the Firefox Application Data directory. It is not a path or what not.
Lets say you use php-webdriver with FirefoxDriver.
And you want to start FirefoxDriver with specific Firefox profile. (for staying logged in and save your login and cookies every selenium run)
First of all, find directory with you firefox profile data. For me on Win 10 it is C:/Users/MyWinProfile/AppData/Roaming/Mozilla/Firefox/Profiles/pivdau5sa.selen
After that use such code for opening firefox php-webdriver:
namespace Facebook\WebDriver;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Firefox\FirefoxDriver;
use Facebook\WebDriver\Firefox\FirefoxOptions;
require_once('vendor/autoload.php');
$firefoxOptions = new FirefoxOptions();
$firefoxOptions->addArguments(['-profile', 'C:/Users/<MyUserName>/AppData/Roaming/Mozilla/Firefox/Profiles/pivdau5sa.selen']);
$capabilities = DesiredCapabilities::firefox();
$capabilities->setCapability(FirefoxOptions::CAPABILITY, $firefoxOptions);
putenv('WEBDRIVER_FIREFOX_DRIVER=C:\PHP\geckodriver.exe'); // you may dont need this line
$driver = FirefoxDriver::start($capabilities);

Categories