Iam auth my user with the build in function. But is fatfree not setting the username global? Cant find it
$angemeldet = new \DB\SQL\Mapper($this->db, 'users');
$auth = new \Auth($angemeldet, array('id'=>'name', 'pw'=>'email'));
$auth->basic(); // a network login prompt will display to authenticate the user
This is working.
http://www.willis-owen.co.uk/2013/02/blog-tutorial-with-fat-free-framework-v3/
Here i found that he is setting it in the SESSION. But if i try to access it, its completly empty. Where can i find the username?
And how can i manipulate the password? So i can compare a hash?
The F3 Auth will not set the user to the SESSION by default, you would have to do that yourself. You can't store PDO objects in the SESSION because they can't be serialized. The username will be stored in the SERVER.PHP_AUTH_USER, so you can use that to fetch the $user.
To hash the password, you pass a function to the $auth->basic( function( $password ){} ); and return the hashed password. Using SHA256 with a salt will be much more secure than MD5.
This is the code I am using to do BASIC auth.
// I call this from the constructor of the handler of secure pages.
public static function authenticate(){
// map to the users db table
$user = new \DB\SQL\Mapper( F3::get( 'db' ), 'users' );
// tell F3 to use the columns username and password
$auth = new \Auth( $user, array( 'id'=>'username', 'pw'=>'password' ) );
// check to see if they are authed, use a function to create hashed password
$authenticated = $auth->basic( function ( $password ){
$salt = 'Some secure salt string...';
return hash( 'sha256', $password . $salt );
} );
// if we are logged in and the user isn't set....
if ( $authenticated && !F3::exists( 'user' ) ){
// use SERVER.PHP_AUTH_USER to load user by username
$user->load( array( 'username=?', F3::get( 'SERVER.PHP_AUTH_USER' ) ) );
// set user to variable if it could be loaded
if ( !$user->dry() ){
F3::set( 'user', $user );
}
}
}
Look at the code below:
public function verify($f3, $params) {
$username = $f3->get('POST.email');
$password = $f3->get('POST.password');
$hashedPassword = md5($password);
$submit = $f3->get('POST.submit');
if (isset($submit)) {
global $db;
$user = new DB\SQL\Mapper($db, 'users');
// username is email, password is password in our case
$auth = new \Auth($user, array('id' => 'email', 'pw' => 'password'));
$loginResult = $auth->login($username, $hashedPassword); // Cross-check with users with hashedPassword
// Authenticated the user successfully
if ($loginResult == true) {
$f3->set('message', 'Logged in successfully.');
$f3->reroute('/login');
}
} else {
$f3->set('message', 'Please enter valid username/password');
}
$f3->reroute('/login');
}
In the above code you can see that I have used md5 hash in the password. This might give you idea on what you are trying to achieve.
check the API docs for the basic auth method: http://fatfreeframework.com/auth#basic
i think it should be something like
$auth->basic(function($input){
return md5($input);
});
unfortunately this method does not return any user data on a valid login. but since objects are passed by reference in php, you could try to have a look at the mapper after the auth process, if some data was populated. var_dump($angemeldet->cast());
This is the easiest way to do basic (browser popup) auth, from my experience:
function renderAdmin() {
$user=new DB\SQL\Mapper($this->db,'users');
$auth== null;
$auth = new \Auth($user, array('id'=>'username', 'pw'=>'password'));
$login_result = $auth->basic();
if ($login_result) $f3->set('SESSION.username','SERVER.PHP_AUTH_USER');
if (!$f3->get('SESSION.username')) $f3->error(401);
else {
// all your code for the admin section
echo \Template::instance()->render('admin.html');
}
}
Related
I am just learning about JWT and Authentication in general, its my first real look inside this world so Its all abit overwhelming.
I wanted to add login/general sessions for my new site (Angular 2 SPA), and after abit of research JWT seemed to be the best approach, so I got php-jwt and setup a super basic authentication with my basic database shown here:
class userAuth {
// create an empty id variable to hold the user id
private $id;
private $email;
private $key = "16FD8C979FC40CCB97457F4AD79B32A73758771B4D1943C379FB3266EECE0C3E";
// Checks if the user exists in the database
private function validUser($email, $password) {
$conn = new mysqli(DBSERVER, DBUSERNAME, DBPASSWORD, DBNAME);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$truepassword = hash('sha256', $password); // password hashing using SHA256
$query = $conn->query("select * from users where ( username='$email' OR email = '$email') and password='$truepassword'");
$count = mysqli_num_rows($query);
if($count == 1) {
$row = mysqli_fetch_array($query);
$this->id = $row['id'];
$this->email = $row['email'];
return true;
}else{
return false;
}
}
private function genJWT() {
// Make an array for the JWT Payload
$payload = array(
"id" => $this->id,
"email" => $this->email,
"exp" => time() + (60 * 60)
);
// encode the payload using our secretkey and return the token
return JWT::encode($payload, $this->key);
}
public function checkUser($email, $password) {
// check if the user exists
if ($this->validUser($email, $password)) {
// generate JSON web token and store as variable
$token = $this->genJWT();
$resultJSON = array(
'email' => $this->email,
'token' => $token
);
return json_encode($resultJSON);
} else {
return 'We Couldn\'t Find You In Our Database. Maybe Wrong Email/Password Combination';
}
}
private function validJWT($token) {
$res = array(false, '');
// using a try and catch to verify
try {
//$decoded = JWT::decode($token, $this->key, array('HS256'));
$decoded = JWT::decode($token, $this->key, array('HS256'));
} catch (Exception $e) {
return $res;
}
$res['0'] = true;
$res['1'] = (array) $decoded;
return $res;
}
public function validLogin($token) {
// checks if an email is valid
$tokenVal = $this->validJWT($token);
// check if the first array value is true
if ($tokenVal['0']) {
// create user session and all that good stuff
return "Everything went well, time to serve you what you need.";
} else {
return "There was an error validating your email. Send another link";
}
}
}
And this was good to get my head around the idea of JWT auth, I managed (after hours mind you) to collect the token and save it to local storage on a successful login. but I tried to use a jwt library to properly manage getting info with my token etc I couldnt get it to work, beccause I imagine my setup doesnt provide what the lib expects the token to be formatted or something along those lines
Would it be a good idea to try and just continue and learn as I go in this manner, because at the moment I havnt found many resources or tutorials on building my own JWT backend, or how I would talk to said backend correctly.
I have now setup a basic auth0 account and im looking into/testing that usage, would I be better off learning on my own, or using a lib (happy to be referred to, to other JWT API's that work with angular 2, or would be appropriate for it).
I also dont like the idea of my server backend being someone else's if that makes sense.
I authenticating an user in my application, even with the right credentials , it returns false. Here is my User registration controller
public function store(CreateUserRequest $request)
{
$user = new User();
$password = str_random(10);
$password_hash = Hash::make($password);
$active_hash = Hash::make(str_random(128));
$new_user = $user->create([
'first_name'=>$request->first_name,
'last_name'=>$request->last_name,
'email'=>$request->email,
'telephone'=>$request->fone,
'password'=>$password_hash,
'active_hash'=>$active_hash,
]);
$new_user->permissions()->create(UserPermission::$default);
//send email to the user
Mail::send('admin.emails.auth.new_user',['new_user'=>$new_user,'active_hash'=>$active_hash,'password'=>$password],function($message) use ($new_user){
$message->to($new_user->email)
->from('lilgaetan88#gmail.com','Pacal Gaetan')
->subject("Activate your account");
});
return redirect()->route('home')->with('Success',"mail sent");
}
The user receive the email with the $passowrd = str_random(10), he then copy it and paste in the password field of the login form
LoginController:
public function postLogin(LoginRequest $request){
$remember = ($request->has('remember')) ? true : false;
$email = $request->email;
$password = $request->password;
$auth = Auth::attempt([
'email'=>$email,
'password'=>$password,
'active'=>1
],$remember);
dd($auth);
if($auth) {
return redirect()->intended('/accueil');
}else{
return redirect()->route('login')->with('fail',"User not found");
}
}
There are 2 issues with your code.
First, you don't hash your password when you create a user. It needs to be done due to security reasons. It also will break the authentication if password stored in the database is not a proper hash, as Laravel uses bcrypt hasher internally to verify passwords.
In your store method you need to pass to create() method
'password' => Hash::make($password),
instead of
'password'=>$password,
Secondly, Auth::attempt() requires a plain-text password to be passed. You are hashing the value user provided before calling this method, that's why it doesn't match.
I'm trying to authenticate a user through Ajax in Laravel.
public function authenticate(){
$email = Input::get('email');
$password = Hash::make(Input::get('password'));
if(!filter_var($email, FILTER_VALIDATE_EMAIL)){
return Response::json(["success"=>"true", "login"=>"false", "error_msg"=>"<span style='margin-bottom:20px;' class='val_error_msg'>Email is not valid!</span>"]);
}
elseif(Auth::attempt(['email' => $email, 'password' => $password])){
return Response::json(["success"=>"true", "login"=>"false", "error_msg"=>"<span style='margin-bottom:20px;' class='val_error_msg'>Logged in</span>"]);
}
else{
return Response::json(["success"=>"true", "login"=>"false", "error_msg"=>"<span style='margin-bottom:20px;' class='val_error_msg'>Email/password is wrong</span>"]);
}
}
Ajax call
$.post(
'/login/authenticate', // location of your php script
{ email: $("#log_email").val(), password: $("#log_password").val()}, // any data you want to send to the script
function( data ){ // a function to deal with the returned information
if(data.login=='false'){
$("#login_response").empty();
$("#login_response").append(data.error_msg);
}
});
But I'm getting the Email/password is wrong message all the time even if the credentials are good.
I tried if((User::where('email', $email)->where('pasword', $password)->count())==1) and it worked.
What's wrong in the Auth::attempt() method?
You have to pass the password in plain text to Auth::attempt():
$password = Input::get('password');
Auth::attempt(['email' => $email, 'password' => $password])
Edit
Apparently you are using md5 to hash your password. This is not only insecure but will also not work with Laravel's Auth methods. Use Hash::make() instead when creating the user instead:
$user->password = Hash::make(Input::get('password'));
Three things:
When you attempt to log in, you need to pass in the password pre-hashed
$password = Input::get('password');
Secondly, your return JSON appears to be setting login to false on a valid login attempt. Change it to true:
return Response::json(["success" => 'true', "login" => 'true', "error_msg" => "<span style='margin-bottom:20px;' class='val_error_msg'>Logged in</span>"]);
Thirdly, when you store the user into your database, you must use Hash::make('string') to build their password.
I'm using Moodle's external database plugin and am having a very annoying problem. Here's an example:
username: johndoe#gmail.com logs in with his password and both are saved in an external DB. Moodle grabs that data (username, password) and saves it locally (mysql) with that user's external DB id. Keep in mind the external DB is the main DB where everything happens, Moodle is only for authorized users that need to take tests. So in Moodle, I have:
username: johndoe#gmail.com
password: blabla
userid: 1234
It works great, except for when johndoe#gmail.com decides to update his username/email on the external DB, so he wants it to be johndoe#hotmail.com now. When he tries to log in, it logs in fine, since Moodle checks with the external DB for both username/password. Problem: A new record is created within Moodle for johndoe#hotmail.com with same password AND userid.
My question is: Where can I safely check with the local DB if userid already exists and NOT create a new record? I do not want to update the moodlelib doc because I don't want to have upgrading problems in the future. I can update the External DB plugin, but can't figure out where would be best.
Here's a workaround someone did - https://moodle.org/mod/forum/discuss.php?d=232163 - but it's done in a cron job instead of immediately on Login.
UPDATE:
It looks like I'll have to update moodlelib and the external db plugin, I'll post my solution if nobody posts.
Since nobody replied, this is the best I could come up with. I have my own comments with *UPDATED so you know where I updated the code.
Under \moodle\lib\moodlelib.php
(Unfortunately I had to update this file because of an authentication call that would trigger the duplicate creation).
1) Update function authenticate_user_login(); replace line 4342 - 4382 with:
$authsenabled = get_enabled_auth_plugins();
// *UPDATED - begin
$authplugin = get_auth_plugin('DB');
$userinfo = ($authplugin->get_userinfo($username)) ? $authplugin->get_userinfo($username) : 0;
// *UPDATED - end
// *UPDATED - added second elseif
if ($user = get_complete_user_data('username', $username, $CFG->mnet_localhost_id)) {
// Use manual if auth not set.
$auth = empty($user->auth) ? 'manual' : $user->auth;
if (!empty($user->suspended)) {
add_to_log(SITEID, 'login', 'error', 'index.php', $username);
error_log('[client '.getremoteaddr()."] $CFG->wwwroot Suspended Login: $username ".$_SERVER['HTTP_USER_AGENT']);
$failurereason = AUTH_LOGIN_SUSPENDED;
return false;
}
if ($auth=='nologin' or !is_enabled_auth($auth)) {
add_to_log(SITEID, 'login', 'error', 'index.php', $username);
error_log('[client '.getremoteaddr()."] $CFG->wwwroot Disabled Login: $username ".$_SERVER['HTTP_USER_AGENT']);
// Legacy way to suspend user.
$failurereason = AUTH_LOGIN_SUSPENDED;
return false;
}
$auths = array($auth);
}
elseif ($user = get_complete_user_data('idnumber', $userinfo['idnumber'], $CFG->mnet_localhost_id)) {
$auth = empty($user->auth) ? 'manual' : $user->auth; // use manual if auth not set
if (!empty($user->suspended)) {
add_to_log(SITEID, 'login', 'error', 'index.php', $username);
error_log('[client '.getremoteaddr()."] $CFG->wwwroot Suspended Login: $username ".$_SERVER['HTTP_USER_AGENT']);
$failurereason = AUTH_LOGIN_SUSPENDED;
return false;
}
if ($auth=='nologin' or !is_enabled_auth($auth)) {
add_to_log(SITEID, 'login', 'error', 'index.php', $username);
error_log('[client '.getremoteaddr()."] $CFG->wwwroot Disabled Login: $username ".$_SERVER['HTTP_USER_AGENT']);
$failurereason = AUTH_LOGIN_SUSPENDED; // Legacy way to suspend user.
return false;
}
$auths = array($auth);
}
else {
// Check if there's a deleted record (cheaply), this should not happen because we mangle usernames in delete_user().
if ($DB->get_field('user', 'id', array('username' => $username, 'mnethostid' => $CFG->mnet_localhost_id, 'deleted' => 1))) {
error_log('[client '.getremoteaddr()."] $CFG->wwwroot Deleted Login: $username ".$_SERVER['HTTP_USER_AGENT']);
$failurereason = AUTH_LOGIN_NOUSER;
return false;
}
// Do not try to authenticate non-existent accounts when user creation is not disabled.
if (!empty($CFG->authpreventaccountcreation)) {
add_to_log(SITEID, 'login', 'error', 'index.php', $username);
error_log('[client '.getremoteaddr()."] $CFG->wwwroot Unknown user, can not create new accounts: $username ".$_SERVER['HTTP_USER_AGENT']);
$failurereason = AUTH_LOGIN_NOUSER;
return false;
}
// User does not exist.
$auths = $authsenabled;
$user = new stdClass();
$user->id = 0;
}
2) Same function, replace line 4408 - 4427 with:
if ($user->id) {
// User already exists in database.
if (empty($user->auth)) {
// For some reason auth isn't set yet.
// *UPDATED $DB->set_field('user', 'auth', $auth, array('username'=>$username));
$DB->set_field('user', 'auth', $auth, array('idnumber'=>$user->idnumber));
$user->auth = $auth;
}
// If the existing hash is using an out-of-date algorithm (or the legacy md5 algorithm), then we should update to
// the current hash algorithm while we have access to the user's password.
update_internal_user_password($user, $password);
if ($authplugin->is_synchronised_with_external()) {
// Update user record from external DB.
// *UPDATED $user = update_user_record($username);
$user = $authplugin->update_user_record($username, $user->idnumber);
}
} else {
// Create account, we verified above that user creation is allowed.
$user = create_user_record($username, $password, $auth);
}
Under \moodle\auth\db\auth.php (External DB plugin Lib)
1) Update function update_user_record() to receive the IDNUMBER parameter:
function update_user_record($username, $idnumber='', $updatekeys=false) {
2) Replace line 512 with:
$user = $DB->get_record('user', array('idnumber'=>$idnumber, 'mnethostid'=>$CFG->mnet_localhost_id));
So now, the main function under the moodle lib will check if user exists by username, if not, checks if user ID exists...if so, it will update the user's info with the new info coming from the external DB. It works fine on Moodle 2.4 and 2.6 for me.
This is quite an old answer, but there's an alternative that requires no manual patching.
The OP uses email addresses (instead of arbitrary usernames) to identify users. This behaviour can be maintained by setting Site administration > Plugins > Authentication > Manage authentication > Allow log in via email (authloginviaemail) to true. Now the username can be populated by the (stable) external database ID. Changing email addresses hence won't result in new accounts.
What I'm looking to do is
Authenticate users on bar.com and
Post their credentials to foo.com/login and re-authenticate them without needing to log in again.
Currently, to GET secure pages on foo.com I'm using form-based access via the SecurityServiceProvider and a db-backed UserProvider to authenticate. Works great: any attempt to load a secured route is intercepted by the firewall and then redirected after successful authentication.
What I can't figure out is how to pass the POST variables (username and password) on to the provider instance and forward the user to the supplied route.
Stub POST route:
$app->post('/login', function(Request $req) use ($app) {
$route = $req->request->filter('route');
$username = $req->get('username');
$password = $req->get('password');
/* magic happens...? */
});
Here is an example of using the user provider to load a user check the password matches then setting the token in the security service. So if you put this code into a route you can get access to the Request for your username and password.
$userProvider = $app['security.user_provider.default'];
$user = null;
try {
$user = $userProvider->loadUserByUsername($username);
} catch (UsernameNotFoundException $e)
{
;
}
$encoder = $app['security.encoder_factory']->getEncoder($user);
// compute the encoded password
$encodedPassword = $encoder->encodePassword($password, $user->getSalt());
// compare passwords
if ($user->password == $encodedPassword)
{
// set security token into security
$token = new UsernamePasswordToken($user, $password, 'yourProviderKeyHere', array('ROLE_USER'));
$app['security']->setToken($token);
// redirect or give response here
} else {
// error feedback
}