Grails 2.2.0 - Validation Issue - validation

I have a group domain object with 3 fields - username, password and email address
Prior to saving the object, I obfuscate the email address so its not stored in plaintext in our database as its a business requirement
I noticed some strange behaviour when I call validate on the domain object.
The constraints for the fields are as follows
userName (nullable: false, unique: false,blank: false, size: 4..200,widget: "textField", matches: "[a-zA-Z0-9, .-##~{}!£%&*^()-_]+")
password (nullable: false, unique: false,blank: false, size: 4..200,widget: "textField", password: true, matches: "[a-zA-Z0-9, .-##~{}!£%&*^()-_]+")
emailAddress (nullable: false, unique: false,blank: false, size: 5..200,widget: "textField",email: true, matches: "[a-zA-Z0-9, .-##~{}!£%&*^()-_]+")
For the object, I validate it to ensure all the values are as expected (emailAddress not obfuscated yet)
If valid I obfuscate the email address and then call save with the value of validate: false
The strange behaviour is as follows
If I fill in a valid email Address and a valid password - the object fails validation on the userName field as it cannot be blank
If I fill in a valid email Address and a valid username- the object fails validation on the password field as it cannot be blank and also on the email Address and it shows the obfuscated value of the email address in the message
I thought first that the obfuscation was causing the problem but it works fine in the case of the password field being entered
Its the exact same code flow for both scenarios.
Is it possible that grails is calling the validate method for the scenario where the password field is not filled in after I obfuscate the email address?
The code flow is as follows
def userLoginUserInstance = UserLoginUser.get(params.id)
userLoginUserInstance.properties = params
if (userLoginUserInstance.validate()) {
//perform updates to database by obfuscating email address first - working fine
} else {
def newObfuscatedEmailAddress = userLoginUserInstance.emailAddress.encodeAsBase64();
userLoginUserInstance.setEmailAddress(newObfuscatedEmailAddress);
render(view: "edit", model: [userLoginUserInstance: userLoginUserInstance])
}
The reason the email address is obfuscated when validation fails is that the gsp reads a transient variable which has a getter than deObfuscates the email address. When the above code runs where a username is not set, it works fine and the email address shows as being ok.
If the password is blank, the error for the password shows but also the obfuscated email address shows as being invalid.
On Further analysis, the validation problem is happening when I run the following line of code
userLoginUserInstance.setEmailAddress(newObfuscatedEmailAddress);
I understand why this is happening as userLoginUserInstance is retrieved from the database.
What confuses me is that this doesnt happen in all scenarios

The validation error is happening because you are trying to store a Base64 String into an attribute which has an email-constraint:
"foo#bar.com".encodeAsBase64()
results in
Zm9vQGJhci5jb20=
So now when your User entity is flushed to the database again of course another validation is happening, complaining that this is no valid email address.
The reason, why the validation errors are not raised in all scenarios may be, that you do not enforce a user.save() nor user.save(flush:true).
This means the email address is not updated ad-hock, but some time later. To see better what's going on add another validation block after the email is assigned.

Sorry for not getting back to this sooner
I solved this by passing a new object back to the view and not the object from the database
Because I have a requirement to obfuscate the email address it really overly complicated this use case
Thanks for your help with this one guys
Regards
Damien

Related

How does Djoser account verification system really works under the hood?

So I'm currently in an attempt to make my own account verification system and I'm using some parts of Djoser as a reference. let me try to walk you to my question
Let's say you're to make a new account in Djoser app
you put in the information of your soon to be made account including email
submit the form to the backend
get an email to the whatever email account you put in earlier to verify your account
click the link in your email
get to the verify account page
now in this page there's a button to submit a UID and a token and both of those information lies in the URL.
My question is:
What are those tokens? is it JWT?
How do they work?
How can I implement that in my own projects without djoser?
The answers to your questions are immersed in the own code of djoser.
You can check djoser.email file and in the classes there, they are few methods get_context_data().
def get_context_data(self):
context = super().get_context_data()
user = context.get("user")
context["uid"] = utils.encode_uid(user.pk)
context["token"] = default_token_generator.make_token(user)
context["url"] = settings.ACTIVATION_URL.format(**context)
return context
So get the context in the class where is instance, and in this context add the 'uid' (this is basically str(pk) and coded in base64, check encode_uid()), the 'token' (just a random string created with a Django function from your Secret key; you can change the algorithm of that function and the duration of this token with PASSWORD_RESET_TIMEOUT setting) to use temporary links, and finally the URL according the action which is performed (in this case the email activation).
Other point to consider is in each of this classes has template assigned and you can override it.
Now, in the views, specifically in UserViewSet and its actions perform_create(), perform_update() and resend_activation(), if the Djoser setting SEND_ACTIVATION_EMAIL is True, call to ActivationEmail to send an email to the user address.
def perform_create(self, serializer):
user = serializer.save()
signals.user_registered.send(
sender=self.__class__, user=user, request=self.request
)
context = {"user": user}
to = [get_user_email(user)]
if settings.SEND_ACTIVATION_EMAIL:
settings.EMAIL.activation(self.request, context).send(to)
...
The email is sent and when a user click the link, whether the token is still valid and uid match (djoser.UidAndTokenSerializer), the action activation() of the same View is executed. Change the user flag 'is_active' to True and it may sent another email to confirm the activation.
If you want code your own version, as you can see, you only have to create a random token, generate some uid to identify the user in the way that you prefer. Code a pair of views that send emails with templates that permit the activation.

