ServiceStack custom response on failed authentication - c#

I've created a custom authentication for servicestack, which works well. The only problem is, that I get empty responses for every route, that requires authentication, when I am not logged in. How can I change this to return something like
{
"statuscode":"401",
"message":"Unauthorized"
}
Thanks!

The Status Code and the Status Description is already in the returned HTTP Response Headers which is the expected response from a HTTP API. If you're calling from a web browser (i.e. client that accepts HTML) you can implement a /login page (configurable with AuthFeature.HtmlRedirect) to show the user a login page.
Otherwise you can override OnFailedAuthentication() in your Custom AuthProvider to override what gets returned in a failed Auth response, be mindful of what you write in the response body as a JSON response only makes sense for clients requesting JSON responses.

Related

C# HttpClient authorization header removed after send to server

I wanna send request to external API through the HttpClient from my own API in c#.
I am using dot net 5 and basic authentication.
Here is my code:
var client = new HttpClient
{
BaseAddress = new Uri(baseUrl)
};
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Put, "apiUrl");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var param = JsonConvert.SerializeObject(new
{
param1="",
param2=""
});
requestMessage.Content = new StringContent(param, Encoding.UTF8, "application/json");
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(Encoding.ASCII.GetBytes($"{user}:{pass}")));
HttpResponseMessage response = await client.SendAsync(requestMessage);
Usually, I send http request like this.
but now I have some problem.
After line HttpResponseMessage response = await client.SendAsync(requestMessage); authorization header removed from my request header and I got UnAuthorized http error.
I know that when redirection occurs, authorization header removed for security reason. Also I'm not sure about redirect in external API.
I add the HttpClientHandler with AllowAutoRedirect = false to my HttpClient
var handler = new HttpClientHandler()
{
AllowAutoRedirect = false,
};
var client = new HttpClient (handler)
{
BaseAddress = new Uri(baseUrl)
};
Now I got Redirect error 301(Permanently moved).
I decided to test the code in Postman. By default, when I call API in Postman, I got http error 405 method not allowed and error detail like this:
{
"detail": "Method "GET" not allowed."}
External API method is PUT. but here I got GET Error.
I tried many options in postman and finally I find the option in Postman:
When I toggle it on, external API work's properly.
Also I test it with Insomnia and it's work properly.
Does it related to my code or dot net 5 or what other thing in my code or it's related to external API?
If it's related to my code, How can I solve the error?
If error related to external API, why Postman and Insomnia response is ok?
External API has Core Policy for specific domain and I send request from other domain.
All I Know is that the CORS policy applied in browser. not in Postman, Insomnia or C# Code.
What about CORS? Does it related to CORS? if Yes, what shall I do?
I will be grateful for your answer.
Update
I detect WWW-Authenticate: JWT realm="api" in the response header.
What exactly is it? and what shall I do?
I find out the problem. It's really Ridiculous.
When I use URL like www.abc.com/api/something the request gets 301 error and postman sends another request like www.abc.com/api/something/. The difference is just / at the end of request.
I tried new URL in postman and first request got ok.
Also I tried URL in my C# code and again its ok.
But i could not understand why.
Thanks a lot dear #pharaz-fadaei
You are right about the removal of authorization headers after redirects. But keep in mind that this behavior is part of the design of the HttpClient in C#. Postman and Insomnia may have different mechanisms to send the authorization headers on each consecutive request that is caused by redirects. The option that you enabled in Postman will make it use the original HTTP method you specified (PUT) as the HTTP method to send further requests based on the redirect messages (Postman uses GET method by default on requests instructed by redirect messages).
The fact that you see a 301 shows that a redirection is required. You can check Location header value in response.Headers to see the real location and send your requests with the authorization headers to that endpoint directly. If I were you I wouldn't use the new location directly because the original endpoint is what you were given by the authors of the API. Instead I would programmatically send the request to the original endpoint and resend the request on 301 codes to the new Location (use PUT method due to the behavior of Postman) until you get the result. This answer can give you some ideas: https://stackoverflow.com/a/42566541/1539231
Since you see WWW-Authenticate: JWT realm="api" header, the external API is required a JWT token authentication, not basic authentication. I think first you might need to check external api's documentation.

Why am I getting a 401 unauthorized when using HttpResponseMessage with a secure url?

