Getting latlong from address using google geocoding - c#

I am using google geocoding api to get latitude and longitude from address.But it gives an exception
The remote server returned an error: (403) Forbidden.
The code is as below:
WebClient client = new WebClient();
Uri uri = GetGeocodeUri(address);
string[] geocodeInfo = client.DownloadString(uri).Split(',');
return new Coordinate(Convert.ToDecimal(geocodeInfo[2]),convert.ToDecimal(geocodeInfo[3]));
The exception comes from line 3 at the time of "downloadstring".
Please help me out.

Was this working before and now stopped working? GeoCoding has usage limits and can return a 403 if your going over those limits.
https://developers.google.com/maps/documentation/business/articles/usage_limits
snip it:
HTTP 403 response
Requests to the web services may also receive a HTTP 403 (Forbidden)
error. In most cases, this is due to an invalid URL signature. To
verify this, remove the client and signature parameters and try again:
If the response is HTTP 200 (OK), the signature was the problem. This
is not related to usage limits; see Generating Valid Signatures in the
Web Services chapter of the Maps API for Business documentation for
details. If the response is still a HTTP 403 (Forbidden) error, the
signature was not necessarily the problem, it may be related to usage
limits instead. This typically means your access to the web service
has been blocked on the grounds that your application has been
exceeding usage limits for too long or otherwise abused the web
service. Please contact Google Enterprise Support if you encounter
this issue. Requests to all web services require URL signatures.
Requests will also be rejected with a HTTP 403 (Forbidden) error when
including the client parameter but missing the signature parameter, or
vice versa.

var loc = await GetLocation("central park");
public static async Task<GeoCoordinate> GetLocation(string address)
{
string url = "http://maps.googleapis.com/maps/api/geocode/json?sensor=true&address=";
using (WebClient wc = new WebClient())
{
wc.Encoding = Encoding.UTF8;
string json = await wc.DownloadStringTaskAsync(url + address);
dynamic result = await JsonConvert.DeserializeObjectAsync(json);
var loc = result.results[0].geometry.location;
return new GeoCoordinate((double)loc.lat, (double)loc.lng);
}
}

Related

Asana API 403 Response in C#

I am trying to implement a Xamarin app that works with the Asana API.
I have successfully implemented the OAuth as documented in the Asana documentation here... at least I assume it is successful. I get an access token from the token endpoint in an HTTPResponse with HTTP Status "OK".
But then when I turn around and try to make an API call with that same access token, I get a 403 Forbidden error. I tried the same API call in my browser (after logging in to Asana), and it works fine, which leads me to believe that I do have access to the resource, I must have an issue with authorizing the request on my end.
The API call in question is (documented here): https://app.asana.com/api/1.0/workspaces.
My C# code is as follows (abbreviated to relevant parts, and assume that ACCESS_TOKEN contains the access token I got from the token exchange endpoint):
HttpClient client = new HttpClient();
client.BaseAddress = "https://app.asana.com/api/1.0";
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", ACCESS_TOKEN);
client.DefaultRequestHeaders.Add("Accept", "application/json");
And then I use this HttpClient (named client) in the following function:
// Returns a list of the Asana workspace names for the logged in user.
private async Task<List<string>> GetWorkspacesAsync()
{
List<string> namesList = new List<string>();
// Send the HTTP Request and get a response.
this.UpdateToken(); // Refreshes the token if needed using the refresh token.
using (HttpResponseMessage response = await client.GetAsync("/workspaces"))
{
// Handle a bad (not ok) response.
if (response.StatusCode != HttpStatusCode.OK)
{
// !!!THIS KEEPS TRIGGERING WITH response.StatusCode AS 403 Forbidden!!!
// Set up a stream reader to read the response.
// This is for TESTING ONLY
using (StreamReader reader = new StreamReader(await response.Content.ReadAsStreamAsync()))
{
// Extract the json object from the response.
string content = reader.ReadToEnd();
Debug.WriteLine(content);
}
throw new HttpRequestException("Bad HTTP Response was returned.");
}
// If execution reaches this point, the Http Response returned with code OK.
// Set up a stream reader to read the response.
using (StreamReader reader = new StreamReader(await response.Content.ReadAsStreamAsync()))
{
// Extract the json object from the response.
string content = reader.ReadToEnd();
JsonValue responseJson = JsonValue.Parse(content);
foreach (JsonValue workspaceJson in responseJson["data"])
{
string workspaceName = workspaceJson["name"];
Debug.WriteLine("Workspace Name: " + workspaceName);
namesList.Add(workspaceName);
}
}
}
// I have other awaited interactions with app storage in here, hence the need for the function to be async.
return namesList;
}
Finally found the answer. It looks like I was using HttpClient incorrectly; a subtle thing that should be equivalent, but is not due to the way it is implemented.
The answer
I needed to place the final slash at the end of the BaseAddress property of HttpClient, and NOT at the start of the relative address for the specific request. This answered question explains this.
To fix my code
I needed to change the setting up of the BaseAddress:
HttpClient client = new HttpClient();
client.BaseAddress = "https://app.asana.com/api/1.0/"; // FINAL SLASH NEEDED HERE
And remove the slash from the request's relative address:
// DO NOT put slash before relative address "workspaces" here
using (HttpResponseMessage response = await client.GetAsync("workspaces"))
Why I got the original error
When HttpClient combined the BaseAddress with the relative URI I specified in GetAsync(), it dropped off some of the base address, since the final slash was not included. The resulting address from combining the BaseAddress with the relative URI was a valid URL, but not a valid page/API call in Asana. Asana thus did an automatic redirect to a login page, which, of course, the rest of the API call would be forbidden from there.
How I discovered this
In debugging, I grabbed the access token returned during my app's authorization with Asana. I then recreated the request to the "/workspaces" API myself in Postman, and the request worked as expected. This confirmed that my authorization worked fine, and the issue must be with the specific request rather than the authorization. In debugging I then looked into the HttpResponseMessage, which has a property called RequestMessage, that includes the actual URL the GetAsync() made the request against. I observed the Login URL from Asana, rather than the BaseAddress I specified... which led me to the question/
answer linked above.
Hope this explanation helps anyone who comes across a similar error!

