I'm having problems with a small OpenID-library called LightOpenID
.
I can authenticate to almost all providers, but I don't know how to fetch the data from the provider. I only get Array(), even with print_r().
You need to call getAttributes() after $openid->validate() not before.
Remember:
Note that it does not guarantee that any of the required/optional parameters will be present
This is how I use it. This is the file openid.php in the folder lightopenid. In the class make the following additional functions -
class LightOpenID
{
public $returnUrl
, $required = array()
, $optional = array()
, $verify_peer = null
, $capath = null
, $cainfo = null;
// these are the variables which store the data about the user...
public function ret_fname() { return $this->data['openid_ext1_value_namePerson_first']; }
public function ret_lname() { return $this->data['openid_ext1_value_namePerson_last']; }
public function ret_email() { return $this->data['openid_ext1_value_contact_email']; }
public function ret_lang() { return $this->data['openid_ext1_value_pref_language']; }
}
Now make your file example login.php which is called when you want to authenticate. There might be several copies of this file for different authentication domains etc.
<?php
# Logging in with Google accounts requires setting special identity, so this example shows how to do it.
session_start();
require 'lightopenid/openid.php';
include_once('config.php'); // initial setting file
try {
$openid = new LightOpenID; // akshat - declared an object of class lightopenid.. this is listed in openid.php
if(!$openid->mode) {
if(isset($_GET['login'])) {
$openid->identity = 'https://www.google.com/accounts/o8/site-xrds?hd=YourDomain.in'; //this can be changed as you know...
$openid->required = array('namePerson/friendly', 'contact/email' , 'contact/country/home', 'namePerson/first', 'pref/language', 'namePerson/last'); // akshat - line added by me from after reading from the net....
header('Location: ' . $openid->authUrl());
}
?>
<script type="text/javascript" src="js/jquery-1.4.2.min.js" language="javascript"></script>
<script type="text/javascript">
$(document).ready(function() {
document.form.submit();
});
</script>
<form name="form" action="?login" method="post"> </form>
<?php
} elseif($openid->mode == 'cancel') {
echo 'User has canceled authentication for Your Domain !';
} else { // FETCH USER INFO HERE
$fname = $openid->ret_fname(); // fetching user first name...
$lname = $openid->ret_lname(); // fetching user last name...
$email = $openid->ret_email(); // fetching user email...
$lang = $openid->ret_lang(); // fetching user language...
session_start();
// use it as required. I set them in session !
$_SESSION['admin']['emailID'] = $email; //put email id in session.
$_SESSION['admin']['fname'] = $fname; //put first name also in session.
$_SESSION['admin']['lname'] = $lname; //put last name also in session.
$rurl = $_SESSION['redirect']; // you can ignore this. Go to your own page now...
header("Location:$rurl"); // Go back to the calling application !
}
} catch(ErrorException $e) {
echo $e->getMessage();
}
?>
Related
FOR THE TL;DR VERSION...GO TO THE BOTTOM AND READ WHAT'S IN BOLD
OK, so I've had this problem for a while, and I've done a lot of research, made some changes and still have no idea what is wrong with my code. My problem is that when a user submits the registration form, the session always reverts back to empty. Here is how the logic goes:
1. The user navigates to mysite/register/ and is served with register.php by index.php in that same directory.
2. index.php handles everything (calls classes for the logic and things of that nature, but everything is run through index.php at the top level)
3. The user submits the login form through a vanilla.js ajax call and the response is console.logged back out.
Now that you understand the logic...let me get you to the code:
Here is index.php:
<?php
// Allowing PHP to be strictly typed and start session
declare(strict_types=1);
session_start();
// Requiring the necessary classes
require_once "../vendor/autoload.php";
require_once "../model/EditSession.php";
require_once "../model/DatabaseConfig.php";
require_once "../model/ServerValidation.php";
require_once "../model/RegisterUser.php";
require_once "../model/Verify.php";
// Creating the new objects
$validatingServer = new ServerValidation();
$sessionToEdit = new EditSession();
$sessionToEdit->create_new_session_id();
// Checks the request protocol
try {
$validatingServer->checkHttps();
} catch (Exception $ex) {
header("Location: /NotSecure.php");
}
// Setting CSRF token for protection
try {
$csrfToken = $sessionToEdit->store_secure_key_in_session("CSRFTOKEN");
} catch (Exception $ex) {
echo "You have a problem setting your session. $ex";
}
// Handling a navigation to the webpage
$validatingServer->navigateToWebsite("register.php", "Register", $csrfToken);
// For when a user submits the form
try {
$validatingServer->checkRequestType("POST");
$validatingServer->checkContentType("application/json");
$registerFormData = json_decode(file_get_contents("php://input"), true);
$csrfTokenFromForm = $registerFormData["csrfToken"];
$csrfTokenFromSession = $sessionToEdit->get_from_session("CSRFTOKEN");
} catch (Exception $ex) {
echo "Bad request data. $ex";
}
//$validatingServer->checkToken($csrfTokenFromForm, $csrfTokenFromSession);
// Call to make original register user object
try {
$register = new RegisterUser($registerFormData["firstName"], $registerFormData["lastName"], $registerFormData["email"], $registerFormData["password"]);
} catch (Exception $ex) {
echo $ex;
}
// Check email and register the user
try {
$register->checkEmail();
$register->register();
} catch (Exception $ex) {
echo $ex;
}
// Sending registration email to the user
try {
$register->sendRegistrationEmail("http://localhost/");
} catch (Exception $ex) {
echo $ex;
}
echo "Successful Register";
Here is the frontend
<!doctype html>
<html>
<head>
<title><?=$pageTitle;?></title>
</head>
<body>
<main>
<form id="registerForm">
<input type="text" id="firstName" name="firstName" autocomplete="given-name" placeholder="First Name" pattern="^[A-Za-z.\s_-]+$" autofocus required>
<input type="text" id="lastName" name="lastName" autocomplete="family-name" placeholder="Last Name" pattern="^[A-Za-z.\s_-]+$" required>
<input type="email" id="email" name="email" autocomplete="email" placeholder="Email" required>
<input type="password" id="password" name="password" placeholder="Password" pattern="^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!##\$%\^&\*]).{8,}" required>
<input type="hidden" id="csrfToken" value="<?=$csrfToken;?>">
<button type="submit" id="registerSubmit">Submit</button>
</form>
</main>
<script src="index.js"></script>
</body>
</html>
Here is index.js
const registerForm = document.getElementById("registerForm");
registerForm.addEventListener("submit", function(e) {
e.preventDefault();
const firstName = document.getElementById("firstName").value;
const lastName = document.getElementById("lastName").value;
const email = document.getElementById("email").value;
const password = document.getElementById("password").value;
const csrfToken = document.getElementById("csrfToken").value;
const registerFormData = {
"firstName":firstName,
"lastName":lastName,
"email":email,
"password":password,
"csrfToken":csrfToken
};
const ajax = new XMLHttpRequest();
ajax.open("POST", "index.php");
ajax.setRequestHeader("Content-Type", "application/json");
ajax.withCredentials = true;
ajax.send(JSON.stringify(registerFormData));
ajax.onload = function() {
console.log(this.response);
}
}, false);
Here is EditSession.php
<?php
declare(strict_types=1);
class EditSession {
private $firstPartOfNewId;
private $secondPartOfNewId;
private $thirdPartOfNewId;
private $newSID;
public $secureKey = "";
// Create new session ID
function create_new_session_id() : void {
if (isset($_SESSION)) {
$firstPartOfNewId = str_replace(array(".", ":"), "", $_SERVER["REMOTE_ADDR"]);
$secondPartOfNewId = round(microtime(true) * 1000);
$thirdPartOfNewId = hash("sha512", random_bytes(64));
$newSID = $firstPartOfNewId.$secondPartOfNewId.$thirdPartOfNewId;
session_id($newSID);
} else {
throw new Exception("Session is not set");
}
}
// Store a value in a set session
function store_in_session(string $key,string $value) : void {
if (!isset($_SESSION)) {
throw new Exception("Session is not set.");
}
if (!isset($_SESSION[$key])) {
$_SESSION[$key] = $value;
}
}
// Store a value in a set session
function store_secure_key_in_session(string $key) : string {
if (!isset($_SESSION)) {
throw new Exception("Session is not set.");
}
if (!isset($_SESSION[$key])) {
$secureKey = hash("sha512", random_bytes(64));
$_SESSION[$key] = $secureKey;
return $secureKey;
} else {
return $secureKey;
}
}
// Unsetting variable associated with the $key
function unset_session_variable(string $key) : void {
if (isset($_SESSION)) {
$_SESSION[$key] = "";
unset($_SESSION[$key]);
} else {
throw new Exception("Session with key is not set.");
}
}
// Getting associated key from session
function get_from_session(string $key) : string {
if (isset($_SESSION[$key])) {
return $_SESSION[$key];
} elseif (isset($_SESSION)) {
throw new Exception("Session is set, but the key passed is not set in the session.");
} else {
throw new Exception("Session is not set.");
}
}
}
?>
Here is ServerValidation.php
<?php
declare(strict_types=1);
class ServerValidation {
// Handles navigation to website
function navigateToWebsite(string $page, string $pageTitle, string $csrfToken) : void {
if (empty($_POST) && empty($_GET) && empty(file_get_contents("php://input"))) {
$csrfToken = $csrfToken;
$pageTitle = $pageTitle;
include_once $page;
exit;
}
}
// Checks if the website is served over https or its localhost
function checkHttps() : void {
if ($_SERVER["REQUEST_SCHEME"] !== "https" && $_SERVER["HTTP_HOST"] !== "localhost") {
throw new Exception("Not served over https");
}
}
// Checks if the content type is what it should be
function checkContentType(string $type) : void {
if ($_SERVER["CONTENT_TYPE"] !== $type) {
throw new Exception("Wrong content-type");
}
}
// Checks request method
function checkRequestType(string $type) : void {
if ($_SERVER["REQUEST_METHOD"] !== $type) {
throw new Exception("Wrong request method");
}
}
function checkToken(string $tokenFromFrontend, string $tokenFromSession) : void {
if ($tokenFromSession !== $tokenFromFrontend) {
throw new Exception("Tokens not matching up, there is a problem!!");
}
}
}
Now, here is what happens with the code. When the user submits the register form, with the csrfToken that is fetched from the hidden value in the form using AJAX, I get an exception thrown in my program (specifically from the checkToken() method in the ServerValidation class) that says "tokens not matching up". And I have confirmed why this is. If I var_dump the $_SESSION right after I call session_start(), it is ALWAYS empty. It doesn't matter if it has already been initialized (by the user first navigating to the page), it is ALWAYS empty. And so, following the logic of the program, it inserts a new value for CSRFTOKEN and so of course they don't match up. I am absolutely stumped and have been working on this problem for a week. Here are some answers to questions I know will be asked:
1. I'm using a macbook running XAMPP and php 7.2
2. My cookies are set to http_only, but not secure_only. All other cookie parameters are default.
3. My file permissions where my session data is being stored (/Applications/XAMPP/xamppfiles/temp/) is 777 (I just wanted to do something I know would work)
4. What happens if I don't create a new php session_id? The same outcome will happen...ie - the session will still always be initialized as empty
5. Can I var_dump the session at different points in the program? Sure...here are different points and their outcomes:
- Right after session_start is called:
- When the user initially navigates to the page: an empty session.
- When the user has submitted the registration form: an empty session
- Right after $csrfToken = $sessionToEdit->store_secure_key_in_session("CSRFTOKEN"); is called:
- When the user initially navigates to the page: a session with the key of CSRFTOKEN is returned
- When the user has submitted the registration form: a session with the key of CSRFTOKEN is returned (but the value is different than when the user originally navigated to the page)
- Right after $validatingServer->navigateToWebsite("register.php", "Register", $csrfToken);
- When the user initially navigates to the page: Nothing, because the program doesn't get that far because it exits out.
- When the user has submitted the registration form: a session with the key of CSRFTOKEN is returned (but the value is different than when the user originally navigated to the page and the value is different than what lives in the hidden field in the registration form)
Here is the question: Why do my session values keep initializing to empty, even though I'm on the same domain, doing all my work in the same file, have my session parameters set right, and have my file permissions set right?
I'm trying to imitate the behavior of flash messages in native PHP, for one-time display of error messages.
Displaying the Login page:
public function showLoginAndRegistrationPage()
{
$session = new Session();
$data['errors']['login']['account'] = $session->getFormErrorFlashData('login', 'account');
$this->viewPresenter->display('basic', 'customer/login-registration', $data, 'Login/Register');
}
Verifying the login details:
public function processLogin()
{
// Some code
$session = new Session();
if($this->formInputFilter->isValid()) {
// Some code
if(true) {
// Some code
} else {
$errors = array(
'account' => 'Account does not exist.'
);
$session->setFormErrorFlashData('login', $errors);
header('Location: /login');
}
} else {
header('Location: /login');
}
}
For setting the error messages:
public function setFormErrorFlashData($form, $errors = array())
{
foreach($errors As $field => $message) {
$_SESSION['errors']["{$form}"]["{$field}"] = $message;
}
}
For getting the error messages stored in the session:
public function getFormErrorFlashData($form, $field)
{
if(isset($_SESSION['errors']["{$form}"]["{$field}"])) {
$message = $_SESSION['errors']["{$form}"]["{$field}"];
unset($_SESSION['errors']["{$form}"]["{$field}"]);
return $message;
}
}
Basically for an invalid attempt, after redirect, it should now display the 'Account does not exist' message, and then when the user refreshes the page, it should no longer be there.
What happens is when I comment out the unset() line in getFormErrorFlashData(), the $_SESSION contains the errors, but of course as expected they do persist even after countless page refreshes.
But when it's not commented out, I get a NULL. It seems that $message is also unset, even after attempting to store in it the value of that session key.
I have a bootstrap file that has the session_start() line, it's loaded for every page so I doubt that's the cause?
UPDATE:
index.php (bootstrap file)
<?php
session_start();
date_default_timezone_set('Asia/Taipei');
require_once 'core/Autoloader.php';
use core\Autoloader As Autoloader;
use core\Router As Router;
use core\Dispatcher As Dispatcher;
spl_autoload_register('core\Autoloader::loadClass');
$request_uri = trim($_SERVER['REQUEST_URI']);
$router = new Router();
$route = $router->handleRequest($request_uri);
if (!$route) {
require_once ('./views/errors/404.php');
} else {
$dispatcher = new Dispatcher($route);
$isDispatched = $dispatcher->dispatch();
if (!$isDispatched) {
echo '<div>' .$route['class'] .'/' . $route['action'] . ' not found </div>';
require_once ('./views/errors/404.php');
}
}
I've found the culprit.
When I traced the request logs, showLoginAndRegistrationPage() was being called twice because I didn't realize I also had a .js file attached in the html file with a submit event handler that gets fired too, thus the double page requests.
I removed the file and now it's working.
Thanks for the help!
I am facing a very strange problem , i am doing CasLogin in my application..
i have successfully implemented CAS, i.e all values are set in $_SESSION variable after all proper validations, and successful login, but when i redirect it from CasLogin() action to Index Action $_SESSION contains nothing..
i am using Yii Frame Work.
here is code.
public function actionCasLogin($CID=NULL)
{
//code to be imported from GMS here
PhpCasControl::setPhpCasContext($CID);
phpCAS::setPostAuthenticateCallback(array($this,'_saveServiceTkt'));
$loginForm = new CasLoginForm;
// validate user input and redirect to the previous page if valid
if ($loginForm->login($CID)) {
if (Yii::app()->user->isGuest){
echo '<br> <br> This shows up..';
var_dump($_SESSION);
}
else{
echo 'Hello at caslogin <br>never shows up';
var_dump(Yii::app()->user->id);
}
$this->redirect(array('index'));
}
else {
throw new Exception("You don't have sufficient permissions to access this service. Please contact Administrator !");
}
}
this function Works Properly and if i put a EXIT; here it will display $_SESSION with all the desired values..
but after redirection... to index..
whose code is this..
public function actionIndex()
{
echo"hello at index";
if (! Yii::app()->user->isGuest) {
//#CASE 1: User is already logged in
$this->redirect(array("site/upload"));
}
else{
//#CASE 2: User is not Logged in
echo '<br>shows up with empty session<br>';
var_dump($_SESSION);
var_dump(Yii::getVersion());
exit;
$this->redirect(array("site/login"));
}
}
here $_SESSION is empty..
any explanation why this might be happening..
i am aware of CAS creating its own session by service ticket name.. i have handled that thing.. by RenameSession function, which i call in CasLoginForm..
whose code is this..
public function rename_session($newSessionId) {
//Store current session variables so that can be used later
$old_session = $_SESSION;
//Destroy current session
session_destroy();
// set up a new session, of name based on the ticket
$session_id = preg_replace('/[^a-zA-Z0-9\-]/', '', $newSessionId);
//start session with session ID as 1) service ticket in case of CAS login, 2) random sTring in case of local login.
session_id($session_id);
session_start();
//echo "<br>new session <br>";
//Restore old session variables
$_SESSION = $old_session;
//var_dump($_SESSION);
}
OK, i think that you should use session_id to change the id.
public function rename_session($newSessionId) {
// set up a new session id, of name based on the ticket
session_id(preg_replace('/[^a-zA-Z0-9\-]/', '', $newSessionId));
}
Is it secure to use
If ($_SESSION['authenticated'] == true) {
/////Show secure page
}
Can someone just go and change where the session variable is stored to make their $_SESSION['autheticated'] = to true?
Same thing with a user having $_SESSION['id'] = to their index id. How would I be able to make this securer?
Could someone just go and change the id value and impersonate another user?
Would the below method be the right way to make something securer?
$_SESSION['random_check'] = (random number)
and also store this in a column in my database and each time I would
If ($_SESSION['authenticated'] == true && $_SESSION['random_check'] == random_number ) {
/////Then show secure page
}
Thanks,
I'm pretty sure Session in most hosting is just an interface to your filesystem, i.e. all Session data is stored in the server's hard disk, if you look at phpinfo() output, you can have a look at where the actual path of Session data is.
With that said, unless you chmod your session path to 777 and the attacker happens to know where you are hosting your app and has the login, then I don't think it's much of an issue.
The bigger issue here is securing your cookie as it's the piece of information that's going back and forth through your server and client, which attackers can use to impersonate legit users.
Yes,Is it secure to use. I use this.
I do this:
-check login,if is an valid login , set $_SESSION['logged'] = 'yes' and generate um token $_SESSION['token'] = 'the token'
this token, I save in an input html element and check in each action.
something like:
<?php
class token {
public function generateToken() {
return $_SESSION['token'] = md5( microtime() );
}
function generateField($name = "token"){
return "<input type='hidden' value='{$_SESSION['token']}' name='{$name}'>";
}
public function getToken() {
return $_SESSION['token'];
}
public function getTokenFromFields($method = "GET") {
return strtoupper($method) == "GET" ? $_GET['token'] : $_POST['token'];
}
public function checkToken() {
return $this -> getToken() == $this -> getTokenFromFields();
}
public function updateToken() {
$_SESSION['token'] = md5( microtime() );
}
}
?>
<?php
//orther file
require 'class.token.php';
$token = new token();
$Atoken = $token -> generateToken();
echo "<script>
var data = {};
data['token'] = '{$Atoken}';
data['foo'] = 'baa';
</script>";
$token -> generateField();
?>
<script>
$.ajax({type:"GET", url:"process.php", "data=foo=baa&token=" + data.token, success:function(response) { } })
</script>
In process.php:
<?php
if($_SESSION['token'] == $_GET['token']) {
//do something
} else die('bad token');
?>
Im Using the following code to validate (poorly, I know) a form's $_POST[]ed data. How can I pass $auth onto the new page so I can print it for the user? (short of using my-account.php?auth=You Must......)
if (!$_POST['supportarea'] || !$_POST['supportbody']) {
$auth = 'You must provide some information if we are ever to help you with your support ticket';
header('Location: ../pages/my-account.php');
}
Thanks. Alex.
You should use the session. In your script:
session_start();
$_SESSION['flash'] = 'You must ...';
In the my-account.php script:
session_start();
if (!empty($_SESSION['flash'])) {
$flash_message = htmlspecialchars($_SESSION['flash']);
unset($_SESSION['flash']);
} else {
$flash_message = null;
}
Then, if !empty($flash_message), show it to the user.