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.
Related
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
In the classic HttpClient GZIP decompression is handled out of the box by ContentCompressionExec. How is this done with an HttpAsyncClient? I can't find any AsyncExecChainHandler that implements this functionality.
I ended up implementing the following AsyncResponseConsumer myself in scala.
class SimpleDecompressingResponseConsumer(val entityConsumer: AsyncEntityConsumer[Array[Byte]])
extends AbstractAsyncResponseConsumer[SimpleHttpResponse, Array[Byte]](entityConsumer) {
override def informationResponse(response: HttpResponse, context: HttpContext): Unit = ()
override protected def buildResult(response: HttpResponse, entity: Array[Byte], contentType: ContentType): SimpleHttpResponse = {
val simpleResponse = SimpleHttpResponse.copy(response)
if (entity != null) simpleResponse.setBody(entity, contentType)
simpleResponse
}
}
class SimpleAsyncDecompressingEntityConsumer extends AbstractBinDataConsumer with AsyncEntityConsumer[Array[Byte]] {
#volatile
private var resultCallback: FutureCallback[Array[Byte]] = _
private var encoding: Array[Byte] => Array[Byte] = _
private var content: Array[Byte] = _
private val buffer = new ByteArrayBuffer(1024)
override def streamStart(entityDetails: EntityDetails, resultCallback: FutureCallback[Array[Byte]]): Unit = {
this.resultCallback = resultCallback
this.encoding = entityDetails.getContentEncoding match {
case "gzip" | "x-gzip" =>
bytes => IOUtils.toByteArray(new GZIPInputStream(new ByteArrayInputStream(bytes)))
case "deflate" =>
bytes => IOUtils.toByteArray(new DeflateInputStream(new ByteArrayInputStream(bytes)))
case _ =>
identity
}
}
override def failed(cause: Exception): Unit = {
if (resultCallback != null) resultCallback.failed(cause)
releaseResources()
}
override def getContent: Array[Byte] = content
override def capacityIncrement(): Int = Int.MaxValue
override def data(src: ByteBuffer, endOfStream: Boolean): Unit = {
if (src == null) return
if (src.hasArray) buffer.append(src.array(), src.arrayOffset() + src.position(), src.remaining())
else while (src.hasRemaining) buffer.append(src.get)
}
override def completed(): Unit = {
this.content = encoding(buffer.toByteArray)
if (resultCallback != null) resultCallback.completed(content)
releaseResources()
}
override def releaseResources(): Unit = buffer.clear()
}
I began learn Groovy, and faced the challenge.
I have this code, that stores meta-data to object:
class Meta {
final MetaItem name
final MetaItem description
// ...
// And more fields with type MetaItem
// ...
Meta() {
name = new MetaItem("name")
description = new MetaItem("description")
}
void setName(String name) {
this.name.value = name
}
String getName() {
return this.name.value
}
void setDescription(String description) {
this.description.value = description
}
String getDescription() {
return this.description.value
}
// ...
// And more methods. Two for each field
// ...
}
class MetaItem {
private final def id
def value
MetaItem(String id) {
this.id = id
}
}
// Validating
def meta = new Meta()
assert meta.name == null
assert meta.description == null
meta.with {
name = "Name"
description = "Desc"
}
assert meta.name == "Name"
assert meta.description == "Desc"
print "Success!"
As you can see from the code, it increases quicly in volumes when new fields are added, because for each field you need to add two methods. Can this somehow be optimized? Redirect the assignment operation from object to his member. I've looked on Delegate, but this is not what I need.
P.S. I can't use access by .value because this class is used in Gradle extension and I need to configure it like this:
myExtension {
meta {
name = "Name"
description = "Desc"
// And many others
}
}
P.P.S. Sorry for my bad english, it's not my first language
I tried this solution: Custom fields with FormBuilder in the Microsoft Bot Framework
But failed to get it working....The problem I encountered is that when I assign the base.Form = value, the _prompt in the _field gets a default recognizer, and it won't get overriden in the next line's SetRecognizer call, that only replaces the _field's recognizer.
However the matching process uses the _prompt's recognizer internally ( ? ).
Here is my code:
public class LuisIntentRecognizer<T> : RecognizePrimitive<T>
where T : class
{
public LuisIntentRecognizer(IField<T> field, string luisModelID, string luisSubscriptionKey)
: base(field)
{
_luisModelID = luisModelID;
_luisSubscriptionKey = luisSubscriptionKey;
}
public override DescribeAttribute ValueDescription(object value)
{
return new DescribeAttribute((string)value);
}
public override IEnumerable<string> ValidInputs(object value)
{
yield return (string)value;
}
public override TermMatch Parse(string input)
{
TermMatch result = null;
if (!string.IsNullOrWhiteSpace(input))
{
var luisModel = new LuisModelAttribute(_luisModelID, _luisSubscriptionKey);
var luisService = new LuisService(luisModel);
var luisResult = luisService.QueryAsync(input).Result; // TODO refactor somehow to async
var winner = luisResult.Intents.MaxBy(i => i.Score ?? 0d);
if (winner != null && !string.IsNullOrEmpty(winner.Intent))
{
result = new TermMatch(0, winner.Intent.Length, 0.0, winner.Intent);
}
else
{
result = new TermMatch(0, input.Length, 0.0, input);
}
}
return result;
}
public override string Help(T state, object defaultValue)
{
var prompt = new Prompter<T>(_field.Template(TemplateUsage.StringHelp), _field.Form, null);
var args = HelpArgs(state, defaultValue);
return prompt.Prompt(state, _field.Name, args.ToArray()).Prompt;
}
private string _luisModelID;
private string _luisSubscriptionKey;
}
public class LuisIntentField<T> : FieldReflector<T>
where T : class
{
public LuisIntentField(string name, string luisModelID, string luisSubscriptionKey, bool ignoreAnnotations = false)
: base(name, ignoreAnnotations)
{
_luisModelID = luisModelID;
_luisSubscriptionKey = luisSubscriptionKey;
}
public override IForm<T> Form
{
set
{
base.Form = value;
base.SetRecognizer(new LuisIntentRecognizer<T>(this, _luisModelID, _luisSubscriptionKey));
}
}
private string _luisModelID;
private string _luisSubscriptionKey;
}
Could anyone get it working?
Thanks
It seems to be a bug in the framework indeed: https://github.com/Microsoft/BotBuilder/issues/879
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 {
...
}