Ignore disabled state in custom TYPO3 Validator - validation

I have a plugin with a form where User can register, to avoid duplicate registrations I've added a custom Validator which checks if a FE user already contain the email.
//This is just the isValid method of the custom validator..
public function isValid($value): void
{
$existingUser = $this->frontendUserRepository->findByEmail($value)->getFirst();
if ($existingUser != null) {
$this->addError(
'E-mail already registered',
1592556619
);
}
}
Because of an additional double opt-in mechanism I would like to disable the new created FE user (which is created in the submit action of the registration form), so far so good.
But now my custom validator didn't find users which are disabled when try to find it by email.
So my question is, how can I tell it that he have to ignore the disabled state of the entry.

You will need to configure your repository method to ignore the disabled enable field. (See enablecolumns in TCA.)
You will need to add a custom findOneByEmail() method to your repository and configure the query accordingly:
$query = $this->createQuery();
$query->getQuerySettings()
->setIgnoreEnableFields(true)
->setEnableFieldsToBeIgnored(['disabled']);
Afterwards you can execute the query as usual which will now include disabled users:
$query
->matching($query->equals('email', $email))
->setLimit(1);
return $query->execute()->getFirst();
Notice that you should put this in a separate findOneByEmailIncludingHidden() or similar to avoid unexpected side-effects and make the special behavior of this query method clear.
(You may have noticed that findOneBy* is used here instead of findBy* since that will automatically return the first object.)

Related

How to validate arbitrary conditions when authenticating an user?

Let's say I have an ASP.NET MVC Core application, and I want to validate certain custom conditions when allowing authentication. For example, an user that provides a valid pair of credentials, but is disabled by the application's administrator, or a flag that indicates the user is up-to-date with his payments, or any other arbitrary condition. Is there a place in ASP.NET Core Identity where I can hook this custom validation? I have to make this work for local and external authentication.
For you case, you could create custom user validators.
Writing a custom validator for ASP.NET Core Identity
Custom User Validator That Requires E-Mail Addresses to End in #example.com
This follows a common pattern within Identity, where you can either implement the interface (in this case IValidator<T>) and provide all of the validation code, or override the base implementation of it and add additional logic by overriding methods as I did here.
public class CustomUserValidator : UserValidator<ApplicationUser>
{
public override async Task<IdentityResult> ValidateAsync(UserManager<ApplicationUser> manager,
ApplicationUser user)
{
IdentityResult baseResult = await base.ValidateAsync(manager, user);
List<IdentityError> errors = new List<IdentityError>(baseResult.Errors);
if (!user.Email.EndsWith("#example.com"))
{
IdentityError invalidEmailError = Describer.InvalidEmail(user.Email);
invalidEmailError.Description += " Email address must end with #example.com";
errors.Add(invalidEmailError);
}
return errors.Count > 0 ? IdentityResult.Failed(errors.ToArray()) : IdentityResult.Success;
}
}
Then to plug this in, head over to the Startup.cs file and find the ConfigureServices method. Somewhere before the line starting with services.AddIdentity, add the following line:
services.AddTransient<IUserValidator<ApplicationUser>, CustomUserValidator>();
This will add the implementation of CustomUserValidator to the internal services collection, allowing it to be injected anywhere that an IUserValidator<ApplicationUser> is required.

Make email authentication case insensitive in Laravel 5.7

