Grails withForm, reset token on error? - forms

Currently using grails 2.2.2
I've been trying to implement tokens into my application and have come up with this issue. We try to avoid re-rendering pages because it can be very slow so we return JSON instead. The following is a basic controller call that we use but I'm not sure what I should be doing to reset/get a new token.
public saveThing(ThingCommand cmd) {
Map model = [:]
withForm {
try {
thingService.saveThing(cmd)
model.success = true
} catch (Exception e) {
model.error = true //any validation errors or anything else
// RESET TOKEN HERE/GET NEW TOKEN?
}
}.invalidToken {
model.invalidToken = true
}
render model as JSON
}
From my understanding the token is thrown away once the withForm closure is executed. This causes an issue since I don't actually re-render the form which seems to be the normal way of generating a new token. How could I do this manually or is there an easier way to do this (plugin?)
Thanks!

Form tokens through withForm are not designed to be used with AJAX requests. They are designed to be used with HTML forms and POST requests which re-render the form and generate a new token for the form.
In order to make them work with JSON/AJAX requests you will need to implement your own token generation when you process the request and reject it. A good starting place would be to look at the old tests which test withForm. This should give you an idea on how tokens are created and stored.

Related

When using shiro to realize stateless application, do i need to login every request?

I use shiro and jwt and try to realize a stateless web application.
When i extend AuthorizingRealm, do i need to executeLogin every request?
Here is my executeLogin method:
public static boolean executeLogin(ServletRequest request) {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String authorization = httpServletRequest.getHeader("Authorization");
if (authorization == null || "".equals(authorization.trim())) {
throw RequestException.fail("未含授权标示,禁止访问");
}
JwtToken token = new JwtToken(authorization, null, null);
// 提交给realm进行登入,如果错误他会抛出异常并被捕获
Subject subject = SecurityUtils.getSubject();
try {
subject.login(token);
} catch (DisabledAccountException e) {
if (e.getMessage().equals("verifyFail")) {
throw new RequestException(ResponseCode.NOT_SING_IN.code, "身份已过期,请重新登录", e);
}
throw new RequestException(ResponseCode.SIGN_IN_INPUT_FAIL.code, e.getMessage(), e);
} catch (Exception e) {
e.printStackTrace();
throw new RequestException(ResponseCode.SIGN_IN_FAIL, e);
}
// 如果没有抛出异常则代表登入成功,返回true
return true;
}
By Stateless means that each request does not depend from the previous, however this does not mean that Shiro does not use sessions.
When the user does a successful login Shiro attaches to the HTTPResponse some cookies. When the client sends the cookies to each further request, Shiro automatically extracts the Subject (associates the cookies with the user) so, in your code, you can immediately call SecurityUtils.getSubject().
A realm is the wrong approch here as it usually have by definition a 1-to-1 correlation with a data source. What you actually want to do is to controll access to your servers resources, verifying a JWT from a client. This can be done by a AccessControlFilter, reading the authorization header and verifing its claims in the filters isAccessAllowed method. The methods return value defines wheather access is allowed or not.
You don't need to login a subject at all since the AccessControlFilter decides wheather access is granted or denied, either forwarding the user to the requested resource or redirecting a 401 - Unauthorized response.
Yes, you should log in for each request. This will attach the subject to the current thread and allow you to use features: like use annotations for authz.
As you are using stateless call, you have to login each time and generate new subject and also load authorization details with appropriate realm.
The another option you could try is, put subject in cache (ehCache) once successful login and then on every request you can get subject from Cache and use for authorization. This will avoid login and authorization object population on every request. But you have to make sure to remove object from cache on logout event.
Similar thing has been already done by one user at:
https://github.com/jikechenhao/springmvc-shiro-react-redux-restful-example

Authentication That Doesn't Require Javascript?

I have a Web API app, initialized thusly:
app.UseCookieAuthentication();
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
app.UseOAuthBearerTokens(OAuthOptions);
app.UseGoogleAuthentication();
For calls to most controllers, it works great. However, it also requires a bit of javascript before client-side service calls are made:
function getSecurityHeaders() {
var accessToken = sessionStorage["accessToken"] || localStorage["accessToken"];
if (accessToken) {
return { "Authorization": "Bearer " + accessToken };
}
return {};
}
The problem is that we have a certain type of controller (one that accesses files) where no javascript can be run during the call. For example, the call might be to:
http://mysite/mycontroller/file/filename.jpg
...where the value is assigned as the src attribute of an img tag. The call works, but Thread.CurrentPrincipal.Identity is unauthenticated with a null name, so there's currently not a way to enforce security.
I'm new to Web API, so it may be a dumb question, but what's the way around this? What switches do I need to flip to not require javascript to add security headers? I was considering trying to find a way to force an authorization header in an IAuthorizationFilter or something, but I'm not even sure that would work.
So I figured out the solution to my problem.
First, I needed to configure the app to use an authentication type of external cookies thusly:
//the line below is the one I needed to change
app.UseCookieAuthentication(AuthenticationType = DefaultAuthenticationTypes.ExternalCookie);
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
app.UseOAuthBearerTokens(OAuthOptions);
app.UseGoogleAuthentication();
Second, it turned out there was a line of code in my WebApiConfig file that was disabling reading the external cookie:
//this line needed to be removed
//config.SuppressDefaultHostAuthentication();
After that, I could see the external cookie from Google, which passed along an email address I could identify the user with.

CSRFGuard - request token does not match session token

