How to add csrf token for immediate file upload for Spring Security 3.2? - jsf

I have been trying to add CSRF token for file uploads in my Spring application having spring security 3.2. The Spring Security CSRF documentation suggests we add MultipartFilter before the spring security filter so that temporary file upload becomes possible without spring security altogether (and hence without CSRF checking also). But wouldn't that be less secure?
Although, to have a working software atleast, I applied the above method but its not working. In error log it looks like the multipart filter is being triggered before the spring security filter, but still it IS going in the spring security filter and then to CSRF filter.
I am using <rich:fileUpload> with immediateUpload="true" to upload the file in the form.
May I get some help in applying this? It would be better if we can add the CSRF token itself instead of circumventing the security filter.

MultipartFilter does not stop the spring security filters from being invoked. But by putting it as the first filter in the filter chain, when there is a csrf token available in body as a param, it makes it possible for csrf token filter to extract the csrf token from body and verify it.
Short answer
You still neef to send csrf token but you can send it in body as a hidden param or in the url as a query param.
Note:
I dont have knowledge about the ui component you use but in your previous get request, you should have received a _csrf token as hidden param and you should include it as part of the url or as a hidden param in the multipart request.
If it is not clear, just to make a GET and POST request working without fileupload to understand the csrf flow
Alternative: Skip the csrf only for file upload
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf()
.requireCsrfProtectionMatcher(new CustomRequiresCsrfMatcher())
.and()
......
}
private static final class CustomRequiresCsrfMatcher
implements RequestMatcher {
private final HashSet<String> allowedMethods = new HashSet<>(
Arrays.asList("GET", "HEAD", "TRACE", "OPTIONS"));
#Override
public boolean matches(HttpServletRequest request) {
String upload_url = "your file upload url";//update it
return !this.allowedMethods.contains(request.getMethod()) &&
!request.getRequestURL().toString().contains(upload_url);
}
}

Related

Send additional parameters to social login

Is there anyway to save additional data to the session when doing a social login/signup?
I noticed that if I send returnUrl parameter to the SS OAuth endpoint (i.e. /auth/google?retunUrl=...) then this value gets saved to the session as ReferrerUrl so I am using that to embed data as url parameters. I would prefer to be able to write to the Meta collection when directing to the SS Auth endpoint and then later read it from the session.
I tried to follow the exact process of how this was being saved to the session but I found it quite confusing.
What is the best way to add additional meta data to a social login/signup?
Edit:
I am talking about making a GET request to /auth/google, /auth/facebook etc...
I have additional data I want to track with the signup the user has entered in the browser.
If I add code to OnAuthenticated then this doesn't solve problem as the data has gone out of scope of the browser. It has to be passed in the GET request to the auth endpoint or have some reference to match up.
Edit:
public class CustomUserSession : AuthUserSession
{
public override void OnCreated(IRequest httpReq)
{
this.Meta.Add("foo", "bar");
httpReq.SaveSession(this);
}
}
You can handle a callback with the OnAuthenticated() Session or Auth Events.

yii2 CSRF not validating host

