0

I am configuring a sign in form from a framework I use every now and then. However, for some reason the $tryagain error keeps populating. I know the information is correct in my database and I even edited the password within the database to remove the hash to eliminate this as the problem.

Does anyone have a clue as to why it keeps throwing the try again error saying the information is wrong? I am able to register a user and then I redirect them to this page to allow them to sign in, so the sign in is the only issue.

Please let me know if you need more code from the framework. I did not want to post loads of code.

ini_set('display_errors', 1);
error_reporting(E_ALL);
require_once 'core/init.php';

if(Input::exists()) {
    if(Token::check(Input::get('token'))) {

        $validate = new Validate();
        $validation = $validate->check($_POST, array(
            'username' => array('required' => true),
            'password' => array('required' => true)
        ));

        if($validation->passed()) {
            $user = new User();

            $remember = (Input::get('remember') === 'on') ? true : false;
            $login = $user->login(Input::get('username'), Input::get('password'), $remember);
            //var_dump($login);

            if($login) {
                Redirect::to('index');
            } else {
                echo $tryagain = '<span class="signinpanel">' . "The information you entered did not match our records." . '</span>';
            }

        } else {
            foreach($validation->errors() as $error) {
                echo $error, '<br>';
            }
        }
    }
}

Form

<?php
    if(Session::exists('home')) {
        echo '<p>' . Session::flash('home') . '</p>';
    }
?>
<form name="Sign In" action="" method="POST" autocomplete="on" accept-charset= "utf-8">
        <div class="field"> 
            <label for="username">Username</label>
            <input type="text" name="username" autocomplete="on" required>
        </div>
        <div class="field">
            <label for="password">Password</label>
            <input type="password" name="password" autocomplete="off" required>
        </div>  
        <div class="field"> 
            <label for="remember">
            <input type="checkbox" name="remember" id="remember"> Remember me
            </label>
        </div><br>
        <input type="hidden" name="token" value="<?php echo Token::generate(); ?>">
        <input type="submit" value="Sign In"> 
    </form> 

Login function

public function login($username = null, $password = null, $remember = false)    {

if(!$username && !$password && $this->exists()) {
    Session::put($this->_sessionName, $this->data()->id);
} else {
    $user = $this->find($username);

    if($user) {
        if($this->data()->password === Hash::make($password, $this->data()->salt)) {
            Session::put($this->_sessionName, $this->data()->id);

            if($remember) {
                $hash = Hash::unique();
                $hashCheck = $this->_db->get('users_session', array('user_id', '=', $this->data()->id));

                if(!$hashCheck->count()) {
                    $this->_db->insert('users_session', array(
                        'user_id' => $this->data()->id,
                        'hash' => $hash
                    ));
                } else {
                    $hash = $hashCheck->first()->hash;
                }

                Cookie::put($this->_cookieName, $hash, Config::get('remember/cookie_expiry'));
            }
            return true;
        }
    }

}
return false;

}

Hash file

class Hash {
    public static function make($string, $salt = '') {
        return hash('sha256', $string . $salt);
    }

    public static function salt($length) {
        return mcrypt_create_iv($length);
    }

    public static function unique() {
        return self::make(uniqid());
    }
}
Becky
  • 2,283
  • 2
  • 23
  • 50

1 Answers1

1

I think your error lies in the check you are making here:

if($this->data()->password === Hash::make($password, $this->data()->salt)) {
        Session::put($this->_sessionName, $this->data()->id);

If I read this correctly you are taking the value that the user has entered and are then creating a brand new Hash of the password with a new random salt being fed in. This value will change every time the code is executed but is (very) unlikely to ever be identical to the input password.

Initially this answer was based on the Laravel libraries:

Instead of using Hash:make use Hash::check as the guard to entering that block:

if(Hash::check($this->data()->password, $password)){
        Session::put($this->_sessionName, $this->data()->id);

This should give a pathway to let the login() function return true.

However, as @becky indicated that they weren't using Laravel a more general answer was needed:

The underlying problem that you have is that you're checking the plaintext password against the encrypted (hashed) password. In all good algorithms this won't be the same thing which is why it's never going to return true from the function.

What you need to do is check the hashed version of what the user has entered: Hash::make($password, $this->data()->salt) with the value that you've stored (because you only store the hashed version). If you can change the code to compare those two values they should be the same and so the identity operator === will return a true value.

Further discussions, and some debugging, indicated that what was coming back from the DB wasn't what was being created on the page by the

Hash::make($password, $this->data()->salt)

statement. On closer inspection it emerged that the length of the column on the db had been reduced from 64 characters to 50. As the Hash::make() function returned a 64-character hash the two could never equate. Remaking that DB column and regenerating the password hashes fixed the problem.

Graham Nicol
  • 163
  • 1
  • 9
  • Thanks. It threw this error though: `Fatal error: Call to undefined method Hash::check()` – Becky Oct 12 '16 at 13:02
  • Apologies, that's the Laravel function from the Auth package, so would be Auth::check(). There's more worked examples [here](https://laravel.com/docs/5.3/authentication#retrieving-the-authenticated-user) – Graham Nicol Oct 12 '16 at 13:14
  • Well my framework appears to be trying to open up an Auth file now using `if(Auth::check($this-`. Error: `Warning: require_once(classes/Auth.php): failed to open stream: N` I added my hash file to my question. – Becky Oct 12 '16 at 13:37
  • It's difficult to second guess which library you're using, `Hash` is a very common name! Which library are you using? – Graham Nicol Oct 12 '16 at 14:00
  • It is not a common one. It is a popular one from a youtube series. It doesn't have a name. – Becky Oct 12 '16 at 14:02
  • Ok. So, the problem that you have is that you're checking the plaintext password against the encrypted (hashed) password. In all good algorithms this won't be the same thing which is why it's never going to return `true` from the function. – Graham Nicol Oct 12 '16 at 14:07
  • What you need to do is check the hashed version of what the user has entered: `Hash::make($password, $this->data()->salt)` with the value that you've stored (because you only store the hashed version). If you can change the code to compare those two values they should be the same and so the identity operator `===` will return a `true`1 value. – Graham Nicol Oct 12 '16 at 14:09
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/125514/discussion-between-graham-nicol-and-becky). – Graham Nicol Oct 12 '16 at 14:15
  • Thanks again for all the help! Just let me know tomorrow when you are on. – Becky Oct 12 '16 at 18:07
  • I got the line we were having issues with to work, but for some reason it is now saying my login variable is not defined, which was never the case before? The fixed code from yesterday: `v=if( $user->data()->password === Cookie::get($cookieName)){` – Becky Oct 13 '16 at 15:25
  • I suspect that this will be something to do with the scope of the variable. There's a reference article [here](http://stackoverflow.com/questions/16959576/reference-what-is-variable-scope-which-variables-are-accessible-from-where-and) that goes through scope in detail for PHP. – Graham Nicol Oct 13 '16 at 16:01
  • The variable works though when I comment out the cookie code we added. – Becky Oct 13 '16 at 16:03
  • I'm slightly lost on which bit of code we're working on now... can you post that into the chat (rather than here) so we're looking at the same thing. – Graham Nicol Oct 13 '16 at 16:37