I have this proprietary code I am working on for my job.
I am writing test cases for it because the code was changed and the test cases are now broken.
It is a C# web Api MVC .Net Framework app
I have a method that I enter a string url in
Then this code executes
HttpResponseMessage response = await Client.GetAsync(url).ConfigureAwait(true);
System.Uri uri = new System.Uri(url); // convert string to Uri
var cert = System.Net.ServicePointManager.FindServicePoint(uri).Certificate;
response.EnsureSuccessStatusCode();
when it gets to response.EnsureSuccessStatusCode() , it gives a 401 unauthorized and then throws an exception not allowing my test to pass
When I try the same thing with http://www.google.com which is not an https, then
it gives a 200. So something is going on with security stuff
What are the things I need to do to get a https to give a 200? Does it need username and password credentials or something or some other token of some sort?
Also, when I test it using Rest Client DHC with the secure https link that was failing above it gives me a 200. However, I had to refresh the bearer token for it to give a 200. If I used an old token it would give a 401.
Furthermoore, when I test a different link like https://www.facebook.com (which is not the one I want to test in my application, just troubleshooting) which is secure, it works giving me a 200 both in my application above and Rest Client DHC even with an old bearer token.
If you're trying to makes CORS requests to web API, you'll need to configure It to accept cross origins requests. If you dont configure your web api to accept cross origin requests, it'll throw these type of errors when calling It. And keep in mind that for web api access, https://www.domain.so and http://www.domain.so are completely diff clients.
Look at this link:
https://learn.microsoft.com/en-us/aspnet/web-api/overview/security/enabling-cross-origin-requests-in-web-api

Http Header Throws Exception C# HttpResponseMessage

Okay I'm developing a sevice application that runs on Cisco IP Phones. The application involves displaying messages to the phone.
I would like to make use of the way CISCO phones use the Expires header in a http Response. Basically a message i send to the phone will expire when the time specified in the header is reached (expired messages are removed from the message stack). The full documentation can be read at this address
http://www.cisco.com/en/US/docs/voice_ip_comm/cuipph/all_models/xsi/3_3_4/english/programming/guide/ip334ch5.html#wp1030621
In my C# WebService i construct the response using a HttpResponseMessage. Before i return my response i add the Expires header using
response.Headers.Add("Expires", "-1"); //Immediately expires.
My problem:
The previous line of code throws an InvalidOperationException
with the message Make sure request headers are used with HttpRequestMessage, response headers with HttpResponseMessage
I believe that the HttpResponseMessage is performing some validation and that Expires is not a valid response header. But its what the CISCO stuff requires.
Can i force this key value into the header even though its not strictly correct HTTP
The Expires header is on the Content object.
response.Content.Headers.Expires = new DateTimeOffset(DateTime.UtcNow.Add(new TimeSpan(0,0,0,5)));

Get Host of HttpResponseMessage in Windows Store App

I have a Windows Store App (C#) where I am sending a HttpRequest and I want to check if the response I am getting is from a Captive/Limited Access Network or from the actual host specified in the HttpRequest.
So lets say I am sending a request to www.serverA.com
I look at the response of that request and determine if it was success based on the status code.
Imagine the same scenario in a captive network(airport networks/starbucks where they redirect you to a login page):
I am sending a request to www.serverA.com
My request gets redirected
to www.serverB.com/AirPortLoginPage
I get back a response that the
AirportLoginPage loaded successfully with a 200 response
My code sees that as a success because of the 200 status code, but I wanted to know if my original request was successful
So, is there a way to determine the host of the server where the Response Message is coming from?
Two things which can solve your problem:
You can set HttpClientHandler.AllowAutoRedirect property to
false. But if any other code depends on this - you will need to
handle 3xx (redirect) manually.
You can check HttpResponseMessage.RequestMessage. In your example after you will send request to www.serverA.com - this property will have www.serverB.com/AirPortLoginPage

IE8 gets stuck while sending openid authentication request with activated attribute exchange

I´m getting a problem sending the authentication request with activated attribute exchange. It works with FF and Opera but IE seems to have a problem with it.
The error occurs within the request.RedirectToProvider(). The Url within the address bar shows the endpoints url.
Here is a code snippet where the authentication request is created and sent
using (OpenIdRelyingParty openid = this.createRelyingParty())
{
IAuthenticationRequest request = openid.CreateRequest(openid_identifier, realm);
;
var fetch = new FetchRequest();
fetch.Attributes.AddRequired(WellKnownAttributes.Contact.Email);
request.AddExtension(fetch);
// Send your visitor to their Provider for authentication.
request.RedirectToProvider();
}
I guess that inside RedirectToProvider() a POST is sent and short after a GET. By RFC a POST followed by a GET is not allowed. Unfortunately I don`t know how to validate it.
Does someone got the same problem?
On further investigation this seems to happen (based upon the providers logs):
The authentication request is sent via POST. The Provider answers with a redirect. This is how it happens that there is at first a POST and then a GET.
I dont think this is how the openId specification say to do it. Shouldnt there be a POST response if i request with a POST and a GET if I request with a GET?
Anyhow.. Is there a way to make the RedirectToProvider()-method sending the request via GET instead of POST?

Categories