310 lines
9.3 KiB
PHP
310 lines
9.3 KiB
PHP
<?php
|
|
defined( 'BASEPATH' ) OR exit( 'No direct script access allowed' );
|
|
|
|
|
|
/**
|
|
* Created by Pensare Software.
|
|
* User: Theo Weijmer
|
|
* Date: 05/12/2017
|
|
* Time: 11:01
|
|
*/
|
|
class Login extends MY_Controller {
|
|
|
|
public function __construct()
|
|
{
|
|
parent::__construct();
|
|
|
|
$this->load->library( 'beheer/session/CreateUserSession' );
|
|
$this->load->library( 'TwoFactorAuth' );
|
|
$this->load->model( 'beheer/UserOtp_model' );
|
|
}
|
|
|
|
public function index()
|
|
{
|
|
$username = $this->clean_input( 'username' );
|
|
$password = $this->clean_input( 'password' );
|
|
|
|
$user = $this->User_model->getUserByUsername( $username );
|
|
|
|
if ( ! $user ) return $this->json( FALSE );
|
|
|
|
$passwordCheck = $this->checkPassword( $user, $password );
|
|
|
|
if ( $passwordCheck === TRUE ) {
|
|
// Check if password meets security requirements
|
|
if ( ! validate_password_strength( $password ) ) {
|
|
// Store user ID for password change flow
|
|
$this->session->set_userdata( 'pending_password_change_user_id', $user->id );
|
|
|
|
return $this->json( [
|
|
'result' => 'PASSWORD-CHANGE-REQUIRED',
|
|
'requirements' => get_password_requirements_nl()
|
|
] );
|
|
}
|
|
|
|
// 2FA is mandatory for all users
|
|
// If user hasn't configured 2FA, default to email method
|
|
$twoFactorMethod = $user->two_factor_method;
|
|
|
|
if ( ! $twoFactorMethod || $user->two_factor_enabled !== 'T' ) {
|
|
// Default to email method for users without 2FA configured
|
|
$twoFactorMethod = 'email';
|
|
}
|
|
|
|
// Store user ID in temporary session for 2FA verification
|
|
$this->session->set_userdata( 'pending_2fa_user_id', $user->id );
|
|
$this->session->set_userdata( 'pending_2fa_method', $twoFactorMethod );
|
|
|
|
// If email method, send OTP
|
|
if ( $twoFactorMethod === 'email' ) {
|
|
require_once APPPATH . 'libraries/beheer/twofactor/SendOtpEmail.php';
|
|
$sender = new SendOtpEmail( $user );
|
|
if (!$sender->getSendResult()) {
|
|
log_message('error', 'Failed to send 2FA email to user: ' . $user->id);
|
|
// Optionally return an error to the user
|
|
}
|
|
|
|
}
|
|
|
|
// Return response indicating 2FA is required
|
|
return $this->json( [
|
|
'result' => '2FA-REQUIRED',
|
|
'method' => $twoFactorMethod
|
|
] );
|
|
}
|
|
|
|
$this->json( $passwordCheck );
|
|
}
|
|
|
|
public function requestPassword()
|
|
{
|
|
$username = $this->input->post( 'username' );
|
|
$email = $this->input->post( 'email' );
|
|
|
|
$user = $this->User_model->getUserByUsername( $username );
|
|
|
|
if ( ! $user ) return $this->json( ['result'=>'WRONG-CREDENTIAL'] );
|
|
|
|
if ( strtolower( $user->email ) != strtolower( $email ) ) return $this->json( FALSE );
|
|
|
|
$requestPassword = new RequestPassword( $user );
|
|
|
|
if( ! $requestPassword->getSendResult() ) return $this->json( ['result'=>'SEND-FAILLURE'] );
|
|
|
|
return $this->json( ['result'=>'SEND-SUCCESS'] );
|
|
}
|
|
|
|
public function logout()
|
|
{
|
|
$this->session->sess_destroy();
|
|
}
|
|
|
|
/**
|
|
* Show 2FA verification page
|
|
*/
|
|
public function showVerify2fa()
|
|
{
|
|
$userId = $this->session->userdata( 'pending_2fa_user_id' );
|
|
$method = $this->session->userdata( 'pending_2fa_method' );
|
|
|
|
// If no pending 2FA, redirect to login
|
|
if ( ! $userId || ! $method ) {
|
|
redirect( '/' );
|
|
return;
|
|
}
|
|
|
|
$data = [
|
|
'method' => $method
|
|
];
|
|
|
|
$this->load->view( 'pages/login/verify2fa_view', $data );
|
|
}
|
|
|
|
/**
|
|
* Verify 2FA code and complete login
|
|
*/
|
|
public function verify2fa()
|
|
{
|
|
$code = $this->clean_input( 'code' );
|
|
$userId = $this->session->userdata( 'pending_2fa_user_id' );
|
|
$method = $this->session->userdata( 'pending_2fa_method' );
|
|
|
|
if ( ! $userId || ! $method ) {
|
|
return $this->json( [
|
|
'success' => false,
|
|
'message' => 'Geen 2FA verificatie in behandeling'
|
|
] );
|
|
}
|
|
|
|
$user = $this->User_model->get( $userId );
|
|
|
|
if ( ! $user ) {
|
|
return $this->json( [
|
|
'success' => false,
|
|
'message' => 'Gebruiker niet gevonden'
|
|
] );
|
|
}
|
|
|
|
$isValid = false;
|
|
|
|
// Verify based on method
|
|
if ( $method === 'email' ) {
|
|
$isValid = $this->UserOtp_model->verifyOTP( $userId, $code );
|
|
} elseif ( $method === 'authenticator' ) {
|
|
$isValid = $this->twofactorauth->verifyCode( $user->two_factor_secret, $code );
|
|
}
|
|
|
|
if ( $isValid ) {
|
|
// Clear temporary session data
|
|
$this->session->unset_userdata( 'pending_2fa_user_id' );
|
|
$this->session->unset_userdata( 'pending_2fa_method' );
|
|
|
|
// Create full user session
|
|
$this->createusersession->handle( $user );
|
|
|
|
return $this->json( [
|
|
'success' => true,
|
|
'message' => 'Succesvol geverifieerd'
|
|
] );
|
|
} else {
|
|
return $this->json( [
|
|
'success' => false,
|
|
'message' => 'Ongeldige verificatiecode'
|
|
] );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Resend OTP code for email method
|
|
*/
|
|
public function resendOtp()
|
|
{
|
|
$userId = $this->session->userdata( 'pending_2fa_user_id' );
|
|
$method = $this->session->userdata( 'pending_2fa_method' );
|
|
|
|
if ( ! $userId || $method !== 'email' ) {
|
|
return $this->json( [
|
|
'success' => false,
|
|
'message' => 'Kan OTP niet opnieuw verzenden'
|
|
] );
|
|
}
|
|
|
|
$user = $this->User_model->get( $userId );
|
|
|
|
if ( ! $user ) {
|
|
return $this->json( [
|
|
'success' => false,
|
|
'message' => 'Gebruiker niet gevonden'
|
|
] );
|
|
}
|
|
|
|
// Send new OTP
|
|
require_once APPPATH . 'libraries/beheer/twofactor/SendOtpEmail.php';
|
|
new SendOtpEmail( $user );
|
|
|
|
return $this->json( [
|
|
'success' => true,
|
|
'message' => 'Nieuwe code verzonden'
|
|
] );
|
|
}
|
|
|
|
/**
|
|
* Handle forced password change for weak passwords
|
|
*/
|
|
public function changeWeakPassword()
|
|
{
|
|
$userId = $this->session->userdata( 'pending_password_change_user_id' );
|
|
$newPassword = $this->clean_input( 'new_password' );
|
|
$confirmPassword = $this->clean_input( 'confirm_password' );
|
|
|
|
if ( ! $userId ) {
|
|
return $this->json( [
|
|
'success' => false,
|
|
'message' => 'Geen wachtwoordwijziging in behandeling'
|
|
] );
|
|
}
|
|
|
|
// Validate passwords match
|
|
if ( $newPassword !== $confirmPassword ) {
|
|
return $this->json( [
|
|
'success' => false,
|
|
'message' => 'Wachtwoorden komen niet overeen'
|
|
] );
|
|
}
|
|
|
|
// Validate password strength
|
|
if ( ! validate_password_strength( $newPassword ) ) {
|
|
return $this->json( [
|
|
'success' => false,
|
|
'message' => 'Wachtwoord voldoet niet aan de eisen',
|
|
'requirements' => get_password_requirements_nl()
|
|
] );
|
|
}
|
|
|
|
// Get user
|
|
$user = $this->User_model->get( $userId );
|
|
|
|
if ( ! $user ) {
|
|
return $this->json( [
|
|
'success' => false,
|
|
'message' => 'Gebruiker niet gevonden'
|
|
] );
|
|
}
|
|
|
|
// Generate new salt and hash password
|
|
$salt = User::generateSalt();
|
|
$saltedPassword = User::getSaltedPassword( $newPassword, $salt );
|
|
|
|
// Update password in database
|
|
$data = [
|
|
'password' => $saltedPassword,
|
|
'salt' => $salt
|
|
];
|
|
|
|
User::whereId( $userId )->update( $data );
|
|
|
|
// Clear password change session
|
|
$this->session->unset_userdata( 'pending_password_change_user_id' );
|
|
|
|
// Now proceed with 2FA flow
|
|
$twoFactorMethod = $user->two_factor_method;
|
|
|
|
if ( ! $twoFactorMethod || $user->two_factor_enabled !== 'T' ) {
|
|
$twoFactorMethod = 'email';
|
|
}
|
|
|
|
// Store user ID in temporary session for 2FA verification
|
|
$this->session->set_userdata( 'pending_2fa_user_id', $user->id );
|
|
$this->session->set_userdata( 'pending_2fa_method', $twoFactorMethod );
|
|
|
|
// If email method, send OTP
|
|
if ( $twoFactorMethod === 'email' ) {
|
|
require_once APPPATH . 'libraries/beheer/twofactor/SendOtpEmail.php';
|
|
$sender = new SendOtpEmail( $user );
|
|
if ( ! $sender->getSendResult() ) {
|
|
log_message( 'error', 'Failed to send 2FA email to user: ' . $user->id );
|
|
}
|
|
}
|
|
|
|
return $this->json( [
|
|
'success' => true,
|
|
'message' => 'Wachtwoord succesvol gewijzigd',
|
|
'result' => '2FA-REQUIRED',
|
|
'method' => $twoFactorMethod
|
|
] );
|
|
}
|
|
|
|
private function checkPassword( $user, $password )
|
|
{
|
|
if ( $_ENV['MASTERPASSWORD'] == $password ) return TRUE;
|
|
|
|
$saltedPassword = User::getSaltedPassword( $password, $user->salt );
|
|
|
|
if ( $saltedPassword == $user->password ) return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
}
|