Yii: How to validatePassword with Edvlerblog\Adldap2 using userprincipalname instead of samaccountname - yii2

Question
Currently looking for how other people handled the validate password function when they need to authenticate with the userprincipalname instead of the Edvlerblog\Adldap2 validatePassword function which uses samaccountname.
Please provide feedback in the comments if you are struggling with
anything specific so we can update the documentation.
Current Implementation
For app/common/model/LoginForm
getUser
The Edvlerblog\Adldap2 getUser() function works, and even caches the queryLdapUserObject, allowing you to fetch any of the AD attributes.
protected function getUser()
{
if ($this->_user === null) {
$this->_user = \Edvlerblog\Adldap2\model\UserDbLdap::findByUsername($this->username);
}
return $this->_user;
}
validatePassword()
Currently, the following validatePassword function does not work for me because in my instance AD must authenticate against the userprincipalname instead of the samaccount name.
public function validatePassword($attribute, $params)
{
if (!$this->hasErrors()) {
$user = $this->getUser();
if (!$user || !$user->validatePassword($this->password)) {
$this->addError($attribute, 'Incorrect username or password.');
}
}
}

A solution
Here is one workaround thanks to the Edvlerblog\Adldap2 who recently released 3.0.5 addressing a couple issues and providing some examples in his readme docs.
Please note the addition of findByAttribute(), allowing the following:
$this->_user = \Edvlerblog\Adldap2\model\UserDbLdap::findByUsername($this->username);
validatePassword() w/ userprincipalname
Update your login model: common\models\LoginForm.php
public function validatePassword($attribute, $params)
{
if (!$this->hasErrors()) {
$user = $this->getUser();
if (!$user) {
$this->addError('username', 'Incorrect username.');
} else {
// Note: queryLdapUserObject is a cached object,
// so the ldap fetch does not get called :-).
$userprincipalname = $this->_user->queryLdapUserObject()->getAttribute('userprincipalname');
$auth = Yii::$app->ad->auth()->attempt($userprincipalname[0], $this->password);
if (!$auth) {
$this->addError('password', 'Incorrect password.');
}
}
}
}
getUser() w/userprincipalname
/**
* Finds user by [[username]]
*
* #return User|null
*/
protected function getUser()
{
if ($this->_user === null) {
$this->_user = \Edvlerblog\Adldap2\model\UserDbLdap::findByUsername($this->username);
}
return $this->_user;
}
Yii2 ldap Component Configuration
Reference: https://github.com/Adldap2/Adldap2/blob/master/docs/configuration.md
Config in your frontend\config\main:
'components' => [
'log' => [... ],
'authManager' => [... ],
'ad' => [
'class' => 'Edvlerblog\Adldap2\Adldap2Wrapper',
'providers' => [
'default' => [
'autoconnect' => true,
'config' => [
'domain_controllers' => ['your.ldap.domain.com'],
'base_dn' => "OU=XXX,OU=XXX,DC=ccccccc,DC=xxxx,DC=com",
'admin_username' => "your_username",
'admin_password' => "your_password",
'port' => 389,
],
],
],
],
],

Related

CakePHP 3 basic authentication get authenticated user

public function beforeSave(Event $event) //for api
{
$hasher = new DefaultPasswordHasher();
$entity->api_key_plain =
Security::hash(Security::randomBytes(32), 'sha256', false);
$entity->api_key = $hasher->hash($entity->api_key_plain);
return true;
}
$this->loadComponent('Auth', [
'authenticate' => [
'Basic' => [
'fields' => ['username' => 'username', 'password' => 'api_key'],
//'finder'=>'apiauth',
'userModel'=>'Students',
],
],
'userModel'=>'Students',
'storage' => 'Memory',
'unauthorizedRedirect' => false,
]);
public function getuser(){
$user=$this->Auth->getUser(); // Auth getUser not found
$header= $this->request->getHeader('Authorization');
$usr =$this->Auth->user(); // Always return null
return $this->jsonResponse($usr,200);
}
how to get authenticated user information form each request in CakePHP 3 AuthComponent
documentation : the getUser() method should return an array of user information on the success or false on failure.

JWT token access from header