One more issue I am facing my site is created in yii2 and CSRF is enabled but when I copy full form including csrf token and create new html file outside server and submit form from outside of server it accepting my form.
What is the expected result?
it should give permission issue
What do you get instead?
it successfully accepting form not sure either I am missing any configuration or what
Yii version 2.0.6
PHP version 5.5.38
Operating system CentOS release 6.9 (Final)
CSRF protection is based on the fact, that third party website should not know CSRF token of your user. If you expose CSRF token, then the whole protection will not work. This is by design.
If you want to block requests from untrusted domains, you should probably use CORS.
That's happening because, as you said, you are using CRSF. If you want to accept data from another domain, you'll need to disable CRSF at least for that particular request. Either this way:
class MyController extends Controller
{
public $enableCsrfValidation = false;
or this way:
class MyController extends Controller
{
public function beforeAction($action)
{
if (in_array($action->id, ['incoming'])) {
$this->enableCsrfValidation = false;
}
return parent::beforeAction($action);
}
From the cookbook: https://yii2-cookbook.readthedocs.io/csrf/
And also, from the official docs: https://www.yiiframework.com/doc/api/2.0/yii-web-controller#$enableCsrfValidation-detail

ASP.NET MVC5 OWIN rejects long URLs

I am creating an ASP.NET MVC5 action method that implements a password reset endpoint and accepts a click-through from an email message containing a token. My implementation uses OWIN middleware and closely resembles the ASP.NET Identity 2.1 samples application.
As per the samples application, the token is generated by UserManager and embedded into a URL that is sent to the user by email:
var token = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
var encoded = HttpServerUtility.UrlTokenEncode(Encoding.UTF8.GetBytes(token));
var uri = new Uri(Url.Link("ResetPasswordRoute", new { id = user.Id, token = encoded }));
The link in the email message targets an MVC endpoint that accepts the token parameter as one of its route segments:
[Route("reset-password/{id}/{token}"]
public async Task<ActionResult> PasswordResetAsync(int id, string token)
{
token = Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(token));
// Implementation here
}
However, requests to this endpoint (using a URL generated in the above manner) fail with Bad Request - Invalid URL.
It appears that this failure occurs because the URL is too long. Specifically, if I truncate the token segment, it connects correctly to the MVC endpoint (although, of course, the token parameter is no longer valid). Specifically, the following truncated URL works ...
http://localhost:53717/account/reset-password/5/QVFBQUFOQ01uZDhCRmRFUmpIb0F3RS9DbCtzQkFBQUFzcko5MEJnYWlrR1RydnVoY2ZwNEpnQUFBQUFDQUFBQUFBQVFaZ0FBQUFFQUFDQUFBQUNVeGZZMzd4OTQ3cE03WWxCakIwRTl4NkVSem1Za2ZUc1JxR2pwYnJSbmJ3QUFBQUFPZ0FBQUFBSUFBQ0FBQUFEcEpnVXFXS0dyM2ZPL2dQcWR1K2x6SkgxN25UVjdMYlE2UCtVRG4rcXBjU0FBQUFE
... but it will fail if one additional character is added ...
http://localhost:53717/account/reset-password/5/QVFBQUFOQ01uZDhCRmRFUmpIb0F3RS9DbCtzQkFBQUFzcko5MEJnYWlrR1RydnVoY2ZwNEpnQUFBQUFDQUFBQUFBQVFaZ0FBQUFFQUFDQUFBQUNVeGZZMzd4OTQ3cE03WWxCakIwRTl4NkVSem1Za2ZUc1JxR2pwYnJSbmJ3QUFBQUFPZ0FBQUFBSUFBQ0FBQUFEcEpnVXFXS0dyM2ZPL2dQcWR1K2x6SkgxN25UVjdMYlE2UCtVRG4rcXBjU0FBQUFEf
I believe that the default IIS configuration setting for maxUrlLength should be compatible with what I am trying to do, but I have also tried explicitly setting it to a larger value, which did not solve the problem.
However, using Fiddler to examine the server response, I can see that the working URL generates a server response with the following header ...
Server: Microsoft-IIS/8.0
... whereas the longer URL is rejected with a response containing the following header ...
Server: Microsoft-HTTPAPI/2.0
This seems to imply that the URL is not being being rejected by IIS, but by a middleware component.
So, I am wondering what that component might be and how I might work around its effect.
Any suggestions please?
Many thanks,
Tim
Note: Although my implementation above Base64 encodes the token before using it in the URL, I have also experimented with the simpler approach used in the sample code, which relies on the URL encoding provided by UrlHelper.RouteUrl. Both techniques suffer from the same issue.
You should not be passing such long values in the application path of the URL as they are limited in length to something like 255 characters.
A slightly better alternative is to use a query string parameter instead:
http://localhost:53717/account/reset-password/5?token=QVFBQUFOQ01uZDhCRmRFUmpIb0F3RS9DbCtzQkFBQUFzcko5MEJnYWlrR1RydnVoY2ZwNEpnQUFBQUFDQUFBQUFBQVFaZ0FBQUFFQUFDQUFBQUNVeGZZMzd4OTQ3cE03WWxCakIwRTl4NkVSem1Za2ZUc1JxR2pwYnJSbmJ3QUFBQUFPZ0FBQUFBSUFBQ0FBQUFEcEpnVXFXS0dyM2ZPL2dQcWR1K2x6SkgxN25UVjdMYlE2UCtVRG4rcXBjU0FBQUFEf
That should be safe for at least 2000 characters (full URL) depending on the browser and IIS settings.
A more secure and scalable approach is to pass a token inside an HTTP header.

What should the return object of ServiceStack Authorize method be?

I am writing my own authorize provider for SAML2 authorization. To help me, I got a third party library to handle most of the SAML2 specification.
However this library is written for the ASP.NET HttpHandler interface where there is no return values for the ProcessRequest method.
With this library the method itself will not return anything, but takes care of most of my work of compressing the authentication request XML, creating the signature for the XML and telling the browser to redirect to SAML2 login page, with the correct attributes for the call. So it does a lot of work for me.
Some pseudo code:
public object Authenticate(IServiceBase authService, IAuthSession session, Authenticate request)
{
...
AuthnRequest authnRequestXML = saml2Util.CreateAuthnRequestXML();
HttpResponseBase httpResponse = authService.Request.Response.OriginalResponse as HttpResponseBase;
// This takes care of signing, compression of the authnRequestXML and the redirect action
SAML2Library.SendAuthnRequestByHTTPRedirect(httpResponse, DestinationURL, authnRequestXML, certificatePrivateKey);
return ?;
}
Return null didn't work.
What should I set as the return value of the Authenticate method in this case?
To return a redirect response you can return a HttpResult e.g:
return HttpResult.Redirect(redirectUrl);

JSF PhaseListener viewId always one behind

Im trying to prevent users to access special pages with a phaselistener. for that reason im trying to figure out on which page they try to access.
but my problem is, i only get the page they where before. not the actual page.
public void afterPhase(PhaseEvent event)
{
FacesContext fc = event.getFacesContext();
System.out.println("test1" + fc.getViewRoot().getViewId());
}
and same here
public void afterPhase(PhaseEvent event)
{
FacesContext fc = event.getFacesContext();
HttpServletRequest request = (HttpServletRequest) fc.getExternalContext().getRequest();
String uri = request.getRequestURI();
System.out.println("uri: " + uri);
}
why is that, and how do i get the pagename the user is trying to access? Not that one that they required one step before, or better the page they are coming from.
It is one step behind because that is the way sequence of HTTP POST request behaves. When you are navigating in JSF application via command buttons each request goes as a post request.
Since you are protecting some resources make sure they are accessed via HTTP GET than you will get exact view id, this can be achieved as
User directly hits the url from address bar of browser.
After a post of jsf app redirect it to the resource instead of simple JSF navigation. POST-REDIRECT-GET pattern falls into this have a look here.
If you are showing some messages after each POST, you might need Flash map for that, which is new feature in JSF2, if you are on JSF1.x hard luck, you can implement flash if you want to.
To conclude catch the view ids on HTTP GET request.
Hope this helps...

Resources