Configuring "RequireHttpsAttribute" filter to account for X-Forwarded-Proto

I am hosting a ASP.NET Framework application on AWS elastic bean, and I am using a load balancer.
Using my current configuration to require https results in infinite loops because the load balancers are using http to communicate with the server. In order to have my filter function i need to account for the X-Forwarded-Proto Header, which from my understanding contains the original requests protocol.
I do understand what is wrong, but I not understand how I can use this attribute in order to ensure a secure connection.
This is my current config:
public class RequireHttpsAttribute : AuthorizationFilterAttribute {
public int Port { get; set; }
public RequireHttpsAttribute()
{
Port = 443;
}
public override void OnAuthorization(HttpActionContext actionContext)
{
var request = actionContext.Request;
if (request.RequestUri.Scheme != Uri.UriSchemeHttps)
{
var response = new HttpResponseMessage();
if (request.Method == HttpMethod.Get || request.Method == HttpMethod.Head)
{
var uri = new UriBuilder(request.RequestUri);
uri.Scheme = Uri.UriSchemeHttps;
uri.Port = this.Port;
response.StatusCode = HttpStatusCode.Found;
response.Headers.Location = uri.Uri;
}
else
{
response.StatusCode = HttpStatusCode.Forbidden;
}
actionContext.Response = response;
}
else
{
base.OnAuthorization(actionContext);
}
}
}
This filter config is added to my WebApiConfig.
My question is:
How do check for the X-Forwarded-Proto in this filter?
If your load balancers are handling SSL for you, you'd cede that restriction (SSL only) to them - as you have noticed, your app will always detect http:80 (not https:443).
Do not use RequireHttpsAttribute on Web APIs that receive sensitive
information. RequireHttpsAttribute uses HTTP status codes to redirect
browsers from HTTP to HTTPS. API clients may not understand or obey
redirects from HTTP to HTTPS. Such clients may send information over
HTTP. Web APIs should either:
Not listen on HTTP.
Close the connection with status code 400 (Bad> Request) and not serve the request.
The note in the doc is saying that API clients may/may not follow your redirect response, so it's recommended that you respond with some error (nor not at all) - and is where you should check on the http headers. In your case, you can't do the first because your app will always get HTTP:80 (hence only the http header check/filter).
In an MVC site you can do routing redirects (Url Rewrite, etc), but that works because the clients are browsers (and know what do with a redirect). An API client however, can be anything (not just browsers).
Update/clarification:
Of course it's important so you should still filter the http header forwarded by your load balancer(s) that indicate whether or not the origin request was via https or not and follow the recommendation in doc - respond with an appropriate http error code (the note suggests 400 Bad Request).
What you can't do is check the actual scheme/protocol of the origin request because your load balancers will always forward http:80 to your app.
TLDR: you restrict based on http header info forwarded by your load balancer(s).

Using one legged OAuth1 in C#, gets error: (401) Unauthorized