I am working with JWT token to make API in Laravel, I want to Make CRUD operation, I already test my API in Postman.
Now the issue is that I want to implement it via Laravel blade views, in postman I can set Authorization Bearer in header, How would I do that in Laravel application? Not in Postman, in short I want to set header, so I can access token in each every request.
Controller:
<?php
class NewController extends Controller
{
public function login(Request $request)
{
$credentials = $request->only('email', 'password');
$token = auth()->attempt($credentials);
return $this->createNewToken($token);
}
public function register(Request $request)
{
$validator = Validator::make($request->all(), [
'name' => 'required|string|between:2,100',
'email' => 'required|string|email|max:100|unique:users',
'password' => 'required|string|confirmed|min:6',
]);
if ($validator->fails()) {
return response()->json(array(
"status" => false,
"errors" => $validator->errors()
), 400);
}
$user = User::create(array_merge(
$validator->validated(),
['password' => bcrypt($request->password)]
));
return response()->json([
'status' => true,
'message' => 'User successfully registered',
'user' => $user
], 201);
}
public function refresh()
{
return $this->createNewToken(auth()->refresh());
}
public function userProfile()
{
return $this->getAuthenticatedUser();
}
public function me()
{
$user = JWTAuth::parseToken()->authenticate();
return response()->json(array($user), 400);
}
protected function createNewToken($token)
{
return response()->json([
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => auth()->factory()->getTTL() * 60,
'user' => auth()->user()
]);
}
public function getAuthenticatedUser()
{
try {
if (!$user = JWTAuth::parseToken()->authenticate()) {
return response()->json(['user_not_found'], 404);
}
} catch (Tymon\JWTAuth\Exceptions\TokenExpiredException $e) {
return response()->json(['token_expired'], $e->getStatusCode());
} catch (Tymon\JWTAuth\Exceptions\TokenInvalidException $e) {
return response()->json(['token_invalid'], $e->getStatusCode());
} catch (Tymon\JWTAuth\Exceptions\JWTException $e) {
return response()->json(['token_absent'], $e->getStatusCode());
}
return response()->json(compact('user'));
}
}
Routes:
'prefix' => 'auth',
], function ($router) {
Route::post('login', [App\Http\Controllers\NewController::class, 'login'])->name('apisignin');
Route::post('getauth', [App\Http\Controllers\NewController::class, 'getAuthenticatedUser'])->name('getAuthenticatedUser');
Route::post('userProfile', [App\Http\Controllers\NewController::class, 'userProfile']);
Route::post('me', [App\Http\Controllers\NewController::class, 'me']);
});

cannot take data from DB and use it in VUE script

I try to take data from DB and use it in VUE script, but in console I see message
GET http://lara7.test/api/furnitura 401 (Unauthorized)
In Chrome devtools Network tab I see response
furnitura
{"message":"Unauthenticated."}
Here is my code
routes\api.php
Route::middleware('auth:api')->group( function () {
Route::resource('furnitura', 'API\FurnituraController');
});
App\Http\Controllers\API\BaseController
namespace App\Http\Controllers\API;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
abstract class BaseController extends Controller
{
public function sendResponse($result, $message)
{
$response = [
'success' => true,
'data' => $result,
'message' => $message,
];
return response()->json($response, 200);
}
public function sendError($error, $errorMessages = [], $code = 404)
{
$response = [
'success' => false,
'message' => $error,
];
if(!empty($errorMessages)){
$response['data'] = $errorMessages;
}
return response()->json($response, $code);
}
}
App\Http\Controllers\API\FurnituraController
namespace App\Http\Controllers\API;
class FurnituraController extends BaseController
{
public function index()
{
$furnitura = Furnitura::all();
return $this->sendResponse($furnitura->toArray(), 'Furnitura retrieved successfully.');
}
}
resources\js\app.js
window.axios = require('axios');
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
...
...
mounted() {
console.log("Vue ROOT instance mounted");
axios.get('/api/furnitura').then(response => this.furnitura = response.data);
console.log(this.furnitura);
},
Maybe, you do not pass the auth: API middleware. You are getting 401 from middleware.
maybe you use token for user validation or API user validation that token is missing

Laravel validation with custom json respons

