I'm trying to add the field confirm password to an user register form. This is an extract of my domain class:
package usuario
class Usuario {
transient springSecurityService
String password
String confirmarPassword
static constraints = {
password blank: false, password: true, size:5..15, matches:/[\S]+/
confirmarPassword blank:false, password: true, size:5..15, matches:/[\S]+/, validator:{ val, obj ->
if (obj.password != obj.confirmarPassword)
return 'usuario.password.dontmatch'
}
}
static transients = ['confirmarPassword']
static mapping = {
password column: '`password`'
}
Set<Rol> getAuthorities() {
UsuarioRol.findAllByUsuario(this).collect { it.rol } as Set
}
def beforeInsert() {
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}
protected void encodePassword() {
password = springSecurityService.encodePassword(password)
}
}
obj.confirmarPassword is always null so the constraint is never accomplished.
I installed the Grails Templates as it is suggested here. I changed the attribute persistentProperties, but it is only at _form.gsp, and _form.gsp is not used by Grails Fields Plugins. Therefore, the transients attributes don't appear in the Internet Browser.
I copied the generated transients attributes of the _form.gsp to create.gsp:
<fieldset>
<g:form class="form-horizontal" action="create" >
<div class="fieldcontain ${hasErrors(bean: usuarioInstance, field: 'confirmarPassword', 'error')} required">
<label for="confirmarPassword">
<g:message code="usuario.confirmarPassword.label" default="Confirmar Password" />
<span class="required-indicator">*</span>
</label>
<g:field type="password" name="confirmarPassword" maxlength="15" pattern="${usuarioInstance.constraints.confirmarPassword.matches}" required="" value="${usuarioInstance?.confirmarPassword}"/>
</div>
<fieldset>
<f:all bean="usuarioInstance"/>
<div class="form-actions">
<button type="submit" class="btn btn-primary">
<i class="icon-ok icon-white"></i>
<g:message code="default.button.create.label" default="Create" />
</button>
</div>
</fieldset>
</g:form>
</fieldset>
The transients attributes appear on the screen, but obj.confirmarPassword is still null
The last approach I thought is to modify views_fields\default_field.gsp to also use these transients attributes, but I didn't find how. This is the documentation. This is the content of that file:
<%# page defaultCodec="html" %>
<div class="control-group ${invalid ? 'error' : ''}">
<label class="control-label" for="${property}">${label}</label>
<div class="controls">
<%= widget %>
<g:if test="${invalid}"><span class="help-inline">${errors.join('<br>')}</span></g:if>
</div>
</div>
Is it possible with Grails Fields Plugin? Where are the conditions tested, on client or server side? (I think part of the checking is on client side, but all the restrictions are checked again on server side).
Oh that i have i encountered it before .
Declaring
String confirmarPassword
and making it traniset it doesn't work me like this
static transients = ['confirmarPassword']
But
transient confirmarPassword
As you did it for the springService...i don't now why that doesn't work and this , some one may have a better clarification ...
In latest versions of Grails, transient attributes are not binded with form by default. This is the documentation of the bindable constraint. This is how my code would become (I just added bindable: true):
static constraints = {
password blank: false, password: true, size:5..15, matches:/[\S]+/
confirmarPassword bindable: true, blank:false, password: true, size:5..15, matches:/[\S]+/, validator:{ val, obj ->
if (obj.password != obj.confirmarPassword)
return 'usuario.password.dontmatch'
}
}
However, transient attributes are not shown with <f:all bean="usuarioInstance"/>, We have to add these attributes manually: <f:field bean="${usuarioInstance}" property="confirmarPassword" />. It is not an ideal solution. I'll keep this question open some days hoping that someone knows the answer.
UPDATE
In my case, the above solution didn't work either because I'm using Spring Security Core plugin. It gives the next error:
null id in usuario.Usuario entry (don't flush the Session after an exception occurs)
In that case, we have to use a command object. That issue is described (and solved) in this post.
Related
I've created a form that a user updates to update his profile. When I update the details of the user, and I log out and log in again, I get access denied. I found out that the reason for this was with the authority, every time I updated the table, other details were saved, but the authority is lost and as a result, access is denied.
So I would like to assign the role again within the form but without the user having any input. Any advise on how to implement that is appreciated.
below is my gsp;
<div class="form-group">
<label class="col-sm-5 control-label">
Roles
</label>
<div class="col-sm-5 ">
<g:each in="${roles}" var="role" status="i">
<div class="checkbox-inline">
<g:checkBox name="roles" value="${role.id}"
checked="${role.authority == "ROLE_MEMBER" ? 'true': user.hasRole(role)}"/>
<label for="roles[${i}]">${role.authority}</label>
</div>
</g:each>
</div>
</div>
<div class="form-group">
<div class="${hasErrors(bean: user, field: 'natureOfIndividual', 'error')} required">
<label for="natureOfIndividual" class="col-sm-5 control-label">
<g:message code="user.natureOfIndividual.label" default="Nature of Individual"/>
</label>
<div class="col-sm-5">
<g:select name="natureOfIndividual"
from="${['Local', 'Foreign']}"
class="form-control" noSelection="['': '-----Select-----']"
value="${user?.natureOfIndividual}"/>
</div>
</div>
</div>
With this code am not able to see the checkboxes. Still finding out why. But ultimately, I don't want the user to see any checkboxes, I want to assign the authority without his/her input.
I got a solution. In my UserController.groovy, there was updateRoles method that was called in update method. I commented out the method call. And now the roles are not affected after an update. Below is the code;
#Transactional
def update(User user) {
if (user == null) {
transactionStatus.setRollbackOnly()
notFound()
return
}
if (user.hasErrors()) {
transactionStatus.setRollbackOnly()
respond user.errors, view: 'edit'
return
}
boolean passChange = false
if (user.isDirty('password')) {
passChange = true
}
user.save flush: true
//updateRoles(user)
request.withFormat {
form multipartForm {
if (passChange) {
flash.message = "A user with username '${params.username}' and password '${params.password}' has been Updated"
} else {
flash.message = "Your profile has been updated"
}
redirect user
}
'*' { respond user, [status: OK] }
}
}
private updateRoles(User user) {
UserRole.removeAll(user)
List roleIds = params.roles instanceof String ? [params.roles] : params.roles
roleIds?.each { roleId ->
def role = Role.get(roleId)
UserRole.create(user, role, true)
}
}
As you've seen, I have commented out the method call in the update method. So when users update their details, their authorization is still preserved.
I have a User domain with a flag for security officer and a Location domain to hold all locations in my web app. I want to allow an administrator to assign a primary and secondary security officer to any location from a pick list of all users with the security officer flag checked. I have this working in a hand-made MVC structure, but I'm currently playing with scaffolding and have run into a strange error I can't figure out. My Location domain is coded as
class Location {
static hasMany = [users:User]
Integer id
...
String address
String city
State state
String zip
...
User primarySecurityOfficer
User secondarySecurityOfficer
static mapping = {
table 'location'
id generator: 'identity'
sort "state"
version false
}
static constraints = {
...
address(blank: false, nullable: false)
city(blank: false, nullable: false)
state(blank: false, nullable: false)
zip(blank: false, nullable: false, size: 5..5)
...
primarySecurityOfficer(blank: true, nullable: true)
secondarySecurityOfficer(blank: true, nullable: true)
}
}
and I generated the views with grails generate-all Location. I modified the security officer selection in the generated _form.gsp to
<div class="fieldcontain ${hasErrors(bean: locationInstance, field: 'primarySecurityOfficer', 'error')}">
<label for="primarySecurityOfficer">
<g:message code="location.primarySecurityOfficer.label" default="Primary Security Officer" />
</label>
<g:select id="primarySecurityOfficer" name="primarySecurityOfficer" value="${locationInstance?.primarySecurityOfficer?.employeeNumber}" from="${securityOfficers}" optionKey="employeeNumber" optionValue="${{it.firstName + ' ' + it.lastName}}" noSelection="${['null':' ']}" disabled="${disabled}"/>
</div>
<div class="fieldcontain ${hasErrors(bean: locationInstance, field: 'secondarySecurityOfficer', 'error')}">
<label for="secondarySecurityOfficer">
<g:message code="location.secondarySecurityOfficer.label" default="Secondary Security Officer" />
</label>
<g:select id="secondarySecurityOfficer" name="secondarySecurityOfficer" value="${locationInstance?.secondarySecurityOfficer?.employeeNumber}" from="${securityOfficers}" optionKey="employeeNumber" optionValue="${{it.firstName + ' ' + it.lastName}}" noSelection="${['null':' ']}" disabled="${disabled}"/>
</div>
and the controller's create and save auto-generated actions (modified to send the view the security officer list) are
def create() {
def securityOfficers = User.findAll("from User as u where u.securityOfficer='1'")
println params
respond new Location(params), model: [ securityOfficers:securityOfficers ]
}
#Transactional
def save(Location locationInstance) {
def securityOfficers = User.findAll("from User as u where u.securityOfficer='1'")
if (locationInstance == null) {
notFound()
return
}
if (locationInstance.hasErrors()) {
respond locationInstance.errors, view:'create', model: [ securityOfficers: securityOfficers ]
return
}
locationInstance.save flush:true
request.withFormat {
form {
flash.message = message(code: 'default.created.message', args: [message(code: 'locationInstance.label', default: 'Location'), locationInstance.id])
redirect locationInstance
}
'*' { respond locationInstance, [status: CREATED], model: [ securityOfficers:securityOfficers ] }
}
}
The error I'm getting is that if I select any security officers and try to save a new location, I get the error Could not find matching constructor for: User(java.lang.String). If I leave the selector blank, the location will save successfully. Any ideas why?
Edit 1: Interesting find from tinkering around. I can successfully save security officers to locations if I change the view code to
<div class="fieldcontain ${hasErrors(bean: locationInstance, field: 'primarySecurityOfficer', 'error')}">
<label for="primarySecurityOfficer">
<g:message code="location.primarySecurityOfficer.label" default="Primary Security Officer" />
</label>
<g:select id="primarySecurityOfficer.employeeNumber" name="primarySecurityOfficer.employeeNumber" value="${locationInstance?.primarySecurityOfficer?.employeeNumber}" from="${securityOfficers}" optionKey="employeeNumber" optionValue="${{it.firstName + ' ' + it.lastName}}" noSelection="${['null':' ']}" disabled="${disabled}"/>
</div>
<div class="fieldcontain ${hasErrors(bean: locationInstance, field: 'secondarySecurityOfficer', 'error')}">
<label for="secondarySecurityOfficer">
<g:message code="location.secondarySecurityOfficer.label" default="Secondary Security Officer" />
</label>
<g:select id="secondarySecurityOfficer.employeeNumber" name="secondarySecurityOfficer.employeeNumber" value="${locationInstance?.secondarySecurityOfficer?.employeeNumber}" from="${securityOfficers}" optionKey="employeeNumber" optionValue="${{it.firstName + ' ' + it.lastName}}" noSelection="${['null':' ']}" disabled="${disabled}"/>
</div>
But now I cannot save WITHOUT a security officer. The error I get if I attempt to is Unparseable number: "null".
I am using grails 2.1.1. I have a table named audit firm. There are two types of firm. Audit review firm and ca firm. I am saving the value of audit review firm in parent table and ca firm in child table that's why ca firm is a multiple select box. But when I want to edit the audit review firm is selected but ca firms are not selected in the multiple select box. I have searched for it and applied some things but no luck. Can anyone please help me on this please ??!!! Here are my attempts below ::
my parent domain >>>
class DistrictAssignToAuditReviewFirm {
static mapping = {
table('ADT_DIST_ASSN_TO_ADT_RV_FIRM')
version(false)
caFirm cascade: 'all'
}
AuditFirm auditReviewFirm
long CREATED_BY=0
Date CREATED_DATE=new Date()
long UPDATED_BY=0
Date UPDATED_DATE=new Date()
static hasMany = [caFirm: DistrictAssignToAuditReviewFirmDetails]
static constraints = {
auditReviewFirm(nullable: false, blank: false)
CREATED_BY(nullable:true)
CREATED_DATE(nullable:true)
UPDATED_BY(nullable: true)
UPDATED_DATE(nullable: true)
}
String toString(){
return auditReviewFirm
}
}
my child domain >>>
class DistrictAssignToAuditReviewFirmDetails {
static mapping = {
table('ADT_DIST_ASSN_TO_ADT_RV_DETL')
version(false)
}
AuditFirm caFirmDetails
DistrictAssignToAuditReviewFirm distAssnToAdtRevFirm
static constraints = {
caFirmDetails(nullable: false, blank: false)
distAssnToAdtRevFirm(nullable: false, blank: false)
}
String toString(){
return caFirmDetails
}
}
my view page >>>
<div class="col-xs-6">
<div class="form-group">
<label for="auditReviewFirm">
<g:message code="dl" default="Audit Review Firm" />
</label>
<g:select id="auditReviewFirm" name="auditReviewFirm.id" from="${auditReviewFirm}" optionValue="auditFirmName" optionKey="id" noSelection="['':'Select One']" required="" value="${districtAssignToAuditReviewFirmInstance?.auditReviewFirm?.id}" class="form-control"/>
</div>
</div>
<div class="col-xs-6">
<div class="form-group">
<label for="caFirm">
<g:message code="dl" default="CA Firm" />
</label>
<g:select id="caFirm" name="caFirm.id" from="${caFirm}" optionValue="auditFirmName" optionKey="id" multiple="true" required="" value="${districtAssignToAuditReviewFirmInstance?.caFirm?.caFirmDetails?.id}" class="form-control"/>
</div>
</div>
I am trying to configure the spring-security 2.0-RC2 plugin to work with my Grails application. I am able to get it to insert my default admin user with a hashed password into mongodb. I have also configured spring security to use emailAddress instead of username as the username field for authentication.
When I attempt to login (with the correct credentials) I am getting an authentication failed error. I'm a bit stumped as to what I am doing wrong. I probably am missing something small that causes this not to work. My configuration is included below.
In Config.groovy I have the standard configuration and specify usernamePropertyName to point to the email address field instead of username.
grails.plugin.springsecurity.userLookup.userDomainClassName = 'model.Person'
grails.plugin.springsecurity.userLookup.usernamePropertyName='email'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'model.PersonRole'
grails.plugin.springsecurity.authority.className = 'model.Role'
grails.plugin.springsecurity.securityConfigType = SecurityConfigType.InterceptUrlMap
//Configure URL Restrictions
grails.plugin.springsecurity.interceptUrlMap = [
'/login/**': [
'IS_AUTHENTICATED_ANONYMOUSLY'
],
'/static/**': [
'IS_AUTHENTICATED_ANONYMOUSLY'
],
'/**': [
'IS_AUTHENTICATED_REMEMBERED']
]
grails.plugin.springsecurity.password.algorithm = 'SHA-256'
I then have a Person.groovy file that was generated by spring security then modified to change username to email address. The generated PersonRole.groovy and Role.groovy haven't been modified.
package model
class Person {
transient springSecurityService
String id
String firstName
String lastName
String emailAddress
String password
boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired
static transients = ['springSecurityService']
static constraints = {
emailAddress blank: false, unique: true
password blank: false
}
static mapping = { password column: '`password`' }
Set<Role> getAuthorities() {
PersonRole.findAllByPerson(this).collect { it.role } as Set
}
def beforeInsert() {
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}
protected void encodePassword() {
password = springSecurityService.encodePassword(password)
}
}
In my BootStrap.groovy I create a default admin user unless one already exists:
def adminUser = Person.findByEmailAddress('admin#test.com') ?: new Person(
firstName: 'Admin',
lastName: 'User',
emailAddress: 'admin#test.com',
password: springSecurityService.encodePassword('admin'),
enabled: true).save(failOnError: true)
I also created a custom auth.gsp file as follows, but I have also tried using the default one with the same result.
<form action="${postUrl}" method="POST" autocomplete="off">
<h4>Sign in</h4>
<g:if test="${flash.message}">
<div class="alert alert-danger" style="padding: 10px">${flash.message}</div>
</g:if>
<p>
<input type="email" class="form-control" placeholder="Email address" name="j_username" autofocus />
</p>
<p>
<input type="password" class="form-control" placeholder="Password" name="j_password" />
</p>
<input type="submit" class="btn btn-lg btn-primary btn-block" value="${message(code: 'springSecurity.login.button')}" />
</form>
So, does anyone see anything I am missing that would stop authentication from working?
You're double-encoding the password. It's done in the Person class in beforeInsert, and you do it again in the BootStrap code. Change
password: springSecurityService.encodePassword('admin'),
to
password: 'admin',
I am developing MVC app.
I am using Jquery in Creat-Veiw for validate the data.
I am adding the Role and checking whether that Role(or you can say UserName) already exists in DB or not.
If Role already exists then validation message should display and should not be allow to add in db (should not allow to save).
I have a text-box which accepts the Role, on the blur function I have checked whether Role already exists or not.
Every thing working ok, If Role already exists then validation message comes up.
But after clicking on save button it saves in db.
I want to prevent it ? How to do this ?
I have below code of Create View.
#model IEnumerable<PaymentAdviceEntity.Role>
<div id="roleList">
<div class="span6">
<div class="span12 HeaderField2">
Roles
<legend style="margin-bottom:2px;margin-top:5px;"></legend>
</div>
<div class="span12">
<div style="display:inline-block"></div>
<div id="addrole" style="display:none">
<span> #Html.TextBox("RoleName", String.Empty, new { #id = "RoleName",style="margin-bottom:0px;" })</span>
<span>
<input type="button" value="Save" id="btnSave"/>
<input type="button" value="Cancel" id="btnCancel" />
</span>
</div>
<div style="margin-top:5px;">
<span id="RoleNameValidation" style="display:none;color:Red;">Role already exists</span>
</div>
</div>
</div>
For this I am using the below Jquery.
$("#RoleName").blur(function ()
{
var Role_Name = $('#RoleName').val();
//alert(RoleName);
var url = "#Html.Raw(Url.Action("checkForUniqueName","Role",new {#RName = "RoleName"}))";
url = url.replace("RoleName", Role_Name);
$.post(url, function (data)
{
if (data == false) {
$("#RoleNameValidation").show();
$('#RoleName').focus();
}
else {
$("#RoleNameValidation").hide()
}
});
});
and the controller Code is....
public ActionResult checkForUniqueName(string RName)
{
bool Valid = false;
var RoleList = from e in db.Roles
where e.Name.Equals(RName)
select e;
if (RoleList.Count() > 0 )
{
Valid = false;
}
else
{
Valid = true;
}
return Json(Valid, JsonRequestBehavior.AllowGet);
}
You can use validation for this purpose if you don't want to insert duplicate records in database.
Try to create a custom rule using the jQuery Validate plugin (using addMethod) that checks if the role is already exists in database.You can find good help at http://matthewmuro.com/2012/05/08/adding-custom-jquery-validation-to-your-form/