Web Service doesn't keep state between requests - php

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?

Related

PHP Session security key steps

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.

How to bypass web session key when I request device API

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.

PHP Login system hard coded username and password

I had to do a basic login system to protect a page, and I have no access to database so i store the username and password hard coded in php page.
My question is, can this login system hold againts an attack? I need it to hold about 1 month.
Any sugestions to improve will be helpefull.
The code is not in laravel, even if it might look like.
The username and password, will be changed to something stronger of course.
Thank you in advance.
<?php
class UserController {
private $username;
private $password;
private $isLoggedIn = false;
// Credentials
public function credentials() {
$credentials = array(
array(
"username" => "telekom",
"password" => "1234"
),
array(
"username" => "telekom2",
"password" => "1234"
)
);
return $credentials;
}
// Basic login
public function login() {
foreach ($this->credentials() as $credential) {
if ($this->username == $credential['username'] && $this->password == $credential['password']) {
Session::put('username', $this->username);
Session::put('password', $this->password);
$this->isLoggedIn = true;
}
}
}
// Get login status
public function isLoggedIn() {
return $this->isLoggedIn;
}
// Logout
public function logout() {
// Delete all sessions
Session::all();
redirect('/telekom/');
}
// Telekom
public function telekom() {
$form = new Form();
if (Input::get('logout') == 1) {
$this->logout();
}
// Post Data from login form
if (Input::has('username') || Input::has('password')) {
if (!$form->isCsrfValid()) {
$form->errors['CSRF'] = "CSRF Token";
} // CSRF protection is on, comment to disable
if (empty($form->errors)) {
$this->username = Input::get('username');
$this->password = Input::get('password');
// Check Login
$this->login();
if (!$this->isLoggedIn()) {
Session::put('login', 'Username and password do not match.');
} else {
redirect('/telekom/');
}
} else {
Session::put('login', '<p class="color-dark-red"><strong>Errors:</strong></p>
<p>' . $form->displayErrors($form->errors) . '</p>');
}
// Check if session has username and password
} elseif (Session::has('username') && Session::has('password')) {
$this->username = Session::get('username', false);
$this->password = Session::get('password', false);
// Check Login
$this->login();
}
}
}// EOF Class User
// Outside class
$user = new UserController();
// Outside class
if (!$user->isLoggedIn()) {
// display login form
} else {
// display protected content
}
?>
My comments are getting lengthy, so I'll just move them here. I would not recommend you put the username and password in the same file. If PHP ever fails to process the page, it will be dumped as plain text to the user. Even for database connections (where the un/pwd almost have to be stored plain text), most people don't put the information in the same file.
You have a couple options:
Make a separate PHP file that sets your UN/PWD variables, put it somewhere that isn't accessible from outside your server, and include it in index.php. In this case, I wouldn't include the file until right when you're going to compare the variables and let the local scope dump it as soon as possible.
Since this is such basic authentication, you could use Apache's built in password authentication module.
in my opinion, this solution is safe enough when you don't plan to use it forever.
What would I check is setting of your web server - some text editors makes backup copies of edited files, like index.php~, index.php.bkp or so. Make sure whether your web server do not serve those files, if any.
The problem with temporary solutions is that they've never temporary.
Never hard code passwords. Some of the reasons are:
It is harder to keep source code secret than it is a key.
Any vulnerabilities in your site that allow reading of source code may reveal the password.
Passwords from development will end up in production.
It is impossible to change passwords without redeploying.

Logging into Facebook with test account using Selenium

I have some PHP code that creates a Facebook test account in my application using the graph api. I've tested this code out, and it works fine.
I'm having trouble actually logging into Facebook as the test user using Selenium Webdriver (for PHP).
Here's a simplified version of my code:
class FB_OAuthTest extends PHPUnit_Framework_TestCase {
private $fbUtils = null;
private $fbUser = null;
private $startUrl = 'http://my.start.page';
protected function setUp() {
$this->webdriver = new WebDriver(Config::SELENIUM_SERVER, Config::SELENIUM_PORT);
$this->webdriver->connect(Config::BROWSER);
$this->fbUtils = new FBUtils(Config::FB_APP_ID, Config::FB_APP_SECRET);
// create new FB test user here
$this->fbUser = $this->fbUtils->createNewTestUser();
}
protected function tearDown() {
// delete the test user when we're done
if($this->fbUser != null) {
$this->fbUtils->deleteTestUser($this->fbUser->id);
}
$this->webdriver->close();
}
// the magic happens here
public function testOAuth() {
// "login" as test user by requesting the login url that they give
$this->webdriver->get($this->fbUser->login_url);
// start the app workflow: go to a page with a FB OAuth button
$this->webdriver->get($this->startUrl);
$this->assertTrue(isTextPresent("FB_OAuth_Test_Start", $this->webdriver));
// click the button to begin the FB OAuth process
$oAuthButton = $this->webdriver->findElementBy(LocatorStrategy::xpath, "//button[#control='FBLogin1']");
$oAuthButton->click();
// The Facebook login/OAuth dialog shows up now, and forces me to login
// despite first going to the FB user's login url
// sleep for the hell of it, just to make sure the FB login dialog loads
sleep(5);
// Selenium fails here - not finding the input with id='email', despite it existing on the page
$emailField = $this->webdriver->findElementBy(LocatorStrategy::xpath, "//input[id='email']");
if ($emailField) {
$emailField->sendKeys(array($this->fbUser->email));
$emailField->submit();
} else {
$this->fail('FB login email field not found');
}
$passwordField = $this->webdriver->findElementBy(LocatorStrategy::xpath, "//input[id='pass']");
if ($passwordField) {
$passwordField->sendKeys(array($this->fbUser->password));
$passwordField->submit();
} else {
$this->fail('FB login password field not found');
}
$loginButton = $this->webdriver->findElementBy(LocatorStrategy::xpath, "//input[name='login']");
if ($loginButton) {
$loginButton->click();
} else {
$this->fail('FB login button not found');
}
$grantAppPermission = $this->webdriver->findElementBy(LocatorStrategy::name, "grant_clicked");
$grantAppPermission->click();
$this->assertTrue(isTextPresent("FB_OAuth_Test_Success", $this->webdriver));
}
}
As you can see from the code comments, Selenium can't find the 'email' input element, and the test fails. Any ideas would be greatly appreciated. Thanks!
Update
I've even tried doing something fairly direct, like the code blow, and it still doesn't work.
private function loginToFacebook() {
$this->webdriver->get('https://www.facebook.com/login.php?login_attempt=1');
sleep(1);
$emailField = $this->webdriver->findElementBy(LocatorStrategy::xpath, "//input[id='email']");
if ($emailField) {
$emailField->sendKeys(array($this->fbUser->email));
$emailField->submit();
} else {
$this->fail('FB login email field not found');
}
$passwordField = $this->webdriver->findElementBy(LocatorStrategy::xpath, "//input[id='pass']");
if ($passwordField) {
$passwordField->sendKeys(array($this->fbUser->password));
$passwordField->submit();
} else {
$this->fail('FB login password field not found');
}
$loginButton = $this->webdriver->findElementBy(LocatorStrategy::xpath, "//input[name='login']");
if ($loginButton) {
$loginButton->click();
} else {
$this->fail('FB login button not found');
}
}
Update: Here's the Working Code
private function loginToFacebook() {
$this->webdriver->get('https://www.facebook.com/login.php?login_attempt=1');
$emailField = $this->webdriver->findElementBy(LocatorStrategy::id, 'email');
if ($emailField) {
$emailField->sendKeys(array($this->fbUser->email));
} else {
$this->fail('FB login email field not found');
}
$passwordField = $this->webdriver->findElementBy(LocatorStrategy::id, 'pass');
if ($passwordField) {
$passwordField->sendKeys(array($this->fbUser->password));
} else {
$this->fail('FB login password field not found');
}
$loginButton = $this->webdriver->findElementBy(LocatorStrategy::xpath, "//input[#name='login']");
if ($loginButton) {
$loginButton->click();
} else {
$this->fail('FB login button not found');
}
}
You have defined ur xpath expression incorrectly
it should have been //input[#id='email'] ##Note the # sign (not sure you need to escape '#' with a blackslash)
But none the less try changing how you try to locate your web elements
// try locating by LocatorStrategy id
$emailField = $this->webdriver->findElementBy(LocatorStrategy::id, 'email');
if ($emailField) {
$emailField->sendKeys(array($this->fbUser->email));
$emailField->submit();
} else {
$this->fail('FB login email field not found');
}
It is quicker to search by id, name as compared to xpath.
make the same changes for password field as well, like so
$passwordField = $this->webdriver->findElementBy(LocatorStrategy::id, "pass");

How to store and change Zend_Auth session ID?

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);

Categories