PHP authentication with multiple domains and subdomains - php

I have one main domain: main.com, subdomains: test1.main.com, test2.main.com and other domains one.com, two.com.
Now it's done like these:
ini_set("session.cookie_domain", ".main.com");
$domain = 'main.com';
login.php
$user = $db->query("SELECT id, login FROM users WHERE email=? AND password=?",
array($email, $password), "rowassoc");
if($user)
{
$_SESSION['user_id'] = $user['id'];
$_SESSION['user_name'] = $user['login'];
$time = 100000;
setcookie('email', $email, time() + $time, "/", "." . $domain);
setcookie('password', $password, time() + $time, "/", "." . $domain);
header('Location: http://' . $user['login'] . "." . $domain);
exit;
}
added on each page:
if(!isset($_SESSION['user_id']))
{
if(isset($_COOKIE['email']) && isset($_COOKIE['password']))
{
$email = $_COOKIE['email'];
$password = $_COOKIE['password'];
$user = $db->query("SELECT id, login FROM users WHERE email=? AND password=?",
array($email, $password), "rowassoc");
if($user)
{
$_SESSION['user_id'] = $user['id'];
$_SESSION['user_name'] = $user['login'];
}
}
}
else
{
$user = $db->query("SELECT id, login FROM users WHERE id=?",
array($_SESSION['user_id']), "rowassoc");
if(!$user)
{
setcookie('email', '', time() , "/", "." . $domain);
setcookie('password', '', time() , "/", "." . $domain);
unset($_SESSION['user_id']);
session_destroy();
setcookie("PHPSESSID","",time(), "/", "." . $domain);
}
else
{
$_SESSION['user_id'] = $user['id'];
$_SESSION['user_name'] = $user['login'];
}
}
logout.php
if(isset($_SESSION['user_id']))
{
setcookie('email', '', time() , "/", "." . $domain);
setcookie('password', '', time() , "/", "." . $domain);
unset($_SESSION['user_id']);
unset($_SESSION['user_name']);
session_destroy();
setcookie("PHPSESSID","",time(), "/", "." . $domain);
header('Location: /main');
exit;
}
But it works only on domain main.com and its subdomains test1.main.com, test2.main.com.
I need to somehow save the session and on other domains one.com, two.com.
How best to do safe authentication, if there are solutions, i really confused, please tell with example.

As far as I know, crossing sessions between sub-domains is fine, but it won't carry over to a whole new domain. To do that you need some sort of centralized data method, or an API.
Database method: you will have to create a remote MySQL data access so that domain2.com can access the database on domain1.com. When a log-in is performed, not only should it create a new session, but a unique log-in token (with an expiry time) should be put into the mysql database. Now, for every link that goes from domain1.com to domain2.com, you should add a $_GET variable that contains a randomly generated session id (md5 hash will do). domain2.com, upon receiving the visitor, will take the $_GET variable, run it through the MySQL database to find the login token, and if there is a match, consider that user to be logged on (and perhaps embed a $_COOKIE as well to store the login data). This will make the log-in transferrable between two completely different domains.
API method: you need to create an API method, so that domain1.com can respond to an external request from authorized domains to retrieve the login token upon a user being forwarded. This method will also require that all links going from domain1.com to domain2.com to be appended with a $_GET variable to pass the unique session hash. Then upon receiving the visitor, domain2.com will do a curl() request to domain1.com/userapi.php (or whatever you call the file) and the variables should be tested against what's in the database.
This is the best I can explain it.. to write this out in code is a significant piece of work so I cannot commit. But judging by your code, you have a very good understanding of PHP so I'm confident you will pull this off!
Good luck mate.

To keep your sessions going across multiple domains, you need to use session_set_cookie_params(). With that, you can specify your domain. For example...
session_set_cookie_params(10000, "/", ".main.com");
That will set the session timeout at 10,000 seconds for all documents under the site root, and for all subdomains of main.com.
You should call session_set_cookie_params() before you do session_start().

But if user reach domains one.com directly, than one.com can't know if user had login by the right answer mentioned above, seems like must use some extra js, it's jsonP! we let account.main.com/userLoginStat.php?callback=loginThisDomain to check if user had login main.com, if so, the js callback function loginThisDomain do some thing to autologin user to one.com.

Related

Detecting a cookie set using setcookie without a page reload

