Grails Ajax Login - ajax

I want to take use of the ajax login feature of the spring security plugin.
I am completely stuck getting a JSON success response from the loginController into my GWT client.
As I understood from the documentation I need to post my params to the url /j_spring_security_check and spring security is redirecting me to the right action.
If I look into my LoginController I see nothing of the actual login logic and its a bit magic for me where all the login/db stuff is done. Further spring security always redirects to action auth instead of using AjaxAuth even if I add the header "X-Requested-With" to post. If I do my post to the url /login/ajaxAuth I am getting a 401 which is OK because its written down in the controller(even if i dont know why we need to return a 401 here). Maybe I am doing something completely wrong :-)
My basic questions are:
Where can I find the login logic?
What parameter do I have to provide?
Which URL do I have to use?
What do I have to do if I dont want to use the username but instead and email field?
Thanks for all your help!

Looks like you're correctly implemented it, maybe there some small bug, like a typo.
Btw:
It's implemented at filter, that process your request before actual controllers. At your case it will be UsernamePasswordAuthenticationFilter (or RequestHolderAuthenticationFilter). Controller is used there only to render an additional data. As for ajax auth, it uses /login/ajaxSuccess, that renders a JSON response
By default it uses j_username & j_password. And you can use ajax=true parameter, instead of X-Request-With header
/j_spring_security_check by default
You can implement your own GrailsUserDetailsService (or extend GormUserDetailsService), and setup it as a spring bean, with name userDetailsService, at resources.xml
You can also turn on logging for Spring Security by:
log4j {
debug 'org.codehaus.groovy.grails.plugins.springsecurity',
'org.springframework.security'
}
maybe it will be helpful

I am using Grails 2.1.1 and ran into this same issue. Tried all the above things but still couldnt get my AJAX login to call the ajaxSuccess method.
However when it failed it was calling authFail?ajax=true.
After digging in more, here is what I did:
Added grails.plugins.springsecurity.successHandler.targetUrlParameter = 'ajaxUrl' in my Config.groovy
Added <input type="hidden" name="ajaxUrl" value="/login/ajaxSuccess" /> in my AJAX login form
Not sure why it fixed, but it seemed to work for me.
Just posting this solution for users who get stuck and come to this ticket for solution.

Related

What would be the default loginProcessingUrl if loginPage has a parameter or anchor?

I had on my security configuration the following:
.formLogin().loginPage("/?showMessage").defaultSuccessUrl("/perfil");
Because on my main page I wanted to know if I've been redirected there because of trying to access an unauthorized page.
I know the loginProcessingUrl is by default the loginPage but being a POST, but when I try a POST into / or even /?showMessage I get
Request method 'POST' is not supported
I kind of workarounded this by just adding .loginProcessingUrl("/") to the configuration, but this makes me wonder, what would be in this case the default one?

What are "actions" in Vaadin 14?