I use the default email authentication in Laravel 5.7.3 (just updated from 5.4) with a sqlite DB. At login my email address gets validated case sensitive which is not what I want. It should be allowed to login with "JohnDoe#foobar.com" as well as "johndoe#foobar.com".
I've tried to add an accessor at my user model to always lowercase the database value.
public function getEmailAttribute($value) {
return strtolower($value);
}
But this one doesn't seem to be used by Auth at all. Additionally I don't know where to change the user input in the incomming request to lower case.
Is there a simple config case sensitive switch? Or where do I need to change/add scripts?
Thanks for your support
Daniel
Your accessor should be fine, but you should make sure that you also lowercase the given value, e.g. In your controller:
Assuming that you're using the default LoginController shipped from Laravel:
I overwrote the credentials method from AuthenticatesUsers in App\Http\Controllers\Auth\LoginController
protected function credentials(Request $request)
{
$credentials = [
$this->username() => strtolower($request->get($this->username())),
"password" => $request->get("password")
];
return $credentials;
}
This works fine, when all emails stored in the database are already stored all-lowercase. If you're starting from scratch you can enforce the emails to be stored lowercase by default. Just implement the following mutator in your App\User:
public function setEmailAttribute($value)
{
$this->attributes['email'] = strtolower($value);
}
If you have stored mixed-case email already, you can update all emails to lowercase emails using this query:
UPDATE users SET email = LOWER(email);
But this still feels kind of incomplete and you maybe don't want to manipulate your data this way. I am pretty much sure that there are more possibilities to make this happen but unfortunately I am not able to dig into this further for now. However my next attempt would be to extend/write a custom UserProvider.
You have to call getEmailAttribute(/your email here/)
before login and signup like this
$request->email = getEmailAttribute($request->get('email'));

Joomla 2.5 onAfterInitialise event not being triggered

I'm trying to write a single-signon extension so that our MediaWiki users with the correct permissions don't need to log in to our Joomla 2.5. I can't get it to work, because the onAfterInitialise event won't trigger (neither does onAfterRoute or onAfterDispatch if I try to use those instead). I know the extension is actually running because the onUserAuthentication event is triggering and logging me in as my test user.
Below is my code with the two events, the first won't trigger and execute the die() statement, the second triggers after login and unconditionally authenticates me properly.
Is there something I'm missing here like that one extension can't use two different categories of events or something?
class plgAuthenticationMwSSO extends JPlugin {
function __construct( &$subject, $config ) {
parent::__construct( $subject, $config );
}
public function onAfterInitialise() {
die('testing');
}
public function onUserAuthenticate( $creds, $opt, &$response ) {
$response->username = 'Foo';
$response->fullname = 'Foo Bar';
$response->email = 'foo#bar.baz';
$response->status = JAuthentication::STATUS_SUCCESS;
$response->error_message = '';
}
}
You need to put the onAfterInitialise in a system plugin. As a parallel example, notice how the Remember plugin is a system plugin and then the Cookie plugin is an authentication one. System plugins are checked very early in the stack and are checked on every page load. Authentication plugins are checked when authentication starts and are specifically loaded as a group at certain times. Since you have an authentication plugin, it is not triggered at the right time to respond to the system events that you are looking for.

working with session on zf2 (recover container)

