Laravel 8: how to translate two factor authentication default message - laravel-8

I'm usign Laravel Fortify and i want translate this default message how do it?
The provided two factor authentication code was invalid.
I found this message in this address but this is source and i can't change it
src/Http/Responses/FailedTwoFactorLoginResponse.php
public function toResponse($request)
{
$message = __('The provided two factor authentication code was invalid.');
if ($request->wantsJson()) {
throw ValidationException::withMessages([
'code' => [$message],
]);
}
return redirect()->route('login')->withErrors(['email' => $message]);
}

Did you install and develop Localization? Seems that message only need the locale. for apply the languages things

Related

Where I can find all the DataAnnotations error keys for localization?

I want to localize my application for Russian.
I have this model (simplified):
public class MyModel
{
[Range(1, 100, ErrorMessage = "RangeError")] // - this translates fine
public int? PremiseArea { get; set; }
}
I have .resx file with my custom localization strings and when I enter 200 in input, the error shows in Russian, as I want.
My problem is when I'm entering letters in the input. I get this error:
How to handle these errors? Where to find the list of all the DataAnnotations errors by default?
'Please enter a valid number.' this format looks like a default jquery validation message.
How did you apply the validation?
You can also directly define the validation message in javascript,and then localize the
validation
message, as my following demo. And this is jquery validation documentation.
<script>
$(document).ready(function () {
$('#form1').validate({
rules: {
PremiseArea: { //rule the number and range
number: true,
range: (1, 100)
}
},
messages: {
PremiseArea: {
number:"#Localizer["Please enter a valid number."]", //localize the message
range: "#Localizer["Range Error"]"
}
}
});
});
</script>
There are different type of validation error messages.
Data annotations validation errors
Model binding validation errors
Identity describer validation errors
Custom validation error messages
Additionally, there are browser form validation errors that depends on the field type, and you can override those errors by configuring client side validation.
Each of them requires different approach to be localized.
Data annotation localization:
ASP.Net core multilingual validation messages for forms
Model Binding Errors Localization:
ASP.NET Core Model Binding Error Messages Localization
Identity Errors Localization:
How to translate Identity Password validation messages
Custom Validation Errors Localization:
ASP.NET Core custom validation error message not localized
You can read these articles to learn more about localization in depth:
Developing Multicultural Web Application
Localizing Data Annotations Errors
Localizing Model Binding Errors
Localizing Identity Error Messages
Last but not least:
Configuring all localization settings takes a lot of time and effort, if you want to do it faster I suggest using XLocalizer, it does all settings in simple setup in the startup, additionlly it can do online translation and auto adding for the localizable strings, so you don't fill resources manually, see the docs for more details.

Why is the callback identifier not being invoked?