I am using an one legged OAuth1 web service! which means I don't need to get a token to get my result just consumer key and secret is enough.I have used many different APIs and got the same result every time,I don't get what I'm doing wrong!
here is the latest API I've used:
https://github.com/rhargreaves/oauth-dotnetcore
the OAuth classes are pretty much straight forward,I've used those and made my request this way:
OAuthRequest client = OAuthRequest.ForRequestToken("key", "secret");
client.RequestUrl = "http://some site/?q=api/sbu_rest/user_books_returned/username";
// For HTTP header authorization
string auth = client.GetAuthorizationHeader();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(client.RequestUrl);
request.Headers.Add("Authorization", auth);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
but I get the error:
The remote server returned an error: (401) Unauthorized.
It's worth to mention that I have checked my URL ,key and secret in postman and they work fine(I'll get the result I want which is a list of books!)
PS: the signature method is HMAC-SHA1

HttpWebRequest not being received correctly in MVC ASP.NET

This is me publicly documenting my mistake so that if I or anyone does it again, they don't have to spend 3 hours tearing their hair out trying to fix such a simple thing.
Context
I was sending an HttpRequest from one C# MVC ASP.NET application to another.
The applications require an HTTPS connection, and we are using URLRewrite to redirect an HTTP request to an HTTPS url.
One application was sending a POST request with some JSON data in the body, pretty standard stuff. The other application was set up to receive this data with an MVC controller class (CollectionAction and Insert methods for GET and POST respectively).
Symptoms of the problem
The receiving application was running the GET method (CollectionAction) instead of the POST action (ItemAction). The reason for this was that the request coming in to the application was in fact a GET request, and to top it off the JSON data was missing too.
I sent the header "x-http-method" to override the request method from GET to POST (I was already setting the request httpmethod to POST but this was being ignored). This worked but still I had no data being sent.
So now I am stuck pulling my hair out, because I can see a POST request with content-length and data being sent out and I have a GET request with no data or content-length coming in (but the headers were preserved)
Turns out I was using UriBuilder to take a base URL and apply a resource path to it. For example I would have "google.com" in my web.config and then the UriBuilder would take a resource like Pages and construct the url "google.com/Pages". Unfortunately, I was not initializing the UriBuilder with the base URL, and instead was using a second UriBuilder to extract the host and add that to the path like so:
public Uri GetResourceUri(string resourceName)
{
var domain = new UriBuilder(GetBaseUrl());
var uribuilder = new UriBuilder()
{
Path = domain.Path.TrimEnd('/') + "/" + resourceName.TrimStart('/'),
Host = domain.Host
};
var resourceUri = uribuilder.Uri;
return resourceUri;
}
The problem with this code is that the scheme is ignored (HTTP:// vs HTTPS://) and it defaults to HTTP. So my client was sending out the request to an HTTP url instead of the required HTTPS url. This is the interesting part, URLRewrite was kicking in and saying that we needed to go to an HTTPS url instead so it redirected us there. But in doing so, it ignored the Http-Method and the POST data, which just got set to defaults GET and null. This is what the 2nd application could see at the receiving end.
So the function had to be rewritten to this which fixed the problem:
public Uri GetResourceUri(string resourceName)
{
var baseUrl = GetBaseUrl();
var domain = new UriBuilder(baseUrl);
var uribuilder = new UriBuilder(baseUrl)
{
Path = domain.Path.TrimEnd('/') + "/" + resourceName.TrimStart('/'),
};
var resourceUri = uribuilder.Uri;
return resourceUri;
}

google oauth access token 411 response

I'm working with google's OAuth api for web server applications, specifically asp.net mvc, and i'm able to get to the point where google returns an authorization code for a certain oauth request. At that point, I'm trying to obtain the access token using the following code:
public ActionResult GetOAuthToken()
{
HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(OAuthConfig.getTokenUrl(Request.QueryString["code"].ToString()));
myReq.Method = "POST";
myReq.Host = "accounts.google.com";
myReq.ContentType = "application/x-www-form-urlencoded";
WebResponse resp = myReq.GetResponse();
return View();
}
The OAuthConfig is just a class I wrote that contains a method getTokenUrl(), which returns a url with parameters such as code, client_secret, client_id etc. for the url: https://accounts.google.com/o/oauth2/token. I've debugged and checked that there's nothing wrong with this url.
I keep getting the following error: The remote server returned an error: (411) Length Required.
I don't know what to specify for the content length, or if there's something else that i need to include to fix this error?
Have you tried to have a look at Google-API .NET Client?
If you debug you will see Google uses "length" as an internal property when sending access-token request. you can try to fix it on your own, but you can use THEIR class in order to send the token request; If you use their class you do not have to worry about internal such as length...

Categories

Resources