I have a web application and a ios application(wasn't made by me, I can't do any code changes there), but both of them are using same backend in order to get data(this is the part where I have access) backend part if written in php on codeigniter framework.
When I did login part on the website I used a login controller and a hook to pass the session on all my controllers.
this is the login side:
public function login_validation() {
$this->load->library('form_validation');
$this->form_validation->set_rules('username','Username',
'required|trim|callback_validate_credentials');
$this->form_validation->set_rules('password','Password','required|trim');
if ($this->form_validation->run()) {
$data= array(
'username'=> $this->input->post('username'),
'is_logged_in' => true
);
$this->session->set_userdata($data);
redirect('Monitor');
} else {
$this->load->view('login');
}
}
and this is my hook:
<?php
class Authenticate {
protected $CI;
public function __construct() {
$this->CI = &get_instance();
}
public function check_user_login() {
$isLoginRequested = $this->_endsWith(base_url(uri_string()), "Main/login");
$isLoginValidating = $this->_endsWith(base_url(uri_string()), "Main/login_validation");
// echo $this->CI->session->userdata('is_logged_in') ;
if(false == $this->CI->session->userdata('is_logged_in') &&
$isLoginRequested == false && $isLoginValidating == false) {
redirect('Main/login');
}
}
function _endsWith($haystack, $needle) {
$length = strlen($needle);
if ($length == 0) {
return true;
}
return (substr($haystack, -$length) === $needle);
}
}
?>
Now the login on the ios device is requesting header X-SESSION-KEY on the api. On this api :
public function types() {
$userSession = $this->_get_user_session();
$reqLanguage = $this->input->get_request_header('Accept-Language');
if ($userSession != null) {
if ($userSession->isLoggedIn() == true) {
$this->_issue_success($this->ptypes->getAll($reqLanguage));
} else {
$this->_issue_respond_with_reason("The provided session is invalid.", HttpResponse::Forbidden);
}
} else {
$this->_issue_respond_with_reason("No session key supplied.", HttpResponse::Forbidden);
}
But what is happening now, on the same URL(like I told both applications are using same backend) my ios app is requesting now the web session not the API side, and I will get redirected on the login.
And on that URL(on the ios app) I get:
{"reason":"No session key supplied."}
and my controllers aren't sending any data.
My question is that, how I can make a if variable on the login controller side, when the user (logged from ios) is requesting the API sessions side, bypass my web session session and avoid that no session key supplied.
Before my login, the application was working fine.
Related
Introduction
For my personal project i am using
Symfony v4.2 with
XAMPP and
Widows 10 Pro
In order to not to display route parameters in URL i save them in the table.
Then in the controller i check if there is variable (that keeps UUID that corresponds to route parameters) in the session.
If i get no variable in session it should redirect to section start page, where UUID and initial data in the table are setup.
Redirect logic is extracted to helper service. In order to redirect to work there are copied functions redirectToRoute and redirect
I test this functionalit by deleting php session variables in temp folder and PHPSESSID cookie in the browser.
Problem
The prolem is - it does not redirect to secton start page.
I can see that correct if branch is selected, but then it "just stops" and does not execute redirect.
Code
public function checkWhereaboutsExist()
{
$em = $this->entityManager;
$repo_whereabouts = $em->getRepository(Whereabouts::class);
$whereabouts = $this->session->get('whereabouts');
if (($whereabouts === null) || ($whereabouts === ''))
{
$data = 'whereabouts === '.$whereabouts;
dump($data);
/*
HERE IT STOPS
*/
return $this->redirectToRoute('section_start');
}
else
{
$my_whereabouts = $repo_whereabouts->getWhereabouts($whereabouts);
if (!$my_whereabouts)
{
return $this->redirectToRoute('section_start');
}
}
}
Question
Does enyone have some ideas about what is the culprit in this case?
You could try to inject the router into your service class:
use Symfony\Component\Routing\RouterInterface;
class MyService
{
private $router;
public function __construct(RouterInterface $router)
{
$this->router = $router;
}
public function checkWhereaboutsExist()
{
// your code ...
return new RedirectResponse($this->router->generate('section_start'));
}
}
Hummmm, i suppose that your code is in a service and not in your controller ?
You can't redirect from a service but only from controller as controller send the final response.
You have to return a boolean from your service and redirect from your controller :
public function hasToGoToStart()
{
$em = $this->entityManager;
$repo_whereabouts = $em->getRepository(Whereabouts::class);
$whereabouts = $this->session->get('whereabouts');
if (($whereabouts === null) || ($whereabouts === ''))
{
return true;
}
else
{
$my_whereabouts = $repo_whereabouts->getWhereabouts($whereabouts);
if (!$my_whereabouts)
{
return true;
}
}
return false;
}
and in your controller :
if ($myService->hasToGoToStart()) {
// redirect
}
I am using the REST server by Phil Sturgeon and I was wondering how I can do CSRF Protection properly? Currently I am using this method:
if(stripos($_SERVER["REQUEST_URI"],'API')!=""){
$config['csrf_protection'] = FALSE;
}else{
$config['csrf_protection'] = TRUE;}
However, I have read that this is not the proper way to protect against csrf attacks. I have tried to extend MY_Security but I am unsure of what I need to do after I extend the class. This is the extended class
defined('BASEPATH') OR exit('No direct script access allowed');
class MY_Security extends CI_Security {
public function csrf_verify()
{
// If it's not a POST request we will set the CSRF cookie
if (strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST')
{
return $this->csrf_set_cookie();
}
/**
* mine implementation for application/json
*/
$reqHeaders = getallheaders();
$content_type = $reqHeaders["Content-Type"];
#it's a json request?
if(preg_match("/(application\/json)/i",$content_type))
{
#the check the cookie from request
$reqCookies = explode("; ",$reqHeaders["Cookie"]);
foreach($reqCookies as $c)
{
if(preg_match("/(".$this->_csrf_cookie_name."\=)/", $c))
{
$c = explode("=",$c);
if($_COOKIE[$this->_csrf_cookie_name] == $c[1])
{
return $this;
}
}
}
}
//< end
// Check if URI has been whitelisted from CSRF checks
if ($exclude_uris = config_item('csrf_exclude_uris'))
{
$uri = load_class('URI', 'core');
foreach ($exclude_uris as $excluded)
{
if (preg_match('#^'.$excluded.'$#i'.(UTF8_ENABLED ? 'u' : ''), $uri->uri_string()))
{
return $this;
}
}
}
// Do the tokens exist in both the _POST and _COOKIE arrays?
if ( ! isset($_POST[$this->_csrf_token_name], $_COOKIE[$this->_csrf_cookie_name])
OR $_POST[$this->_csrf_token_name] !== $_COOKIE[$this->_csrf_cookie_name]) // Do the tokens match?
{
$this->csrf_show_error();
}
// We kill this since we're done and we don't want to polute the _POST array
unset($_POST[$this->_csrf_token_name]);
// Regenerate on every submission?
if (config_item('csrf_regenerate'))
{
// Nothing should last forever
unset($_COOKIE[$this->_csrf_cookie_name]);
$this->_csrf_hash = NULL;
}
$this->_csrf_set_hash();
$this->csrf_set_cookie();
log_message('info', 'CSRF token verified');
return $this;
}
}
Do I need to set headers for each json POST or get request? This is an example of what I send to my REST backend
public function user_create_activity($activity){
$this->curl->create(UserCreateActivity);
$this->curl->http_login(REST_KEY_ID,REST_KEY_PASSWORD);
$this->curl->post(array(
'activity' => $activity,
));
return json_decode($this->curl->execute(),true);
}
I am quite unsure if I am on the right path. Hopefully someone can guide me.
Thank you.
I am struggling with PHP login and user validation after they log on to the system. I know the basics but I'm not sure if I'm doing it right. I will try to explain it step by step.
I have a form for user name and password.
After users enter they login and password i'm using LDAP authentication to authorize them. And if authentication pass then i need to start new session.
New session (and this is where i'm struggling).
if ($validation->ldap_authentication())
{
$session = new session();
$session -> login($validation->getUsername(), $validation->logedAs(), $validation->getSID());
if($session->validate_login())
{
exit(header('Location:index2.php'));
}
else
{
echo 'error';
}
}
And my session class:
class session
{
public function __construct()
{
if(!isset($_SESSION))
{
session_name(SESSIONNAME);
ob_start();
session_start();
} else {
session_regenerate_id(true) ;
}
}
public function login($sessionUserName, $logedAs, $sid)
{
$_SESSION['logedUserName'] = isset($sessionUserName) ? $sessionUserName : null;
$_SESSION['logedAs'] = isset($logedAs) ? $logedAs : null;
$_SESSION['sid'] = isset($sid) ? $sid : null;
}
public function validate_login()
{
if (!isset($_SESSION['logedUserName']) || (trim($_SESSION['logedUserName']) == '') ||
!isset($_SESSION['logedAs']) || (trim($_SESSION['logedAs']) == '') ||
!isset($_SESSION['sid']) || (trim($_SESSION['sid']) == '')
)
{
return false;
} else {
return true;
}
}
}
So in the another pages i need to start a class session (again) and validate validate_login()?
For me it looks really poor authentication.
What do I need to add and improve?
I already searched online but couldn't find an answer and don't know what exactly I need to improve.
I'm a beginer in PHP, so my answer might be worthless.
I think you can trust the variable stored in $_SESSION as only the server can access them. So you could have a boolean $_SESSION['loggedIn'] that let you know that the user have gone through the login process successfully, and this variable would be accessible from any page.
I've recently started using Zend Framework and I'm still pretty used to session_start, and assigning variables to certain session names (ie: $_SESSION['username'] == $username)
I'm trying to figure out how to do something similar to this in Zend. Right now, my auth script checks the credentials using LDAP against my AD server and, if successful, authenticates the user.
I want to create a script that will allow an admin user to easily "enter" someone else's session. Let's say admin1 had an active session and wanted to switch into user1's session. Normally I would just change the $_SESSION['username'] variable and effectively change the identity of the user logged in.
But with Zend, I'm not quite sure how to change the session info. For what it's worth, here's my authentication script:
class LoginController extends Zend_Controller_Action
{
public function getForm()
{
return new LoginForm(array(
'action' => '/login/process',
'method' => 'post',
));
}
public function getAuthAdapter(array $params)
{
$username = $params['username'];
$password = $params['password'];
$auth = Zend_Auth::getInstance();
require_once 'Zend/Config/Ini.php';
$config = new Zend_Config_Ini('../application/configs/application.ini', 'production');
$log_path = $config->ldap->log_path;
$options = $config->ldap->toArray();
unset($options['log_path']);
require_once 'Zend/Auth/Adapter/Ldap.php';
$adapter = new Zend_Auth_Adapter_Ldap($options, $username, $password);
$result = $auth->authenticate($adapter);
if ($log_path) {
$messages = $result->getMessages();
require_once 'Zend/Log.php';
require_once 'Zend/Log/Writer/Stream.php';
require_once 'Zend/Log/Filter/Priority.php';
$logger = new Zend_Log();
$logger->addWriter(new Zend_Log_Writer_Stream($log_path));
$filter = new Zend_Log_Filter_Priority(Zend_Log::DEBUG);
$logger->addFilter($filter);
foreach ($messages as $i => $message) {
if ($i-- > 1) { // $messages[2] and up are log messages
$message = str_replace("\n", "\n ", $message);
$logger->log("Ldap: $i: $message", Zend_Log::DEBUG);
}
}
}
return $adapter;
}
public function preDispatch()
{
if (Zend_Auth::getInstance()->hasIdentity()) {
// If the user is logged in, we don't want to show the login form;
// however, the logout action should still be available
if ('logout' != $this->getRequest()->getActionName()) {
$this->_helper->redirector('index', 'index');
}
} else {
// If they aren't, they can't logout, so that action should
// redirect to the login form
if ('logout' == $this->getRequest()->getActionName()) {
$this->_helper->redirector('index');
}
}
}
public function indexAction()
{
$this->view->form = $this->getForm();
}
public function processAction()
{
$request = $this->getRequest();
// Check if we have a POST request
if (!$request->isPost()) {
return $this->_helper->redirector('index');
}
// Get our form and validate it
$form = $this->getForm();
if (!$form->isValid($request->getPost())) {
// Invalid entries
$this->view->form = $form;
return $this->render('index'); // re-render the login form
}
// Get our authentication adapter and check credentials
$adapter = $this->getAuthAdapter($form->getValues());
$auth = Zend_Auth::getInstance();
$result = $auth->authenticate($adapter);
if (!$result->isValid()) {
// Invalid credentials
$form->setDescription('Invalid credentials provided');
$this->view->form = $form;
return $this->render('index'); // re-render the login form
}
// We're authenticated! Redirect to the home page
$this->_helper->redirector('index', 'index');
}
public function logoutAction()
{
Zend_Auth::getInstance()->clearIdentity();
$this->_helper->redirector('index'); // back to login page
}
}
Is there any way to do what I have described? Thanks for any suggestions.
Given your code, the result of authenticating is stored in the PHP session through a Zend_Auth_Storage_Session object.
Calling Zend_Auth::getIdentity() gets access to the storage and returns the result if it is not empty. Likewise, you can change the stored identity by getting access to the underlying storage and changing its value. The actual identity stored as a result of authenticating with Zend_Auth_Adapter_Ldap is just a string value representing the LDAP username.
To effectively change the logged in user, you can do:
Zend_Auth::getInstance()->getStorage()->write('newUserName');
This assumes the default behavior which should be in place given your code.
What I do in my applications after successful authentication is to create a new object of some User model, and write that to the Zend_Auth session so that I have more information about the user available in each session, so you should be aware that different things can be in the storage depending on the application.
This is what I do for example:
$auth = new Zend_Auth(...);
$authResult = $auth->authenticate();
if ($authResult->isValid() == true) {
$userobj = new Application_Model_UserSession();
// populate $userobj with much information about the user
$auth->getStorage()->write($userobj);
}
Now anywhere in my application I call Zend_Auth::getInstance()->getIdentity() I get back the Application_Model_UserSession object rather than a string; but I digress.
The information that should help you is:
$user = Zend_Auth::getInstance()->getIdentity(); // reads from auth->getStorage()
Zend_Auth::getInstance()->getStorage()->write($newUser);
I am developing an ASP.NET Web Service:
# MyWS.cs
[WebMethod(EnableSession = true)]
public bool TryLogin(string user, string pass)
{
if (/* user validation is successful*/)
{
Context.Session["user"] = user;
return true;
}
else
{
Context.Session.Abandon();
return false;
}
}
[WebMethod(EnableSession = true)]
public string RetrieveSomething()
{
if (Context.Session["user"] == null)
throw Exception("User hasn't logged in.");
/* retrieve something */;
}
This ASP.NET must be consumed by a PHP Web site I am developing as well:
# ws_client.php
function get_soap_client()
{
if (!isset($_SESSION['client']))
$_SESSION['client'] = new SoapClient('MyWS.asmx?WSDL');
return $_SESSION['client'];
}
function try_login($user, $pass)
{
return get_soap_client()->TryLogin(
array('user' => $user, 'pass' => $pass))
->TryLoginResult;
}
function retrieve_something()
{
return get_soap_client()->RetrieveSomething(
array())->RetrieveSomethingResult;
}
# index.html
<?php
if (isset($_POST['submit']))
{
session_start();
require_once('ws_client.php');
if (try_login($_POST['user'],
$_POST['pass']))
{
session_write_close();
header('Location: /main.php');
exit();
}
?>
<html> <!-- login form here >
# main.php
<?php
session_start();
require_once('ws_client.php');
// Here I get the Exception "User hasn't logged in.", even though
// the user has logged in and the web service has already been notified.
echo htmlspecialchars(retrieve_something());
?>
What could be wrong with either my Web Service or my PHP site?
I don't know the PHP SOAP tools, but Session state is maintained through a cookie. Will this code accept a cookie the first time, then send it back on subsequent calls?