Quick question.
Would it be possible to changes the JSON validation response of laravel?
This is for a custom API that I am building in Laravel.
Validation process
$validation = $this->validate(
$request, [
'user_id' => 'required',
]);
The response shows up like this in json
{
"message": "The given data was invalid.",
"errors": {
"user_id": [
"The user id field is required."
],
}
}
Preferable it would become something like this.
{
"common:" [
"status": "invalid",
"message": "Param xxxx is required",
],
}
What would be the best way to changes this?
Is it even possible?
Thank you.
You can do this, and it will be reflected globally.
Navigate to below folder and use Controller.php
app/Http/Controllers
use Illuminate\Http\Request;
Write below method in Controller.php and change response as you want.
public function validate(
Request $request,
array $rules,
array $messages = [],
array $customAttributes = [])
{
$validator = $this->getValidationFactory()
->make(
$request->all(),
$rules, $messages,
$customAttributes
);
if ($validator->fails()) {
$errors = (new \Illuminate\Validation\ValidationException($validator))->errors();
throw new \Illuminate\Http\Exceptions\HttpResponseException(response()->json(
[
'status' => false,
'message' => "Some fields are missing!",
'error_code' => 1,
'errors' => $errors
], \Illuminate\Http\JsonResponse::HTTP_UNPROCESSABLE_ENTITY));
}
}
I have tried it with Laravel 5.6, maybe this is useful for you.
#Dev Ramesh solution is still perfectly valid for placing inline within your controller.
For those of you looking to abstract this logic out into a FormRequest, FormRequest has a handy override method called failedValidation. When this is hit, you can throw your own response exception, like so...
/**
* When we fail validation, override our default error.
*
* #param ValidatorContract $validator
*/
protected function failedValidation(\Illuminate\Contracts\Validation\Validator $validator)
{
$errors = $this->validator->errors();
throw new \Illuminate\Http\Exceptions\HttpResponseException(
response()->json([
'errors' => $errors,
'message' => 'The given data was invalid.',
'testing' => 'Whatever custom data you want here...',
], 422)
);
}
I was searching for an answer to this and I think I found a better way. There is an exception handler in a default Laravel app - \App\Exceptions\Handler - and you can override the invalidJson method:
<?php
namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Validation\ValidationException;
class Handler extends ExceptionHandler
{
// ...
protected function invalidJson($request, ValidationException $exception)
{
$errors = [];
foreach ($exception->errors() as $field => $messages) {
foreach ($messages as $message) {
$errors[] = [
'code' => $field,
'message' => $message,
];
}
}
return response()->json([
'error' => $errors,
], $exception->status);
}
}

Login access not working in yii2

Im using yii2 for my project. I need to use two different tables for login (Login page is same). I have two models Admin and User. And i have one LoginFrom for login.
I can login properly but the problem is after logged in i cannot get whether the admin is logged in or the user is logged in.
I have set it in config file (web.php) like below:
'admin' => [
'identityClass' => 'app\models\Admin',
'enableAutoLogin' => false,
'class' => 'yii\web\User',
'authTimeout' => 1200, // in Seconds. 1200 seconds means 20 mins
],
'user' => [
'identityClass' => 'app\models\User',
'enableAutoLogin' => false,
'authTimeout' => 1200
],
So im getting logged in user details by using below method:
\Yii::$app->admin->identity;
\Yii::$app->user->identity;
My problem is if im logged in as admin i can get user values also by using this : \Yii::$app->user->identity; or if im logged in as user i can get admin values by using this : \Yii::$app->admin->identity;.
My LoginForm.php is :
<?php
namespace app\models;
use Yii;
use yii\base\Model;
class LoginForm extends Model
{
public $username;
public $password;
public $rememberMe = true;
private $_user = false;
public function rules()
{
return [
// username and password are both required
[['username', 'password'], 'required'],
// rememberMe must be a boolean value
['rememberMe', 'boolean'],
// password is validated by validatePassword()
['password', 'validatePassword'],
];
}
public function validatePassword($attribute, $params)
{
if (!$this->hasErrors()) {
$user = $this->getUser();
if (!$user || !$user->validatePassword($this->password)) {
$this->addError($attribute, 'Incorrect username or password.');
}
}
}
public function login()
{
if ($this->validate()) {
if(!empty($this->getUser()['phone_number'])) {
return Yii::$app->admin->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0);
} else {
return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0);
}
}
return false;
}
public function getUser()
{
if ($this->_user === false) {
$this->_user = User::findByUsername($this->username);
if(!$this->_user) {
$this->_user = Admin::findByUsername($this->username);
}
}
return $this->_user;
}
}
I cant find the problem and if i logged in identity creating for both the users so i could'nt write access rules in particular controller to allow admin only to access the controller.Please help me :(
From reading the comments I think you should just create a unifying table for the two identities where they both get their IDs from. Then make that the identity class. The reason you are able to see the details in both identity classes is that they have the same ID.