I'm trying to implement matching a Kerberos authentication with a local user database in CakePHP4. So I installed CakePHP 4 and the Authentication plugin 2.0. Since Kerberos auth is managed by our IIS WebServer, only thing I have to do is check if the authenticated user is known by my webapp.
The callback authentication should let me implement something like this, right ?
So I put this function in Application.php :
<?php
public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
{
$service = new AuthenticationService();
// Define where users should be redirected to when they are not authenticated
$service->setConfig([
'unauthenticatedRedirect' => '/users/login',
'queryParam' => 'redirect',
]);
// Load the authenticators. Session should be first.
$service->loadAuthenticator('Authentication.Session');
$service->loadIdentifier('Authentication.Callback', [
'callback' => function($data) {
// do identifier logic
if (empty($_SERVER['REMOTE_USER'])) {
return new Result(
null,
Result::FAILURE_OTHER,
['message' => 'Unknown user.']
);
} else {
// On vérifie que l'utilisateur est autorisé à utiliser cette application
$users = TableRegistry::getTableLocator()->get('Users');
$remoteUserNoDomain = str_replace("DOMAIN\\", "", $_SERVER['REMOTE_USER']);
$result = $users->find()
->where(['username' => $remoteUserNoDomain]);
if ($result) {
return new Result($result, Result::SUCCESS);
}
return new Result(
null,
Result::FAILURE_OTHER,
['message' => 'Removed user.']
);
}
return null;
}
]);
return $service;
}
But so far, it doesn't seem to work, like it won't call the callback function at all. I tried to put some debug code, exits... Nothing works.
I would assume that you've also done all the other required configuring for authentication to work, ie loading the plugin, adding the authentication middleware, etc.!?
https://book.cakephp.org/authentication/2/en/index.html
That said, identifiers do not do any work on their own, they are being triggered by authenticators in case they actually require them. You only have the Session authenticator loaded, which in its default configuration doesn't make use of identifiers, but even if you configure it to use identifiers (by setting its identify option to true), it will only use them when there already is an identity in the session, then the identifier is being used to validate that identity.
https://github.com/cakephp/authentication/blob/2.3.0/src/Authenticator/SessionAuthenticator.php#L52
I'm not familiar with Kerberos authentication, but if it pre-populates $_SERVER['REMOTE_USER'] (btw. never access superglobals in CakePHP directly, it will only cause trouble down the road), then what you need is a custom authenticator. You could then re-use the password identifier for the ORM access part, as it allows finding something without checking the password (weirdly enough, given its name).
Quick and dirty example based on your snippet:
// src/Authenticator/KerberosAuthenticator.php
namespace App\Authenticator;
use Authentication\Authenticator\AbstractAuthenticator;
use Authentication\Authenticator\Result;
use Authentication\Authenticator\ResultInterface;
use Psr\Http\Message\ServerRequestInterface;
class KerberosAuthenticator extends AbstractAuthenticator
{
public function authenticate(ServerRequestInterface $request): ResultInterface
{
$server = $request->getServerParams();
if (empty($server['REMOTE_USER'])) {
return new Result(null, Result::FAILURE_CREDENTIALS_MISSING);
}
$remoteUserNoDomain = str_replace("DOMAIN\\", "", $server['REMOTE_USER']);
$user = $this->_identifier->identify(['username' => $remoteUserNoDomain]);
if (empty($user)) {
return new Result(
null,
Result::FAILURE_IDENTITY_NOT_FOUND,
$this->_identifier->getErrors()
);
}
return new Result($user, Result::SUCCESS);
}
}
Your service authenticator/identifier setup would then look like this:
$service->loadAuthenticator('Authentication.Session');
$service->loadAuthenticator('Kerberos');
$service->loadIdentifier('Authentication.Password');
Nore sure if you'd then really want to use the session authenticator like that though, ie whether you only want to identify the remote user once per session.

Using CakePHP Form and Basic Authentication together

