I try create simple OAuthHandler.
After my request (using the implicit flow), server send request to my page, with an authorization code. But in query string from server, all parameters starts with hash (#) instead?
In method HandleRemoteAuthenticateAsync, I'm trying to parse query string, but none of the properties contain authorization code or anything like that.
How can I handle hash in query string?
As Joppe and David mentioned in the comments, anything after the hash (#) is part of the fragment, and is not sent to the server by the browser. That's why your server code can't see it.
The implicit flow is for JavaScript clients, not web servers. You want the authorization code flow instead. The redirect will look like:
REDIRECT_URI?code=7a6fa...
Since the code is transmitted in the query string, instead of the fragment, your server-side code will be able to see it.
Related
How do I clear/remove query string parameters, which my MVC action, doesn't require/support?
For instance, my action requires, say an id and a bool flag, so the url would be something like: http://localhost:someport/controller/action/?id=1&remove=true
But, if a user types in something like, http://localhost:someport/controller/action/?id=1&remove=true&some-junk-param=0
Then, I want the some-junk-param to be removed and not shown in the address bar, when the request is processed.
Any thoughts?
If you need to get rid of unwanted query string parameters, you have two general options:
Do it on server-side. You can achive this only with redirection, that means when browser asks URL with bad query string, server redirects browser to URL with good query string.
Caveats:
In this case we have redundant query just for cleaning query string.
User will have trash in browser history.
Do it on client-side. ASP.NET MVC Model binder will get only expected parameters from query string, so it's nothing bad with having other values in query string. You can check your URL on client-side with javascript and rewrite it with or without changing history using History API (IE10+).
Caveats:
In this case you will have to support consistency about allowed parameters between JS and C# code
Of course every way is suitable for it's own cases, but looking at caveats the second way is better, because it affects developer expirience whereas first way affects user expirience.
When sending a request via Zuul to a client, Zuul seems to change the query String. More specifically, if the client should receive an url-encoded query String, Zuul decodes the query String once. Here is a concrete example:
If "http://localhost:8080/demo/demo?a=http%3A%2F%2Fsomething/" is sent to the client, the client receives as a query String "a=http://something/".
Looking into Zuul`s code, the function "buildZuulRequestQueryParams" uses "HTTPRequestUtils.getInstance().getQueryParams();" which decodes the query String.
Is this a desired feature or a bug?
Zuul actually offers a flag to disable this behavior.
8.9 Query String Encoding
When processing the incoming request, query params are decoded so that they can be available for possible modifications in Zuul filters. They are then re-encoded the backend request is rebuilt in the route filters. The result can be different than the original input if (for example) it was encoded with Javascript’s encodeURIComponent() method. While this causes no issues in most cases, some web servers can be picky with the encoding of complex query string.
To force the original encoding of the query string, it is possible to pass a special flag to ZuulProperties so that the query string is taken as is with the HttpServletRequest::getQueryString method, as shown in the following example:
application.yml.
zuul:
forceOriginalQueryStringEncoding: true
[Note] This special flag works only with SimpleHostRoutingFilter.
Also, you loose the ability to easily override query parameters with
RequestContext.getCurrentContext().setRequestQueryParams(someOverriddenParameters),
because the query string is now fetched directly on the original
HttpServletRequest.
8. Router and Filter: Zuul
I was facing the same issue yesterday. I think it's related to this pull request. A faster way to solve this issue (without wait for PR get merged) is rewrite the classes in your own project using the same package and class name to override the framework class.
I ran into the same issue recently. Submitted a PR to Netflix/Zuul. Basically adding the same ability that's currently available on spring cloud gateway to Netflix. Hoping it'll get addressed soon.
If accepted, you could pretty much add a config to keep the original uri encoding
zuul.keepOriginalQueryStringEncoding=true
I've tried send request like this.
localhost:3000/ws/job_histories/index?agent_id=#1000
But on Controller I've received agent_id='' or like this one
localhost:3000/ws/job_histories/index?agent_id=10#00
I've received agent_id='10'. I think problem has because Rails understand it like comment.
How can I correctly received my data. Rails doesn't give me any exception.
The hash symbol is the fragment identifier and your browser will not send it to the webserver ever.
If you want to send it you need to URL encode it (%23), you can achieve that with CGI.escape('#').
This is completely normal, hashes belong to the client, they are not sent to the server.
And # is what represent a hash so remove it or encode it
Hash fragments aren't sent to servers from the browser, so this would never work, for any server-side framework, not just Rails.
From Wikipedia, Fragment identifiers:
Clients are not supposed to send URI-fragments to servers when they retrieve a document...
From URL Fragments and Redirects:
The Fragment component of the URL is the end of the URL from the hash symbol (#) onward. URL Fragments are never sent to the server in the HTTP request...
Is there away to get the current fragment from a route that was issued via action link. This is how I am getting the action from the route.
string currentAction = requestContext.RouteData.Values["action"] as string ?? "index";
Can I do something similar to this?
string currentFragment = requestContext.RouteData.Values["Fragment"] as string ?? "";
No, you can't do anything like this. The fragment (everything that follows the # sign in an url) is never sent to the server by the browser, so the sole fact of talking about getting the url fragment server side simply doesn't make sense.
So if you have the following url: http://example.com/foo/bar?key1=value1#abc the server will never be able to fetch abc simply because the client will never send it.
As it has already been pointed out that is not possible. Document fragments (the string after the hash as you call it) are intended for the browsers only to correctly position the viewport. They have no meaning for the server and therefore are not transmitted there.
There is however a workaround you can use. Repeat the fragment as part of your url to make it accessible for the server.
Look at the permalink to the answers in this question. For instance, the link to my answer looks like this:
http://stackoverflow.com/questions
/6285833/get-current-fragment-in-route-asp-net-mvc/6286097#6286097
See how the value 6286097 is duplicated as the last route parameter. It's intentional. You can use this technique as well.
P.S. The fragment must point to an identifier in the document (id of some HTML element). At least in XHTML only identifiers work as fragments. Valid ids may not begin with a digit therefore instead of #6286097 use something like #answer-6286097.
P.S.#2. Do not use any JavaScript trickery to get around this limitation. Basic site functionality and design must work without JavaScript - don't listen to anyone who tells you otherwise. Fragments obviously belong to the basic tool box. Use JavaScript only for advanced interactivity.
I have a workaround for you, but first of all lets get more into the problem.
The strings after the hash symbol which are called Fragment values are not query parameters but they are strings to be read by the client-side (living in the browser) and the server cannot read them because they are not sent to the server by the browser.
Some authentication providers like Google and Azure send the access token as Fragment value for security reasons so that they are not transferred over the internet after they get sent as direct response from the authentication provider.
The only way you can come around that is to use javascript to convert the fragment values to query parameters by replacing the '#' with '?' and redirecting to the endpoint in your server controller.
I suppose the easiest way is to handle all that from server, meaning you get get the request in server, send a javascript code to the browser on the fly, that replaces the '#' into '?' and redirects to your second endpoint which reads the token as strong parameter.
Here how you can do it in ASP.NET Core 3.1:
[AllowAnonymous]
[HttpGet("authredirect")]
[Produces("text/html")]
public virtual ContentResult ConvertUrlFragmentToQueryParamThenRedirect()
{
return Content("<html><script>window.location.href=window.location.href.replace('#', '?').replace('authredirect', 'authparams')</script></html>", "text/html");
}
[AllowAnonymous]
[HttpGet("authparams")]
public virtual void GetAccessToken([FromQuery] string access_token)
{
// now you have your access token server side here
}
Please remember to set your redirectUrl to the correct one, in this case 'YOUR REDIRECT URL/authredirect'.
Due to my current implementation of using QR Codes, I cannot change the request url. I need to be able to parse an address to get the string after the hash sign, i.e.:
http://domain.com/#getthisstring
Is there a way to do this?
You cannot do this on the server side. URL fragment identifiers are not sent to the server.
You can however trap this value on the client side with JavaScript and send an Ajax request to the server passing the aforementioned value.
An impl in jQuery perchance?
$(function() {
$.post('someRailsEndpoint', {hash: document.location.hash});
});
On the Rails end, you'd use params[:hash] to access this value.