I am trying to incorporate the CSRFGuard library in order to rectify some CSRF vulnerabilties in an application. However after configuring as specified here I am now getting the below messages in the log, when I navigate the application:
WARNING: potential cross-site request forgery (CSRF) attack thwarted (user:<anonymous>, ip:169.xx.x.xxx, uri:/myapp/MyAction, error:request token does not match session token)
Through including the:
<script src="/sui/JavaScriptServlet"></script>
On my main.jsp page the links have all been built incorporating the CSRFGuard token, e.g.
......./myapp/MyAction?CSRFTOKEN=BNY8-3H84-6SRR-RJXM-KMCH-KLLD-1W45-M18N
So I am unable to understand what I'm doing wrong that could cause the links to pass a token other than the expected value.
Please let me know if any additional information would make it easier to understand.
In case anyone stumbles across a similar issue:
Turned out that accessing the app using IE wasn't passing a token to an AJAX call, this would in turn result in the tokens being refreshed but the links in the already rendered page remained, causing the mismatch when clicked.
Found out the issue by building CSRFGuard myself from source and adding extra logging.
The primefaces commandlink and commandbutton seem to cause the csrfguard javascript to malfunction, if you have use these two component with ajax set to true (which is the default), it can prevent the token being injected after the ajax call
One of the possible fixes is to change the following 2 lines in Owasp.CsrfGuard.js file.
Change
function injectTokenForm(form, tokenName, tokenValue, pageTokens) {
var action = form.attribute("action");
To
function injectTokenForm(form, tokenName, tokenValue, pageTokens) {
var action = form.attributes["action"].value;
AND
Change
function injectTokenAttribute(element, attr, tokenName, tokenValue, pageTokens) {
location = element.getAttribute(attr);
To
function injectTokenAttribute(element, attr, tokenName, tokenValue, pageTokens) {
var location = null;
if (attr == "action") {
location = element.attributes[attr].value;
} else {
location = element.getAttribute(attr);
}

MVC jquery ajax form server side validations

We have a number of forms on our site that are shown with jquery .dialog and we submit them using an ajax post request.
I've done a fair bit of research and from what I can tell there isn't any definite patterns on how to return validation errors from the server side as a result of an ajax request.
Pretty much the only pattern I could find was to post the form and then do validation server side and in either case return a json object that encapsulated a result and if the result was incorrect the form html
ie.
{result: true}
{success: false, html = "<form>....</form>"}
So in the case the result was false you would need to rewire up any events attached to items on the form as you would be replacing the old form with the new form that has the validation errors.
This seems like an ok approach but you also end up potentially returning a lot more data to the client that you need to when they only really need to validation messages and you are also forced to rewire the form up which is a bit annoying.
I did find one other mention of somehow getting the validation errors and returning them in a json object from the action and somehow telling the client to display them against the correct fields.
Is there any frameworks out there that make this easier or should I write my own or just stick to returning the entire partial for the form and rewiring it when validation is incorrect?
I don't know of any frameworks that handle this particular case–and I don't know that there's a clear best practice–but it's easy enough to serialize validation errors and return them as a JSON object. You could try this extension method on ModelStateDictionary:
public static IEnumerable<ValidationResult> GetValidationResults(this ModelStateDictionary dictionary)
{
foreach (var key in dictionary.Keys)
foreach (var error in dictionary[key].Errors)
if (error != null)
yield return new ValidationResult(error.ErrorMessage, new string[] { key });
}
And in the controller:
if (!ModelState.IsValid)
{
return new JsonResult(ModelState.GetValidationResults());
}
But you're right, you would then have to loop through the object and append the errors to the correct fields. If you have ClientValidationEnabled and UnobtrusiveJavaScriptEnabled set to true, the loop would look something like this:
$.each(errors, function(i, item) {
$('span[data-valmsg-for=' + item.MemberNames[0] + ']').html(item.ErrorMessage);
})
If not, it wouldn't be that difficult to match up the error messages to their respective fields as the object contains the field name. This would definitely save you some data across the wire, but it moves a larger share of the validation responsibility into Javascript. Like I said, I don't know that there's a clear best practice, but I have used this method in the past with success.

Log user in manually with Forms Authentication

I'm trying to implement token-based authorization for an Asp.Net MVC2 app, and I think my approach is wrong. First off: by token-based authorization I mean that when an unauthenticated user goes to http://myapp.com/some/action?tok=[special single-use token here] they are logged in.
All of the controllers in my app extend a common ApplicationController, so my approach was to override OnAuthorize on that controller as follows:
class ApplicationController
{
protected override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.QueryString["tok"] != null)
{
var token = HttpUtility.UrlDecode(filterContext.HttpContext.Request.QueryString["tok"]);
if ((var user = getUserByToken(token)) != null)
{
FormsAuthentication.SetAuthCookie(user.Email, false);
}
else{ /* highly-proprietary handling of invalid token */ }
}
base.OnAuthorization(filterContext);
}
}
I am absolutely certain that SetAuthCookie is being called when it should and not being called when it shouldn't.
The problem is, that doesn't really log the user in. It sets a cookie, which means I'd have to redirect (User.Identity.IsAuthenticated remains false after calling SetAuthCookie.) But the whole idea about this is to continue the request as normal and avoid a pointless redirect. Is there some way to accomplish this goal? It doesn't really seem like a whole lot to ask...
After you call SetAuthCookie, nothing changes with the User.Identity. On the next request, the data will be what you are expecting. The best thing to do here is to issue a redirect after SetAuthCookie has been called.