PRECEDENTS:
using a custom hack OF ZfcUserLdap to authenticate against a LDAP server (include zfcUser too as dependency)
the hack is due the Ldap server uses a ldapc wrapper, so the bind and search process doesn't belong to Ldap standards but through a ldapc library
the login/password box works great against the Ldap server by modifying the bind and findbyuser methods
NEED:
add country selection at login step
check if the user has the permission to work with this country (so to have the country here has sense, don't need ACL, it will be check through LDAP user groups)
store the selected country to use along the whole application
WORK IN PROGRESS:
add SELECT dropdown with available countries to login box [OK]
get the country selected at the login form [OK]
-> at authenticate method on ZfcUserLdap\Authentication\Adapter\Ldap.php class I get correctly the country set at the form
PROBLEM:
how to store the country into a session variable,
-> since zfcUser has an Storage defined and the country is defined at the login step, I would like to use that Storage
I will appreciate any kind of clarification or tips to accomplish this task.
SOLUTION:
The logic is more at zfcUserLdap module, since the auth is against an LDAP Server.
I added to the Entity extended at zfcUserLdap a new property, country that is set to the Entity object along the findByUsername method.
public function findByUsername($username, $country = null)
{
$pUser = $this->ldap->findByUsername($username);
if (isObjectNotNull($pUser))
{
$this->entity->setDisplayName(getLdapUserFirstName($pUser) . ' ' . getLdapUserLastName($pUser));
$this->entity->setEmail(getLdapUserMail($pUser));
$this->entity->setId(getLdapUserUid($pUser));
$this->entity->setUsername(getLdapUserUid($pUser));
$this->entity->setLdapcObject($pUser);
$this->entity->setUserCountry($country);
return $this->entity;
}
else {
return null;
}
}
To have the country here will be useful because the authentication process might check if the username has permission to work within that country. I'll need to add that check later.
Like this, the country is part of the entity object, so I can get the country at the same way I was able to get the username.
For now, I have create a View Helper very similar to ZfcUserDisplayName. I just update the get metohd to get the country property.
$countryName = $user->getUserCountry();
I plan to create a Controller Plugin to get the country from any Controller.
ZFCUser has an authenticate event that you should leverage for this. IN your Module's main bootstrap:
$sm = $e->getApplication()->getServiceManager();
$zfcAuthEvents = $e->getApplication()->getServiceManager()->get('ZfcUser\Authentication\Adapter\AdapterChain')->getEventManager();
$zfcAuthEvents->attach( 'authenticate', function( $authEvent ) use( $sm ){
try
{
// use $authEvent->getIdentity() to get country and stick it in a session
return true;
}
catch( \Exception $x )
{
// handle it
}
});
How you store in session is up to you, there's 400 ways to skin that cat.

How do order statuses/states work in Magento 1.4.x

As far as I understand Magento have various order statuses under global/sales/order/statuses which can be altered by either copying app/code/core/Mage/Sales/etc/config.xml to local scope or overriding it with your custom module.
There are also global/sales/order/states defined in the same file and as far as I understand states are something like statuses groups. Only states (not statuses) can be set at the order status in magento and statuses are something like states subdivisions. So in administrator interface you can change statuses of a placed order but you can't change state from the order status drop-down (you can change it by either invoicing the client or canceling the order).
As far as I understand you can easily add a new status to your Magento but can't add new state as states are somehow hardcoded with the rest or Magento order processing logic. I really hope that I'm wrong.
Please correct me if I'm wrong in any point as these are just my thoughts and it might be quite far from real Magento 1.4.x flow.
I'm quite sure that 'state' is free data, it can be set to ANY value using the setData option on an order instance. So if you write a custom module that can load an order, set data to one of your new 'states' and test with what ever custom logic you require.
$order = Mage::getModel('sales/order')->load(1);
$order->setData('state','myCustomState');
$order->setData('status','onCustomState');
echo $order->getState()
// Returns myCustomState
its worth bearing in mine that CLOSED/CANCELLED are protected states, so trying to use $order->setState('my_state') will fail on those order, but shouldn't fail on setData so you can overwrite a closed or cancelled order with this method.
if you were to overwrite the order model with a custom one you could add your own logic such as isOnCustomState() and allow the order to be handled in any way just by loading by id.
To add 'custom logic' to your order you could do something copy app\code\core\Mage\Sales\Model\Order.php into your local folder, then you can add functions into that model,
public function isActive(){ if($this->getState() == 'active'){ return true; } else { return false; }
public function isInActive(){ if($this->getState() == 'deactivated'){ return true; } else { return false; }
public function activate(){
if(!$this->isActive()){
$this->setData('state','active');
$this->setData('status','Active Subscription');
// some custom code to start a recuring payment
return $this;
}
}
public function deactiveate(){
if(!$this->isInActive()){
$this->setData('state','deactivated');
$this->sendOrderUpdateEmail(true,'Your subscription has been deactivated.');
// some custom code to stop a recuring payment
return $this;
}
}
now you can load an order and set activate or deactivate on that order to fire your custom code,
$order = Mage::getModel('sales/order')->load(1)->activate();
this code is all untested and just an example of somethings you could try, please don't just dump this code in your model and expect it to work perfectly. in code\core\Mage\Sales\etc\config.xml in the nodes sales/order/states add
<activated translate="label">
<label>Active Subscription</label>
<statuses>
<pending default="1"/>
</statuses>
<visible_on_front/>
</activated>
Magento Order is a finite state machine.
Therefore when you define status it would automatically try to define its state. Altering state directly is not recommended.
When you define status it checks various flags for shipment and invoices and depending in all those it would get the right state. Once order is in approved state however you can easily change status regardless of if there is invoice or any flag etc.

Resources