I am maintaining the code for an eCommerce website, they use a highly modified version of osCommerce v2.2 RC2. Was noticing an issue where the session isn't started for a new user until they visit the 2nd page of the site.
Looking at the code, before starting the session, it tries to set a cookie. If it detects the cookie it starts the session. Something along this line:
setcookie('cookie_test', 'please_accept_for_session', time()+60*60*24*30, $cookie_path, $cookie_domain);
if (isset($_COOKIE['cookie_test'])) {
session_start();
...
I found an article here that talks about a situation like this, it states:
The first time you only tell the browser to set the cookie, at the time, there is no cookie data in the request header (which could get from $_COOKIE).
Which explains why it takes two page loads for the session to be started. One to set the cookie and one to get notification from the browser that the cookie is set.
My question is, is there anyway around having to go through two page loads to detect the cookie was successfully set on the users browser?
I found this question that didn't really answer my question completely. The highest voted solution was:
setcookie('uname', $uname, time()+60*30);
$_COOKIE['uname'] = $uname;
Which may make it "work" but it doesn't truely tell me that the script was able to set a cookie successfully.
I also found this question, that suggested accessing the headers_list to find the cookie information like so:
function getcookie($name) {
$cookies = [];
$headers = headers_list();
// see http://tools.ietf.org/html/rfc6265#section-4.1.1
foreach($headers as $header) {
if (strpos($header, 'Set-Cookie: ') === 0) {
$value = str_replace('&', urlencode('&'), substr($header, 12));
parse_str(current(explode(';', $value, 1)), $pair);
$cookies = array_merge_recursive($cookies, $pair);
}
}
return $cookies[$name];
}
// [...]
setcookie('uname', $uname, time() + 60 * 30);
echo "Cookie value: " . getcookie('uname');
Which, again, doesn't seem to be verifying that the cookie was set successfully. All this appears to do is search the headers being sent to the browser for the cookie value.
The only solution I can think of is to redirect on the first visit after setting the cookie. Is there any other way?
Here is the answer:
<?php
function set_cookie($name, $value) {
if (!isset($_COOKIE[$name]) || ($_COOKIE[$name] != $value)) {
$_COOKIE[$name] = $value;
}
setcookie($name, $value, strtotime('+1 week'), '/');
}
// Usage:
set_cookie('username', 'ABC'); //Modify the value to see the change
echo $_COOKIE['username'];

PHP Redirect to Selected Page After Login

I'm trying to find a way to redirect a user to the page they selected if they have been forced to log in again after a session timeout.
Right now, after the user logs in, they are redirected to index.php. But, if a user received a link in an email to a different section of my site and they have not logged in all day, they are obviously asked to log in but end up on the index.php instead of the page the link was for.
Here is a snippet of my code in the login page:
if (mysql_num_rows($result_set) == 1) {
// username/password authenticated
// and only 1 match
$found_user = mysql_fetch_array($result_set);
$_SESSION['user_id'] = $found_user['id'];
$_SESSION['username'] = $found_user['username'];
$_SESSION['last_activity'] = time();
$_SESSION['time_out'] = 7200; // 2 hours
redirect_to("index.php");
Any ideas would be helpful.
I want to thank everyone who answered my question. The solution was a combination of a few suggestions I received here. I'd like to share with you how I solved this:
Part of the reason why I was having trouble saving the url the user tried to go to before being forced to log in again was that my sessions are handled by an external php file which takes care of confirming login and expiring current session. This file is required by all pages on my website. HTTP_REFERER would not work because it would always be set to the login.php. Here's what I did on my session.php file:
session_start();
$protocol = strpos(strtolower($_SERVER['SERVER_PROTOCOL']),'https')
=== FALSE ? 'http' : 'https';
$host = $_SERVER['HTTP_HOST'];
$script = $_SERVER['SCRIPT_NAME'];
$params = $_SERVER['QUERY_STRING'];
$currentUrl = $protocol . '://' . $host . $script . '?' . $params;
if ($currentUrl != "http://domain.com/login.php?") {
$expiryTime = time()+(60*5); // 5 mins
setcookie('referer',$currentUrl,$expiryTime,'/');
}
Essentially, I saved the referring url in a cookie that is set to expire in 5 minutes, giving the user enough time to login. Then, on login.php I did this:
if(isset($_COOKIE['referer'])) {
redirect_to($_COOKIE['referer']);
} else {
redirect_to('index.php');
}
And, BINGO! Works every time.
Try this:
$actual_link = "http://" . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"];
if($actual_link == 'the email link'){
header('Location: '. $actual_link);
}else{
header('Location: index.php');
}
Try to save the URL in session whenever a user hit any url like http://www.abc.com/profile.php
once the user has successfully logged in redirect the user to saved URL(which is in session)
it the previous page is in the same directory and then you can try header('Location : .') or else if you if you need to redirect somewhere else.save the path before that situation occurs and in $url then u can redirect using header('Location: $url') or header('Location $url?values')

Why won't my cookie go away? **UPDATE**

I'm setting an auth cookie like so:
$identifier = $this->createIdentifier($username);
$key = md5(uniqid(rand(), true));
$timeout = time() + 60 * 60 * 24 * 100;
setcookie('auth', "$identifier:$key", $timeout);
After logout I'm trying to invalidate it by doing this:
setcookie('auth', "", time() - 3600);
When I try to view a restricted page after logging out I'm checking to see if the cookie exists:
if (isset($_COOKIE['auth'])) {
error_log("COOKIE EXISTS: " . print_r($_COOKIE, true));
}
Here is my logout script:
if (!isset($_SESSION)) session_start();
$ref="index.php";
if (isset($_SESSION['username'])) {
unset($_SESSION['username']);
session_unset();
session_destroy();
// remove the auth cookie
setcookie('auth', "", time() - 3600);
}
header("Location: " . $ref);
exit();
I shouldn't be hitting this code but I am. After logging out I see the cookie has been removed from my browser. Any idea how it's finding it again after logging out?
UPDATE
This code get called from another class that checks user privs etc. The only files it doesn't work with are files that reference it from one directory above. For instance
Any file referencing it like this works OK:
<?php include_once('classes/check.class.php');
Any file referencing it like so DO NOT work:
<?php include_once('../classes/check.class.php');
Any thoughts what might be causing this?
After you log the user out you need to do a redirect to cause a new page load. Since cookies are sent with page requests until a new requests is made those cookies are still alive even after you "delete" them.

transfering session using session_id across domains

I am attempting to transfer a session to another domain by using session_id function.
User logs in # domainA.com and gets redirected to domainB.com where I want to transfer the session.
if(isset($_REQUEST["redirect"]) && $_REQUEST["redirect"] != ''){
$url = urldecode($_REQUEST["redirect"]);
if(strpos($url, "xxxxx.") === false){ //Means we are redirecting to a custom domain
$urlParts = parse_url($url);
$url = $urlParts["scheme"] . "://" . $urlParts["host"] . "/login/index/sid:" . session_id() . "?redirect=" . $url;
}
$this->redirect($url);
}
SiteB.com will receive the session id and set it like so:
if(isset($this->params["named"]["sid"]) && $this->params["named"]["sid"]){
session_id($this->params["named"]["sid"]);
$this->redirect($this->params["url"]["redirect"]);
}
I am sure that the session is arriving at siteB.com but $_SESSION remains empty.
What am I missing?
Thanks
You should call session_id($sess_id) before session_start();

Setting a cookie in an AJAX request?

I'm validating a login form with jQuery AJAX call to PHP. In php, I create a session and if they checked the 'remember me' checkbox, I want to create a cookie. Here's the php code:
<?php
include '../includes/connection.php';
date_default_timezone_set('GMT');
$name = $_POST['username'];
$pass = $_POST['password'];
$query = mysql_query("SELECT id, username, password FROM users WHERE username = '$name' LIMIT 1");
if(mysql_num_rows($query) == 0) {
echo 'error';
exit;
}
while($row = mysql_fetch_array($query)) {
if($row['username'] == $name && $row['password'] == $pass) {
session_start();
$_SESSION['username'] = $row['username'];
$_SESSION['usrID'] = $row['id'];
echo 'success';
if($_POST['remember']) {
setcookie('username', $row['username'], $exp);
setcookie('password', $row['password'], $exp);
setcookie('usrID', $row['id'], $exp);
}
} else {
echo 'error';
exit;
}
}
?>
The session is set successfully, however the cookie is not set at all. I've tried setting all the values (domain, path, etc.) but that didn't change anything. Is there anything obvious I'm missing?
Here are few suggestions:
Make sure that you are specifying the correct expiration format of date
When setting a cookie on a page that redirects, the cookie must be set after the call to header('Location: ....'); eg:
header('Location: http://www.example.com/');
setcookie('asite', $site, time()+60*60, '/', 'site.com');
If you have human urls like www.domain.com/path1/path2/, then you must set cookie path to / to work for all paths, not just current one.
setcookie('type_id', $new_type_id, time() + 60*60*24*30, '/');
Notice the last / in the arguments.
From PHP manual:
The path on the server in which the
cookie will be available on. If set to
'/', the cookie will be available
within the entire domain . If set to
'/foo/', the cookie will only be
available within the /foo/ directory
and all sub-directories such as
/foo/bar/ of domain . The default
value is the current directory that
the cookie is being set in.
setcookie() defines a cookie to be sent along with the rest of the HTTP headers. Like other headers, cookies must be sent before any output from your script meaning there should be no html/code echo statements before that.
You won't be able to set the cookie server-side when using an AJAX call. Instead, wait until you get a successful response and set the cookie client side. To make it easier, you could use a jQuery plugin.

Categories