Laravel - delete password value from request when form is not validated

I'm using FormRequest validation in my Laravel controller method. I'm validating (beside others) fields 'password' and 'password_confirmation'. The rules are:
$rules['password'] = 'required|string|min:8|required_with:password_confirmation';
$rules['password_confirmation'] = 'min:8|required_with:password|same:password';
(I'm not using 'confirmed', because the validation message is always only on the first field, not on the confirmation one)
When the password confirmation does not match thus the validation fails all data does get returned to the form, including the passwords. Is there some way to exclude them from returning only in case of failed validation - so that the user has to manually input them again? I presume it has to be done somewhere in the custom FormValidation class, probably overriding one of its methods - however, how would I go about it? Just delete it from the returning array?
in the password fields of your register.blade.php, remove the old('password') from the value attribute.

Pre-filling a hosted MailChimp signup form with an email address shows validation errors

We're trying to pre-fill the email address field of a hosted MailChimp form. Here's the blog post that talks about exactly this matter: https://blog.mailchimp.com/how-to-pre-fill-items-on-your-mailchimp-hosted-form/.
So here's our Newsletter signup form without any validation errors:
https://camping.us2.list-manage.com/subscribe/post?u=761a52bbd46ab21474b3af314&id=5cc638b5e6.
The problem arises when I add an email address to the URL as the value for the first form field, MERGE0, like this (url-encoding the email address, so # becomes %40):
https://camping.us2.list-manage.com/subscribe/post?u=761a52bbd46ab21474b3af314&id=5cc638b5e6&MERGE0=test%40camping.info.
Now, the form correctly copies the email address into the input field with name MERGE0 but it also displays three validation error messages:
Note: the email address field is mandatory.
When I try to pre-fill the user's first or last name fields adding MERGE1=John or MERGE2=Doe to the form's url, all is well - no error happens. It seems to be a problem with mandatory fields.
I'm arguing that this is a problem on MailChimp's side but they refuse to help saying that this is custom code and none of their business.
Can anybody help fix these errors?
It turned out that the problem was caused by a mistake in the URL.
Instead of camping.us2.list-manage.com/subscribe/POST?u=761a52bbd46ab...
it had to be camping.us2.list-manage.com/subscribe?u=761a52bbd46ab...
And the errors were gone!
This really made sense in the end, because posting the form should actually trigger the validation.

grails validate email customized message

I wanted to customized the error message for email validation when it fails the constraint:
email(size: 1..255, blank: false, email:true)
this displays message like this:
Property [email] of class [class
com.companyname.icmgrails.nonpersistentdomains.UserProfile] with value
[eulinda] is not a valid e-mail address
I could not figure out how to use that and put it in my messages.properties like the example below when email is blank.
com.companyname.icmgrails.nonpersistentdomains.UserProfile.email.blank=Email
should not be blank!
tried solutions:
I used
[com.companyname.icmgrails.nonpersistentdomains.UserProfile.email]
+ notavalidemail or notvalid or notavalidemaladdress or notvalidemaladdress
but was unsucessfull. ANyone can tell me how to use it? thanks
Every constraint specifies the required message code on its reference page in the user guide. In the case of the email constraint you need
com.companyname.icmgrails.nonpersistentdomains.UserProfile.email.email.invalid=Not a valid email address

Remove unnecessary error message with form validation

Using Codeigniter, I'm able to create a function for user authentication.
I have a function that I call to check if the username/password given are valid.
The problem I'm having is, I don't want the code to display "Invalid Login" if a password isn't given. It should read "Password is required" or something like that.
I guess I could NOT require the password field, in that case a blank password would result in a failed log in anyways. However, I want to make sure sql injection doesn't occur.
$this->form_validation->set_rules('username','username','required|callback_authenticate');
$this->form_validation->set_rules('password','password','required');
$this->form_validation->set_message('authenticate','Invalid login. Please try again.');
authenticate function
function authenticate() {
return Current_User::checkLogin($this->input->post('username'),
$this->input->post('password'));
}
I suggest that you create a callback function that you can use as a rule that you can add to the set_rules() function like this:
$this->form_validation->set_rules('password','Password','required|your_callback_function');
This way, the required rule is sure to be called first. When the user types in a password, then the next rule is checked. In this case, it goes through your callback validation function. If the user doesn't enter anything in your password field, then the error message should automatically show that the password is required.
If you want to prevent SQL injection on the password field, add the sha1 or md5 rule to the password field.
Check out the Callbacks: Your own Validation Functions in the Form Validation library.
Also, if you will use the Active Record class instead of manually typing in your query, your queries will be safer since values are automatically escaped by the system. You also have the option to use prepared statements to prevent SQL injection.

Resources