In Vaadin 14, while looking at the Login component, specifically the source code for AbstractLogin.java, I noticed:
An "action" can be saved on a login widget via getElement.setProperty.
The Javadoc for AbstractLogin::setAction says: “Once action is defined a {#link AbstractLogin.LoginEvent} is not fired anymore.”
I understand making an object of mine a listener for LoginEvent by registering with the login widget via AbstractLogin::addLoginListener.
But this “action” seems to be an alternative way to work instead of event listeners.
Can someone tell me more about actions and how they work in Vaadin Flow?
I searched the Vaadin Docs for the word action but found nothing there.
The HTML API of the LoginForm specifies the following
action: string | null | undefined= null notify
If set, a synchronous POST call will be fired to the path defined. The
login event is also dispatched, so event.preventDefault() can be
called to prevent the POST call.
I understand that, with this option you can configure the login form to post the data login processing or e.g. to external authentication service. Useful use case is to set it "login" when using Vaadin with Spring security. This case is shown in Bakery App Starter.

Grails Spring Security only responds with ajax/JSON on login fail

I'm using spring security in a grails app and when a login fails it always redirects to "login/authfail?ajax=true" and a json is rendered.
I even tried to redefine the 'ajaxAuthFailUrl' to be the same as 'defaultFailureUrl', but even though it redirects to '/login/authfail?login_error=1' I still getting the same json.
I dig the spring plugin to see why it 'thinks' it's an ajax request. Then on 'SpringSecurityService.java' I put some debug messages on 'isAjax' method. The result was, first of all, it calls 'isAjax' 2 times in a row. And the request is considered an ajax for different reasons:
there is a header 'ajaxHeader'
there is an ajax parameter on the request
and finally when it checks the SavedRequest's headers, it also finds it to be an ajax call.
I confess I'm lost, I don't have a clue about how to try to fix it...
I'm using:
Grails 2.3.8
spring-security-core:2.0-RC4
runtime ':spring-security-acl:2.0-RC1'
and I have a custom authentication handler that is set on BootStrap:
authenticationProcessingFilter.authenticationSuccessHandler = new MyUrlAuthenticationSuccessHandler()

Template-less Django + AJAX: Does Django's CSRF token get updated during the course of a browsing session?

My current setup is AngularJS + Django 1.5 and I have completely thrown away the use of Django's template engine (ie. the backend is pretty much an API server).
Since I am not using the csrf_token template tag, Django, in turn, does not set and send the csrftoken cookie in response. As instructed by the official docs, the ensure_csrf_cookie() decorator should be used to force the decorated view to send the csrftoken cookie.
I have applied the ensure_csrf_cookie() decorator to the view, which serves the first GET request that my web client calls at bootstrapping. With that, my web client gets a hold of the CSRF token and henceforth is allowed to call unsafe methods (ex. POST) to the server.
The above setup works fine only if the CSRF token remains the same until the browsing session ends.
Question: Does Django's CSRF token get updated during the course of a browsing session? If 'yes', does that mean I would need to apply the ensure_csrf_cookie() decorator to all the views I have?
1) Does Django's CSRF token get updated during the course of a browsing session?
Looks like the CSRF token is unique per session, but it is based in my observations, I have no "official" source. With Angular.js I use the following code without problems:
angular.module('app', ...)
.config(function($httpProvider) {
var cookies = document.cookie.split(';');
var csrftoken = _.find(cookies, function(v) {
return v.trim().indexOf('csrftoken=') == 0;
});
if(csrftoken) {
$httpProvider.defaults.headers.common['X-CSRFToken'] = csrftoken.split('=')[1];
}
})
Since I serve the HTML from Django, by the time Angular bootstraps the cookie is already there.
2) If 'yes', does that mean I would need to apply the ensure_csrf_cookie() decorator to all the views I have?
You can try CORS instead if CSRF. Otto Yiu maintains the django-cors-headers package, which is known to work correctly with REST framework APIs.
Some (untested) ideas to apply ensure_csrf_cookie():
monkey-patch APIView
create a CSRFCookie mixin and add it to your views
apply ensure_csrf_cookie() to your base classes
Giving support to the #Paulo Scardine ideas of applying the ensure_csrf_cookie() (which I consider valid, and useful), I would like to add a new one possible solution to it, if you definitely have to ensure_csrf_cookie() in all your views. You could write a custom middleware, and implement the logic that is there inside the ensure_csrf_cookie. Something like this:
On your app.middleware.py:
from django.middleware.csrf import get_token
class EnsureCsrfCookie(object):
def process_request(self, request):
# Forces process_response to send the cookie
get_token(request)
and of courses on your settings file add the middleware to the MIDDLEWARE_CLASSES:
MIDDLEWARE_CLASSES = (
.,
.,
.,
'app.middleware.EnsureCsrfCookie',
.,
.,
.,
)
It is just one idea more to face this problem. I hope it can be useful for somebody in the future.

After Wicket session timeout - pageParameters are null

I'm using wicket 6.
My application is based on WebPages created with pageParameters in the constructor. I'm using also a pageParameter country that is a path-parameter defined with:
mountPage("/${country}/pagepath", MyPage.class);
I have many statefull forms in every page.
I'm now trying to handle the case when the session expires (to reproduce this scenario I delete or modify the jsessionid cookie).
After that I click a submit button in a page and I'd expect wicket to understand that the session has expired.
But the behaviour that I have is this:
the current page is reloaded but the pageparameters are 'null'
the url is rewritten using the package notation like:
localhost:8080/wicket/bookmarkable/com.test.pages.MyPage
So it looks like the url mapping is somehow lost.
I need to reload the same page with pageParameters information or show an info page that says something like click here to reload.
I've already tried to use:
getApplicationSettings().setPageExpiredErrorPage(HomePage.class);
but that didn't help.
Any help is appreciated. Thanks.
Looks like there is a bug in Wicket 6 which causes this issue: https://issues.apache.org/jira/browse/WICKET-5068
It is fixed in Wicket 7. For Wicket 6, there is a workaround: disable WICKET-4594 fix.
First add the following mapper:
public class BookmarkableMapperThatSavesPageParametersForListener extends BookmarkableMapper {
#Override
protected PageParameters getPageParametersForListener(PageInfo pageInfo, PageParameters pageParameters) {
return pageParameters;
}
}
Then use it to replace a built-in BookmarkableMapper in your Application#init() (this has to be added before any manipulations with the root mapper):
mount(new BookmarkableMapperThatSavesPageParametersForListener());
This approach works in our application and it does not seem to break anything.
More info: Wicket 6: empty PageParameters when recreating a page after expiration
You could ask your question in the wicket mailing list. What you are observing might be a bug. Please check PageParameters missing from re-created Page
Conceptually, it should be possible to submit the form normally even if you need an authenticated user session.
If the session is expired then you may be able to re-create a user session with a remember-me cookie. Wicket should re-construct the page with parameters, apply the form values and process the submit. In case where the page is stateful, there could be some complications that are possibly resolvable. If you find that your use case is not supported with stateful pages then you could file an issue and meanwhile use StatelessForm.

Resources