I'm having some hard time figuring out what's wrong in this simple code:
This is a command I made for changing the password:
package myapp.commands
import org.springframework.web.context.request.RequestContextHolder as RCH
import myapp.User
class PasswordCommand {
String currentPassword
String password
String passwordConfirm
private u
User getUser() {
def id = RCH.requestAttributes.session?.user?.id
if (!u && id) {
u = User.get(id)
}
return u
}
static constraints = {
currentPassword blank: false, validator: { val, cmd ->
if (cmd.user && cmd.user.password != val)
return "user.password.invalid"
}
...
}
And in the appropriate controller I use this action:
def doPassword = { PasswordCommand cmd ->
if (!cmd.hasErrors()) {
User user = cmd.getUser()
...
Unfortunately, I get an Error 500 when I try to change the password:
URI: /Myapp/user/doPassword
Class: java.lang.NoSuchMethodError
Message: PasswordCommand.validate()Z
What is going on ?!
Add the #Validateable annotation:
import grails.validation.Validateable
...
#Validateable
class PasswordCommand {
...
}
Related
Been working on a small project to and whenever I call any function of assemblyscript contract, I get "instantiation error". Heres the log:
Log Image
Scheduling a call:
dev-1643739174146-18174234067579.init({"owner":"$OWNER"})
Doing
account.functionCall() Receipt:
5CnMQ2RB2hHbDYTW6BecYfcYznLVqWuz3icVSXuXJcCj
Failure [dev-1643739174146-18174234067579]: Error: Error happened during instantiation
ServerTransactionError: Error happened
during instantiation
at Object.parseResultError (/mnt/c/Users/d4r18/AppData/Roaming/npm/node_modules/near-cli/node_modules/near-api-js/lib/utils/rpc_errors.js:31:29)
at Account.signAndSendTransactionV2 (/mnt/c/Users/d4r18/AppData/Roaming/npm/node_modules/near-cli/node_modules/near-api-js/lib/account.js:160:36)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async scheduleFunctionCall (/mnt/c/Users/d4r18/AppData/Roaming/npm/node_modules/near-cli/commands/call.js:57:38)
at async Object.handler (/mnt/c/Users/d4r18/AppData/Roaming/npm/node_modules/near-cli/utils/exit-on-error.js:52:9)
Heres my modules.ts:
import { Context, u128, PersistentVector } from 'near-sdk-as';
#nearBindgen
export class Note {
private content: string;
constructor(public text: string) {
this.content = text;
}
delete(): void {
this.content = "";
}
edit(note: string, append: bool = false): string {
if (append)
this.content.concat(note);
else
this.content = note;
return this.content;
}
get(): string {
return this.content;
}
}
#nearBindgen
export class Vector<T> extends PersistentVector<T>{
get_all(): Array<T> {
const result = new Array<T>();
for (let i = 0; i < this.length; i++) {
const entry = this[i];
result.push(entry);
}
return result;
}
}
and heres the index.ts
import { Context, logging, storage } from 'near-sdk-as'
import { Note, Vector } from './modules'
#nearBindgen
export class Contract {
private owner: string;
private notes: Vector<Note> = new Vector<Note>('m');
private message: Note;
constructor(master: string) {
this.owner = master;
}
#mutateState()
create(note: string): bool {
// this.message = new Note(note);
console.log("this.message.get()");
return true;
}
list(): Array<Note> {
return this.notes.get_all();
}
private assert_owner(): void {
const caller = Context.predecessor;
assert(
this.owner == caller,
'Only the owner of this contract may call this method'
);
}
}
Would be great help if anyone could help me with this.
The "console.log" statement was causing the problem. Removing it fixed the issue.
I instead used logger.log() method for it. It can be imported from "near-sdk-as"
import { Context, logging, storage } from 'near-sdk-as'
import { Note, Vector } from './modules'
#nearBindgen
export class Contract {
private owner: string;
private notes: Vector<Note> = new Vector<Note>('m');
private message: Note;
constructor(master: string) {
this.owner = master;
}
#mutateState()
create(note: string): bool {
// this.message = new Note(note);
// Remove the console.log line
// console.log("this.message.get()");
return true;
}
list(): Array<Note> {
return this.notes.get_all();
}
private assert_owner(): void {
const caller = Context.predecessor;
assert(
this.owner == caller,
'Only the owner of this contract may call this method'
);
}
}
I've been banging my head against the wall trying to figure out what's going wrong here for a while. I created a simple Ktor server that allows you to create a user, which should return a token to the user and store the session. Then I want an authenticated endpoint to allow the user to be deleted. However, the authenticated call loads an empty session, and can't find the user, so the user can't be deleted. Any help would be appreciated! Code here:
Application.kt
...
fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args)
#Suppress("unused")
#kotlin.jvm.JvmOverloads
fun Application.module(testing: Boolean = false) {
install(Locations) {
}
install(Sessions) {
cookie<MySession>("MY_SESSION") {
cookie.extensions["SameSite"] = "lax"
}
}
DatabaseFactory.init()
val db = MyRepository()
val jwtService = JwtService()
val hashFunction = { s: String -> hash(s) }
install(Authentication) {
jwt("jwt") { //1
verifier(jwtService.verifier) // 2
realm = "My Server"
validate { // 3
val payload = it.payload
val claim = payload.getClaim("id")
val claimString = claim.asInt()
val user = db.findUser(claimString) // 4
user
}
}
}
install(ContentNegotiation) {
gson {
}
}
routing {
users(db, jwtService, hashFunction)
}
}
UserRoute.kt
...
const val USERS = "$API_VERSION/users"
const val USER_CREATE = "$USERS/create"
const val USER_DELETE = "$USERS/delete"
#KtorExperimentalLocationsAPI
#Location(USER_CREATE)
class UserCreateRoute
#KtorExperimentalLocationsAPI
#Location(USER_DELETE)
class UserDeleteRoute
#KtorExperimentalLocationsAPI
fun Route.users(
db: Repository,
jwtService: JwtService,
hashFunction: (String) -> String
) {
post<UserCreateRoute> {
val request = call.receive<CreateUserRequest>()
val password = request.password
?: return#post call.respond(
HttpStatusCode.Unauthorized, "Missing Fields")
val email = request.email
?: return#post call.respond(
HttpStatusCode.Unauthorized, "Missing Fields")
val hash = hashFunction(password)
try {
val newUser = db.addUser(email, hash)
newUser?.userId?.let {
call.sessions.set(MySession(it))
call.respondText(
jwtService.generateToken(newUser),
status = HttpStatusCode.Created
)
}
} catch (e: Throwable) {
call.respond(HttpStatusCode.BadRequest, "Problems creating User")
}
}
authenticate("jwt") {
delete<UserDeleteRoute> {
try {
val userId = call.sessions.get<MySession>()?.userId
if (userId == null) {
call.respond(
HttpStatusCode.BadRequest, "Problem retrieving User")
return#delete
}
if (db.deleteUser(userId)) {
call.respond(HttpStatusCode.NoContent, "User deleted")
} else {
call.respond(HttpStatusCode.BadRequest, "Failed to delete user")
}
} catch (e: Exception) {
application.log.error("Failed to delete user")
call.respond(HttpStatusCode.BadRequest, "Failed to delete user")
}
}
}
}
Is there something I'm missing? The token is returned successfully, and then my delete request is routed to the right place, but the line val userId = call.sessions.get<MySession>()?.userId returns null every time.
You don't show the client code but it is just as important. Likely the problem is on the client not on server. When the clients does the delete does it send the token?
jwt would be more complicated for for basic auth after you get a session each request must include the session header:
curl -H "MY_SESSION: f152dad6e955ba53" -D - localhost:8080/api/admin/principle
I have a Grails domain class. I would like to add a validation such that when the application is running in TEST environment, the domain class can't have more than 100 records.
I can't figure out the best way to add this type of validation. I am on Grails 2.5.3.
This is what I have so far.
class MyDomain {
String test
static constraints = {
test blank: false, nullable: false
id blank: false, validator: {value, command ->
if (Environment.current == Environment.TEST) {
//do validation for not allowing more than 100 records
}
}
}
How can I add this validation?
Solution for a single domain
What #Joshua answered is perfectly fine but there are few other ways. One of them is:
class MyDomain {
String test
void beforeInsert() {
if (Environment.current == Environment.TEST) {
MyDomain.withNewSession {
if (MyDomain.count() == 100) {
throw new Exception("Not allowing more than 100 records")
}
}
}
}
static constraints = {
test blank: false
}
}
Also, please note two things:
The blank: false on the id field of no use since it is not a string because blank constraint is applicable on a String
The nullable: false is of no use since the default value of nullable constraint is false
Generic solution for across domain TL;DR
If you want this behavior across multiple domains, copying the same code is not recommended as your code won't be DRY. For that, you can register a custom event listener:
First define a Java annotation in src/groovy:
import java.lang.annotation.Documented
import java.lang.annotation.ElementType
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
import java.lang.annotation.Target
#Documented
#Target([ElementType.TYPE, ElementType.FIELD])
#Retention(RetentionPolicy.RUNTIME)
public #interface LimitRowsFoo {
int value() default 100
}
Now define another Groovy class:
import grails.util.Environment
import org.grails.datastore.mapping.engine.event.PreInsertEvent
import org.grails.datastore.mapping.engine.event.AbstractPersistenceEvent
import org.grails.datastore.mapping.engine.event.AbstractPersistenceEventListener
class PreInsertEventListener extends AbstractPersistenceEventListener {
PreUpdateEventListener(final Datastore datastore) {
super(datastore)
}
#Override
protected void onPersistenceEvent(AbstractPersistenceEvent event) {
// Instance of domain which is being created
Object domainInstance = event.entityObject
if (Environment.current == Environment.TEST) {
if (domainInstance.class.isAnnotationPresent(LimitRowsFoo.class)) {
// Just using any domain reference here
MyDomain.withNewTransaction {
int maxRows = domainInstance.class.getAnnotation(LimitRowsFoo.class).value()
if (domainInstance.class.count() == maxRows) {
event.cancel()
}
}
}
}
}
#Override
boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
// Only allow PreInsert event to be listened
eventType.name == PreInsertEvent.class.name
}
}
Now register this in Bootstrap.groovy:
application.mainContext.eventTriggeringInterceptor.datastores.each { k, datastore ->
applicationContext.addApplicationListener new PreInsertEventListener(datastore)
}
Now, in your domain, all you have to do is like these:
#LimitRowsFoo
class MyDomain {
String test
static constraints = {
test blank: false
}
}
#LimitRowsFoo(value = 200) // to limit records to 200
class MyAnotherDomain {
String name
}
Wouldn't something like this do the trick for you?
class MyDomain {
String test
static constraints = {
test blank: false, nullable: false
id blank: false, validator: {value, command ->
if (Environment.current == Environment.TEST) {
//do validation for not allowing more than 100 records
if (MyDomain.count() > 100) return ['too.many.records']
}
}
}
I have created the RegisterController.groovy out of the spring ui package.
When I created it, it looked like that:
class RegisterController extends grails.plugin.springsecurity.ui.RegisterController{
}
Then I just copied the initial RegisterController.groovy into my template.
package com.testApplication.register
import grails.plugin.springsecurity.SpringSecurityUtils
import grails.plugin.springsecurity.authentication.dao.NullSaltSource
import grails.plugin.springsecurity.ui.RegistrationCode
import groovy.text.SimpleTemplateEngine
class RegisterController extends grails.plugin.springsecurity.ui.RegisterController {
// override default value from base class
static defaultAction = 'index'
// override default value from base class
static allowedMethods = [register: 'POST']
def mailService
def messageSource
def saltSource
def index() {
def copy = [:] + (flash.chainedParams ?: [:])
copy.remove 'controller'
copy.remove 'action'
[command: new RegisterCommand(copy)]
}
def register(RegisterCommand command) {
if (command.hasErrors()) {
render view: 'index', model: [command: command]
return
}
String salt = saltSource instanceof NullSaltSource ? null : command.username
def user = lookupUserClass().newInstance(email: command.email, username: command.username,
accountLocked: true, enabled: true)
RegistrationCode registrationCode = springSecurityUiService.register(user, command.password, salt)
if (registrationCode == null || registrationCode.hasErrors()) {
// null means problem creating the user
flash.error = message(code: 'spring.security.ui.register.miscError')
flash.chainedParams = params
redirect action: 'index'
return
}
String url = generateLink('verifyRegistration', [t: registrationCode.token])
def conf = SpringSecurityUtils.securityConfig
def body = conf.ui.register.emailBody
if (body.contains('$')) {
body = evaluate(body, [user: user, url: url])
}
mailService.sendMail {
to command.email
from conf.ui.register.emailFrom
subject conf.ui.register.emailSubject
html body.toString()
}
render view: 'index', model: [emailSent: true]
}
def verifyRegistration() {
def conf = SpringSecurityUtils.securityConfig
String defaultTargetUrl = conf.successHandler.defaultTargetUrl
String token = params.t
def registrationCode = token ? RegistrationCode.findByToken(token) : null
if (!registrationCode) {
flash.error = message(code: 'spring.security.ui.register.badCode')
redirect uri: defaultTargetUrl
return
}
def user
// TODO to ui service
RegistrationCode.withTransaction { status ->
String usernameFieldName = SpringSecurityUtils.securityConfig.userLookup.usernamePropertyName
user = lookupUserClass().findWhere((usernameFieldName): registrationCode.username)
if (!user) {
return
}
user.accountLocked = false
user.save(flush:true)
def UserRole = lookupUserRoleClass()
def Role = lookupRoleClass()
for (roleName in conf.ui.register.defaultRoleNames) {
UserRole.create user, Role.findByAuthority(roleName)
}
registrationCode.delete()
}
if (!user) {
flash.error = message(code: 'spring.security.ui.register.badCode')
redirect uri: defaultTargetUrl
return
}
springSecurityService.reauthenticate user.username
flash.message = message(code: 'spring.security.ui.register.complete')
redirect uri: conf.ui.register.postRegisterUrl ?: defaultTargetUrl
}
def forgotPassword() {
if (!request.post) {
// show the form
return
}
String username = params.username
if (!username) {
flash.error = message(code: 'spring.security.ui.forgotPassword.username.missing')
redirect action: 'forgotPassword'
return
}
String usernameFieldName = SpringSecurityUtils.securityConfig.userLookup.usernamePropertyName
def user = lookupUserClass().findWhere((usernameFieldName): username)
if (!user) {
flash.error = message(code: 'spring.security.ui.forgotPassword.user.notFound')
redirect action: 'forgotPassword'
return
}
def registrationCode = new RegistrationCode(username: user."$usernameFieldName")
registrationCode.save(flush: true)
String url = generateLink('resetPassword', [t: registrationCode.token])
def conf = SpringSecurityUtils.securityConfig
def body = conf.ui.forgotPassword.emailBody
if (body.contains('$')) {
body = evaluate(body, [user: user, url: url])
}
mailService.sendMail {
to user.email
from conf.ui.forgotPassword.emailFrom
subject conf.ui.forgotPassword.emailSubject
html body.toString()
}
[emailSent: true]
}
def resetPassword(ResetPasswordCommand command) {
String token = params.t
def registrationCode = token ? RegistrationCode.findByToken(token) : null
if (!registrationCode) {
flash.error = message(code: 'spring.security.ui.resetPassword.badCode')
redirect uri: SpringSecurityUtils.securityConfig.successHandler.defaultTargetUrl
return
}
if (!request.post) {
return [token: token, command: new ResetPasswordCommand()]
}
command.username = registrationCode.username
command.validate()
if (command.hasErrors()) {
return [token: token, command: command]
}
String salt = saltSource instanceof NullSaltSource ? null : registrationCode.username
RegistrationCode.withTransaction { status ->
String usernameFieldName = SpringSecurityUtils.securityConfig.userLookup.usernamePropertyName
def user = lookupUserClass().findWhere((usernameFieldName): registrationCode.username)
user.password = springSecurityUiService.encodePassword(command.password, salt)
user.save()
registrationCode.delete()
}
springSecurityService.reauthenticate registrationCode.username
flash.message = message(code: 'spring.security.ui.resetPassword.success')
def conf = SpringSecurityUtils.securityConfig
String postResetUrl = conf.ui.register.postResetUrl ?: conf.successHandler.defaultTargetUrl
redirect uri: postResetUrl
}
protected String generateLink(String action, linkParams) {
createLink(base: "$request.scheme://$request.serverName:$request.serverPort$request.contextPath",
controller: 'register', action: action,
params: linkParams)
}
protected String evaluate(s, binding) {
new SimpleTemplateEngine().createTemplate(s).make(binding)
}
static final passwordValidator = { String password, command ->
if (command.username && command.username.equals(password)) {
return 'command.password.error.username'
}
if (!checkPasswordMinLength(password, command) ||
!checkPasswordMaxLength(password, command) ||
!checkPasswordRegex(password, command)) {
return 'command.password.error.strength'
}
}
static boolean checkPasswordMinLength(String password, command) {
def conf = SpringSecurityUtils.securityConfig
int minLength = conf.ui.password.minLength instanceof Number ? conf.ui.password.minLength : 8
password && password.length() >= minLength
}
static boolean checkPasswordMaxLength(String password, command) {
def conf = SpringSecurityUtils.securityConfig
int maxLength = conf.ui.password.maxLength instanceof Number ? conf.ui.password.maxLength : 64
password && password.length() <= maxLength
}
static boolean checkPasswordRegex(String password, command) {
def conf = SpringSecurityUtils.securityConfig
String passValidationRegex = conf.ui.password.validationRegex ?:
'^.*(?=.*\\d)(?=.*[a-zA-Z])(?=.*[!##$%^&]).*$'
password && password.matches(passValidationRegex)
}
static final password2Validator = { value, command ->
if (command.password != command.password2) {
return 'command.password2.error.mismatch'
}
}
}
class RegisterCommand {
String username
String email
String password
String password2
def grailsApplication
static constraints = {
username blank: false, validator: { value, command ->
if (value) {
def User = command.grailsApplication.getDomainClass(
SpringSecurityUtils.securityConfig.userLookup.userDomainClassName).clazz
if (User.findByUsername(value)) {
return 'registerCommand.username.unique'
}
}
}
email blank: false, email: true
password blank: false, validator: RegisterController.passwordValidator
password2 validator: RegisterController.password2Validator
}
}
class ResetPasswordCommand {
String username
String password
String password2
static constraints = {
password blank: false, validator: RegisterController.passwordValidator
password2 validator: RegisterController.password2Validator
}
}
However, I am getting an error at:
class RegisterController extends grails.plugin.springsecurity.ui.RegisterController {` with the error:Cannot override the final method from RegisterController`
and at
package com.testApplication.register
Multiple markers at this line
- The type org.springframework.security.core.context.SecurityContext cannot be resolved. It is indirectly
referenced from required .class files
- The type org.springframework.security.core.GrantedAuthority cannot be resolved. It is indirectly referenced
from required .class files
- The type org.springframework.security.web.savedrequest.SavedRequest cannot be resolved. It is indirectly
referenced from required .class files
I tried to use #Override however, this does not change it. What am I doing wrong?
I appreciate your answer!
The final keyword prevents you from modifying a class if applied to the class, or a method if applied to a method.
From http://en.wikipedia.org/wiki/Final_%28Java%29 :
A final method cannot be overridden or hidden by subclasses. This is used to prevent unexpected behavior from a subclass altering a method that may be crucial to the function or consistency of the class.
If you subclass a class with a final method you need to leave that method alone. If the class is final you can't subclass it at all.
Refresh dependencies solved my issue.
I want to add a date expression validator in my command object, but I'm not sure what's the correct syntax...
class UserController {
…
}
class DateServiceCommand {
String date //valid format is DD-MMM-YYYY, 01-APR-2011
static constraints = {
date(blank:false, ??? )
}
}
You can use a custom validator:
import java.text.*
class DateServiceCommand {
String date
static constraints = {
date blank: false, validator: { v ->
def df = new SimpleDateFormat('dd-MMM-yyyy')
df.lenient = false
// parse will return null if date was unparseable
return df.parse(v, new ParsePosition(0)) ? true : false
}
}
}