I've created a simple test site using CakePHP 3.8 and Authentication 1.0 to try it out. I'd like to use both Form and Basic authentication since the intended app will offer REST calls.
The site works properly if the HttpBasic is not included, that is the Login window is displayed. However, with HttpBasic, the site goes directly to basic authentication.
The code is directly from the cookbook.
What am I missing?
public function getAuthenticationService(ServerRequestInterface $request, ResponseInterface $response)
{
$service = new AuthenticationService();
$service->setConfig([
'unauthenticatedRedirect' => '/users/login',
'queryParam' => 'redirect'
]);
$fields = [
'username' => 'user',
'password' => 'password',
];
// Load Identifiers
$service->loadIdentifier('Authentication.Password', compact('fields'));
// Load the authenticators
$service->loadAuthenticator('Authentication.Session');
$service->loadAuthenticator('Authentication.Form', [
'fields' => $fields,
'loginUrl' => '/users/login',
]);
$service->loadAuthenticator('Authentication.HttpBasic');
return $service;
}
As mentioned in the comments, using the form authenticator and the HTTP basic authenticator together won't work overly well, this is due to the fact that the authentication service won't stop executing all loaded authenticators, unless one of them returns a response that indicates successful authentication.
This means that you'd always be presented with the authentication challenge response, and never see your login form. Only the actual authentication part would work in that constellation, ie directly sending your login credentials as form data to the login endpoint.
If you don't actually need the basic auth challenge response that is preventing you from accessing the login form, then you could use a custom/extended authenticator that doesn't cause a challenge response to be returned, which should be as simple as overriding \Authentication\Authenticator\HttpBasicAuthenticator::unauthorizedChallenge():
src/Authenticator/ChallengelessHttpBasicAuthenticator.php
namespace App\Authenticator;
use Authentication\Authenticator\HttpBasicAuthenticator;
use Psr\Http\Message\ServerRequestInterface;
class ChallengelessHttpBasicAuthenticator extends HttpBasicAuthenticator
{
public function unauthorizedChallenge(ServerRequestInterface $request)
{
// noop
}
}
$service->loadAuthenticator(\App\Authenticator\ChallengelessHttpBasicAuthenticator::class);
Also not that you might need to add additional checks in case your application uses the authentication component's setIdentity() method, which would cause the identity to be persisted in the session, even when using stateless authenticators. If you don't want that, then you'd need to test whether the successful authenticator is stateless before setting the identity:
$provider = $this->Authentication->getAuthenticationService()->getAuthenticationProvider();
if (!($provider instanceof \Authentication\Authenticator\StatelessInterface))
{
$this->Authentication->setIdentity(/* ... */);
}

What is the proper way to set up API endpoints for usage with Keystone?

It's not clear in the docs how one would use existing Keystone models to expose API endpoints that return json within a Keystone.js app. I would simply like to be able expose REST API endpoints with Keystone and be able to use the Keystone CMS capabilities to manage content via interacting with those endpoints. Thanks!
Now that they've standardized the admin API I found that it's pretty trivial to use the same methods. For my read only APIs that are powering my react app I've done put something like this in my routes/index.js
router.get('/api/:list/:format(export.csv|export.json)',middleware.initList,require('keystone/admin/server/api/list/download'));
And I've made my own version of the admin initList middleware:
exports.initList = function(req, res, next) {
console.log('req.keystone', req.keystone);
req.keystone = keystone;
req.list = keystone.list(req.params.list);
if (!req.list) {
if (req.headers.accept === 'application/json') {
return res.status(404).json({ error: 'invalid list path' });
}
req.flash('error', 'List ' + req.params.list + ' could not be found.');
}
next();
};
You may consider using:
restful-keystone by #creynders, or
keystone-rest by #danielpquinn
I've never actually used either of these because I have my own implementation, which I will open source once Keystone implements it plugin architecture (see Keystone Issue #912: Proposed Keystone Package Architecture).
I suspect many other similar modules will start surfacing once Keystone is more "plugin friendly".

Firebase authentication not working as expected

I'm following along with the firebase docs about anonymous authentication, but I must be missing something.
Here is my attempt at authenticating:
var dataRef = new Firebase('https://myfirebaseurl.firebaseio.com');
// Log me in
dataRef.authAnonymously(function(error, authData) {
if (error) {
console.log('Login Failed!', error);
} else {
console.log('Authenticated successfully with payload:', authData);
}
});
The result is that I get a 'TypeError: undefined is not a function' message because 'authAnonymously()' is supposedly not defined.
I have 'Enable Anonymous User Authentication' checked for my firebase though... and I don't know what else would keep this from being an option. Is it not offered in the 'Hacker' version?
I am running this locally, so it shouldn't be a domain permissions issue since 'localhost' is included in the default accepted domains.
David was right.
I followed a tutorial on Firebase to setup my angular app, and I assumed that the version that tutorial was using was up to date with the version used in the docs. It was not. Just change your version to the most recent one if you were also silly enough to run into this :P.