Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Api security controller #570

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
- Enh: Keycloak auth client (e.luhr)
- Fix: Social Network Auth (eluhr)
- Enh #532: /user/registration/register now shows form validation errors
- Enh: Allow/suggest new v3 releases of 2amigos 2fa dependencies: 2fa-library, qrcode-library (TonisOrmisson)
- Enh: Allow/suggest new v3 releases of 2amigos 2fa dependencies: 2fa-library, qrcode-library (TonisOrmisson)
- Ehh: Added all the classes to the Bootstrap.php classMap
- Enh: Added option to disable viewing any other user's profile for non-admin users (TonisOrmisson)
- Ehn: updated Estonian (et) translation by (TonisOrmisson)
- Ehn: use recaptcha.net instead of google.com (Eseperio)
Expand Down
32 changes: 30 additions & 2 deletions src/User/Bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ protected function initUrlRestRoutes(WebApplication $app)
{
/** @var Module $module */
$module = $app->getModule('user');
$rules = $module->adminRestRoutes;
$rules = array_merge($module->adminRestRoutes, $module->restRoutes);
$config = [
'class' => 'yii\web\GroupUrlRule',
'prefix' => $module->adminRestPrefix,
Expand Down Expand Up @@ -399,26 +399,54 @@ protected function buildClassMap(array $userClassMap)
'Assignment',
'Permission',
'Role',
'SessionHistory'
'SessionHistory',
'AbstractAuthItem',
'Rule',
],
'Da\User\Search' => [
'UserSearch',
'PermissionSearch',
'RoleSearch',
'SessionHistorySearch',
'RuleSearch',
'AbstractAuthItemSearch',
],
'Da\User\Form' => [
'RegistrationForm',
'ResendForm',
'LoginForm',
'SettingsForm',
'RecoveryForm',
'GdprDeleteForm',
],
'Da\User\Service' => [
'AccountConfirmationService',
'AuthItemEditionService',
'AuthRuleEditionService',
'EmailChangeService',
'MailService',
'PasswordExpireService',
'PasswordRecoveryService',
'ResendConfirmationService',
'ResetPasswordService',
'SocialNetworkAccountConnectService',
'SocialNetworkAuthenticateService',
'SwitchIdentityService',
'TwoFactorEmailCodeGeneratorService',
'TwoFactorQrCodeUriGeneratorService',
'TwoFactorSmsCodeGeneratorService',
'UpdateAuthAssignmentsService',
'UserBlockService',
'UserConfirmationService',
'UserCreateService',
'UserRegisterService',
],
'Da\User\Helper' => [
'AuthHelper',
'ClassMapHelper',
'MigrationHelper',
'SecurityHelper',
'TimezoneHelper',
]
];

Expand Down
2 changes: 0 additions & 2 deletions src/User/Controller/SecurityController.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
use Da\User\Service\SocialNetworkAuthenticateService;
use Da\User\Traits\ContainerAwareTrait;
use Da\User\Traits\ModuleAwareTrait;
use Da\User\Validator\TwoFactorEmailValidator;
use Da\User\Validator\TwoFactorTextMessageValidator;
use Yii;
use yii\authclient\AuthAction;
use yii\base\InvalidConfigException;
Expand Down
121 changes: 121 additions & 0 deletions src/User/Controller/rest/v1/SecurityController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<?php

/*
* This file is part of the 2amigos/yii2-usuario project.
*
* (c) 2amigOS! <http://2amigos.us/>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace Da\User\Controller\rest\v1;

use Da\User\Event\FormEvent;
use Da\User\Form\LoginForm;
use Da\User\Model\User;
use Da\User\Traits\ContainerAwareTrait;
use sizeg\jwt\JwtHttpBearerAuth;
use Yii;
use yii\base\InvalidConfigException;
use yii\base\InvalidParamException;
use yii\filters\Cors;
use yii\rest\Controller;

/**
* Controller that provides REST APIs to login via:
* - JWT (JSON Web Token)
* - login and password
*/
class SecurityController extends Controller
{
use ContainerAwareTrait;

/**
* {@inheritdoc}
*/
public function init()
{
parent::init();
Yii::$app->user->enableSession = false;
Yii::$app->user->loginUrl = null;
}

/**
* {@inheritdoc}
*/
public function behaviors(): array
{
$behaviors = parent::behaviors();

// Set JWT authenticator
$behaviors['authenticator'] = [
'class' => JwtHttpBearerAuth::class,
'optional' => [
'login'
],
];

// Cors filter
$behaviors['corsFilter'] = [
'class' => Cors::class,
];

return $behaviors;
}

/**
* {@inheritdoc}
*/
protected function verbs(): array
{
// Get parent verbs
$verbs = parent::verbs();

// Add new verbs and return
$verbs['login'] = ['POST'];
return $verbs;
}

/**
* Controller action responsible for handling login.
* @return array|User
* @throws InvalidParamException
* @throws InvalidConfigException
*/
public function actionLogin()
{
if (!Yii::$app->user->getIsGuest()) {
return [
'success' => false,
'message' => Yii::t('usuario', 'User is already logged in'),
];
}

/**
* @var LoginForm $form
*/
$form = $this->make(LoginForm::class);

/**
* @var FormEvent $event
*/
$event = $this->make(FormEvent::class, [$form]);

if ($form->load(Yii::$app->request->post(), '')) {
$form->validate();
$this->trigger(FormEvent::EVENT_BEFORE_LOGIN, $event);
if ($form->login()) {
$form->getUser()->updateAttributes([
'last_login_at' => time(),
'last_login_ip' => $this->module->disableIpLogging ? '127.0.0.1' : Yii::$app->request->getUserIP(),
]);

$this->trigger(FormEvent::EVENT_AFTER_LOGIN, $event);
}
$this->trigger(FormEvent::EVENT_FAILED_LOGIN, $event);
}

return $form->getUser();
}
}
6 changes: 6 additions & 0 deletions src/User/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,12 @@ class Module extends BaseModule
'users/<id>' => 'admin/options',
'users' => 'admin/options',
];
/**
* @var array Routes for REST controllers.
*/
public $restRoutes = [
'POST login' => 'rest/v1/security/login',
];

/**
* @return string with the hit to be used with the give consent checkbox
Expand Down
2 changes: 1 addition & 1 deletion src/User/Service/MailService.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public function run()
->send();

if (!$result) {
Yii::error("Email sending failed to '{$this->to}'.", 'mailer');
Yii::error("Email sending failed to '{$this->to}'.", __CLASS__);
}
return $result;
}
Expand Down
2 changes: 1 addition & 1 deletion src/User/Service/PasswordRecoveryService.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public function run()

return true;
} catch (Exception $e) {
Yii::error($e->getMessage(), 'usuario');
Yii::error($e->getMessage(), __CLASS__);

return false;
}
Expand Down
4 changes: 2 additions & 2 deletions src/User/Service/UserCreateService.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,14 @@ public function run()
$model->addError('username', $error_msg);
}
$transaction->rollBack();
Yii::error($error_msg, 'usuario');
Yii::error($error_msg, __CLASS__);
return false;
}
$transaction->commit();
return true;
} catch (Exception $e) {
$transaction->rollBack();
Yii::error($e->getMessage(), 'usuario');
Yii::error($e->getMessage(), __CLASS__);

return false;
}
Expand Down
2 changes: 1 addition & 1 deletion src/User/Service/UserRegisterService.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public function run()
return true;
} catch (Exception $e) {
$transaction->rollBack();
Yii::error($e->getMessage(), 'usuario');
Yii::error($e->getMessage(), __CLASS__);

return false;
}
Expand Down