Add Multiple WWW-Authenticate headers with OWIN - http

I want our service to advertise more than one authentication scheme: for example both Bearer and some custom scheme, say X-Custom. (I have an OWIN middleware component for each scheme). I take if from RFC 2616, sec 14.47 there is more than one way to do it:
Option a) multiple headers
WWW-Authenticate: Bearer
WWW-Authenticate: X-Custom
Option b) comma-separated list
WWW-Authenticate: Bearer, X-Custom
My preference would be option a) so a client only has to do something like Response.Headers.Exists("WWW-Authenticate", preferredScheme) instead of comma parsing the header (which the RFC says they should, but...)
However, Katana uses a dictionary for headers. Trying to add the second header throws an exception with "The key 'WWW-Authenticate' is already present in the dictionary."
Is there a way for a middleware component to inject more than one WWW-Authenticate header?

It is IDictionary<string, string[]>. Key is a string but value is an array of string. So, you just need to set the header like this.
app.Run(async (IOwinContext context) =>
{
context.Response.Headers.Add("WWW-Authenticate",
new[] { "Bearer", "X-Custom" });
// Some other code
});
UPDATE
I believe you are very kind to accept my answer as answer :). Thanks but not sure it answered your question and hence the edit. First of all, I did not get the point you tried to make, which is to add the different headers from different middleware and yet wanting to see them in different lines in the response. I do not think there is anyway to do this for standard HTTP headers like WWW-Authenticate. In fact, before I answered your question, I quickly wrote a small program to verify but the mistake I made was to misspell this header.
Because of that, I was actually getting the header values like this.
WWW-Authentciate: X-Custom
WWW-Authentciate: Bearer
Anyways, the following works in getting the header values in two lines.
app.Use(async (IOwinContext context, Func<Task> next) =>
{
context.Response.Headers.Set("WWW-Authenticate", "Bearer");
await next.Invoke();
});
app.Run(async (IOwinContext context) =>
{
var x = context.Response.Headers.Get("WWW-Authenticate");
context.Response.Headers.Remove("WWW-Authenticate");
context.Response.Headers.Add("WWW-Authenticate", new[] { "X-Custom", x });
});
However, this does not work for standard headers. Nonetheless, this is an interesting exercise but at the end of the day, there is no accepted standard in terms of the API here (as far as I know). Even if you somehow get this working the way you want, the moment you change an underlying OWIN component, say the server or host, you could get different behavior. After all, option a and option b are exactly the same and you should not see any difference if you are working on top of some library to read the headers, unless you do some low-level stuff.

Related

Send a File as well as parameters (through JSON) inside one HTTP request

I am creating a server using Go that allows the client to upload a file and then use a server function to parse the file. Currently, I am using two separate requests:
1) First request sends the file the user has uploaded
2) Second request sends the parameters to the server that the server needs to parse the file.
However, I have realised that due to the nature of the program, there can be concurrency problem if multiple users try to use the server at the same time. My solution to that was using mutex locks. However, I am receiving the file, sending a response, and then receiving the parameters and it seems that Go cannot send a response back when the mutex is locked. I am thinking about solving this problem by sending both the file and the parameters in one single HTTP request. Is there a way to do that? Thanks
Sample code (only relevant parts):
Code to send file from client:
handleUpload() {
const data = new FormData()
for(var x = 0; x < this.state.selectedFile.length; x++) {
data.append('myFile', this.state.selectedFile[x])
}
var self = this;
let url = *the appropriate url*
axios.post(url, data, {})
.then(res => {
//other logic
self.handleParser();
})
}
Code for handleParser():
handleNessusParser(){
let parserParameter = {
SourcePath : location,
ProjectName : this.state.projectName
}
// fetch the the response from the server
let self = this;
let url = *url*
fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(parserParameter),
}).then( (response) => {
if(response.status === 200) {
//success logic
}
}).catch (function (error) {
console.log("error: ", error);
});
}
The question is not really about Go or reactjs or any particular software library.
To solve your problem you'd first need to understand how HTTP POST works,
hence I invite you to first read this intro on MDN.
In short:
There are multiple ways to encode the data sent in a POST request.
The way the receiver should deal with this data depends on how it's encoded by the sender.
The sender has to communicate the encoding with its request — usually via the Content-Type header field.
I won't go into the details of possible encodings — the referenced introductory material covers them, and you should do your own research on them, but to maybe recap what's written there, here is some perspective.
Back in the 80s and 90s the web was "static" and the dreaded era of JavaScript-heavy "web apps" did not yet come. "Static" means you could not run any code in the client's browser, and had to encode any communication with the server in terms of plain HTML.
An HTML document could have two ways to make the client rendering it to send something back to the server: a) embed an URL which would include query parameters; this would make the client to perform a GET request with these parameters sent to the server; b) embed an HTML "form" which, when "submitted", would result in performing a rather more complex POST request with the data taken from the filled in form.
The latter approach was the way to leverage the browser's ability to perform reasonably complex data processing — such as slurpling a file selected by the user in a specific form's control, encoding it appropriately and sending it to the server along with the other form's data.
There were two ways to encode the form's data, and they are both covered by the linked article, please read about them.
The crucial thing to understand about this "static web with forms" approach is that it worked like this: the server sends an HTML document containing a web form, the browser renders the document, the user fills the form in and clicks the "submit" button rendered by the browser; the browser collects the data from the form's controls, for entries of type "file" it reads and encodes the contents of those files and finally performs an HTTP POST request with this stuff encoded to the URL specified by the form. The server would typically respond with another HTML document and so on.
OK, so here came "web 2.0", and an "XHR" (XMLHttpRequest) was invented. It has "XML" in its name because that was the time when XML was perceived by some as a holy grail which would solve any computing problem (which it, of course, failed to do). That thing was invended to be able to send almost arbitrary data payloads; XML and JSON encoding were supported at least.
The crucial thing to understand is that this way to communicate with the server is completely parallel to the original one, and the only thing they share is that they both use HTTP POST requests.
By now you should possibly see the whole picture: contemporary JS libs allow you to contruct and perform any sort of request: they allow you to create a "web form"-style request or to create a JS object, and serialise it to JSON, and send the result in an HTTP POST request.
As you can see, any approach allows you to pass structured data containing multiple distinct pieces of data to the server, and the way to handle this all is a matter of agreement between the server and the client, that is, the API convention, if you want.
The difference between various approaches is that the web-form-style approach would take care of encoding the contents of the file for you, while if you opt to send your file in a JSON object, you'll need to encode it yourself — say, using base64 encoding.
Combined approaches are possible, too.
For instance, you can directly send binary data of a file as a POST request's body, and submit a set of parameters along with the request by encoding them as query-parameters of the URL. Again, it's up to the agreement between the client and the server about how the latter encodes the data to be sent and the former decodes them.
All-in-all, I'd recommend to take a pause and educate yourself on the stuff I have outlined above, and then have another stab at solving the problem, but this time — with reasonably complete understanding about how the stuff works under the hood, and how you intend to wield it.

Android,Retrofit how to use #Headers?

Currently, I am using Retrofit in Android.
Every REST call have different headers. I find there is key word #Header in retrofit in Retrofit, the example is as follows:
#GET("/tasks")
Call<List<Task>> getTasks(#Header("Content-Range") String contentRange);
But I also find another key words #Headers, How can I use Headers in Retrofit, because I have many headers, so I think #Headers maybe better.
Don't post okHttpClient method, I have already known how to use that.
Thanks
#Headers is for static headers, arguments cannot go there.
#Headers({
"X-Something: Foo",
"X-Else: Bar",
"Cache-Control: max-age=300000"
})
#GET("/getStuff") <Task> getStuff();
if you got many different headers per call then you need to use #Header or rethink your API on a backend. Alternatively you may add headers using Interceptor but I do not think this is the way to go.

Manipulate the response status text in Play 2.2 Scala

Does anyone know how to manipulate the HTTP Status text in Scala Play 2.2?
I see that it's easy to specify the status code but not the accompanying text.
The reason I'm interested is that I'm trying to emulate exactly a web service I need to consume, and it puts specific information in the status text.
For example, when failing a login attempt I'll get the following snippet from this service (curl output):
< HTTP/1.1 401 username or password invalid
< ...
When I return an Unauthorized response from my Mock service I just get the following:
< HTTP/1.1 401 Unauthorized
< ...
I'm clearly missing the real way to do this if it's even possible in the first place.
Here's how I'm constructing the unauthorized response:
Unauthorized(views.html.invalidlogon(message)).withHeaders(
CONTENT_TYPE -> "text/plain"
)
Here's what I'd like to do in my fictional naive world:
Unauthorized(views.html.invalidlogon(message)).withHeaders(
CONTENT_TYPE -> "text/plain"
).setStatusText(message)
Thanks for the help!
Edit - Additional Info
So it turns out what I'm really looking for is the Reason Phrase.
According to the RFC they say the following:
The reason phrases listed here are only recommendations -- they MAY be replaced by local equivalents without affecting the protocol.
Of particular interest is the use of MAY with regard to the existing error codes.
However if in Play I return a custom 4XX error then the reason phrase is just Client Error following the classification of the 4XX status. It would be nice to have control over the reason phrase so that it accompanies the custom response status code.
De facto response status is a numeric value by HTTP specification and therefore it's hardcoded in Play.
If you really need this so as suggested in answer to other question it's better to add custom header, ie:
Unauthorized("You can't login now, sorry...").withHeaders(
CONTENT_TYPE -> "text/plain; charset=utf-8",
"X-Error-Message" -> "Login or password invalid"
)
TIP: For security reasons be careful with too descriptive error messages during login proccess.
After review of the Play code I don't think this is possible at the moment.
If you look here they do the following:
def createNettyResponse(header: ResponseHeader, closeConnection: Boolean, httpVersion: HttpVersion) = {
val nettyResponse = new DefaultHttpResponse(httpVersion, HttpResponseStatus.valueOf(header.status))
...
The call to HttpResponseStatus.valueOf(header.status) doesn't allow for Reason Phrase to be added.
In a purely fictional (and possibly dubious) world the following change might allow this:
def createNettyResponse(header: ResponseHeader, closeConnection: Boolean, httpVersion: HttpVersion) = {
val nettyResponse = header.reasonPhrase match {
case Some(reasonPhrase) => new DefaultHttpResponse(httpVersion, HttpResponseStatus(header.status, header.reasonPhrase))
case _ => new DefaultHttpResponse(httpVersion, HttpResponseStatus.valueOf(header.status))
}
...
However a change like that has a big ripple effect.
So If I'm correct, this is just not possible and I will see what the Play folks think.
thanks

Angular: Custom headers are ignored by $http and $resource. Why?

I'm trying to access a REST service I don't control. First problem is that the service doesn't include a Access-Control-Allow-Origin header, which is a problem that, if I understand correctly, immediately limits me to JSONP.
Also, by default, this service sends XML rather than JSON, though it's capable of sending JSON. I think it should respond to my Accept header, the people responsible for the service say it looks at my Content-Type. That would mean I'd need to do a POST rather than a GET (though get makes more sense when I'm just getting some static data, right?).
Stubborn as I am, I'm trying my Accept header first. Since Angular only accepts JSON, I'd expect it to use the Accept: application/json header by default, but it doesn't, and it ignores my attempts to set it manually:
app.config(['$httpProvider', function($httpProvider){
console.log($httpProvider.defaults.headers.common);
delete $httpProvider.defaults.headers.common['X-Requested-With'];
$httpProvider.defaults.headers.post['Accept'] = 'application/json, text/javascript';
$httpProvider.defaults.headers.post['Content-Type'] = 'application/json; charset=utf-8';
$httpProvider.defaults.headers.post['Access-Control-Max-Age'] = '1728000';
$httpProvider.defaults.headers.common['Access-Control-Max-Age'] = '1728000';
$httpProvider.defaults.headers.common['Accept'] = 'application/json, text/javascript';
$httpProvider.defaults.headers.common['Content-Type'] = 'application/json; charset=utf-8';
$httpProvider.defaults.useXDomain = true;
}]);
I do this again in the actual resource:
return $resource('http://foo.com/getStuff', {}, {
fetch: {
method:'JSONP',
params: params,
headers: {
'Accept':'application/json, text/javascript',
'Content-Type':'application/json; charset=utf-8'
},
isArray:false,
callback: 'JSON_CALLBACK'
}
});
But still, the request headers contain Accept: */*.
My question is: WHY? Why does Angular ignore my headers? And how do I get it to use the proper headers anyway?
And also: is there a way to use JSONP in a POST?
Edit: Originally I used Angular 1.0.7, but I just tried it with 1.2.3 and got the same results. Headers are ignored, yet everybody claims that this is the way to do it.
I also tried doing it directly with $http, rather than with $resource, with the same results.
Edit 2: Here's a JSFiddle. It's anonymized and doesn't use my real server, but using Firebug/developer tools, you can verify that it sends Accept: */* on both calls, despite my many attempts to set application/json headers. And that is my real problem here. On my real server, I'm getting an XML result because of that, despite my real server's ability to send JSON.
(Whether the real server supports jsonp is less relevant at the moment. This dummy server clearly doesn't, but that's okay. I just care about the headers.)
Edit 3: I've tried both solutions suggested below:
$http.defaults.headers.common['Accept'] = 'application/json, text/javascript';
$http.defaults.transformRequest.push(function (data, headersGetter) {
headersGetter().Accept = "application/json, text/javascript";
return data;
});
I've tried both statements separately. In the controller, and then in the service just before the http call itself. Still doesn't work.
Can someone give me a JsFiddle where this is shown to work?
Edit 4: I notice that when I use GET rather than JSONP, the Accept header is correct. But then the response is rejected because it doesn't have the correct header.
What kind of headers should a JSONP call have? Because there's a lot more headers in the JSONP call, but nothing that identifies it as JSONP. Does the server have to have explicit JSONP support for this to work? I suddenly realize I don't know nearly enough about jsonp.
I think your answer is here. According to the wiki, A JSONP call is executed through injection of a <script> tag to load the script from the host server, which responds by calling your callback, passing the data. A <script> tag generates a regular browser request (not an XmlHttpRequest), and the browser will send its own Accept header (it also sends its own User-Agent header, for example).
I would hope there is an easier client-side way to do this, but I think the only way may be the one suggested in the referenced post:
So, if you want to be able to set request headers for cross domain calls
you will have to setup a server side script on your domain that will
delegate the call to the remote domain (and set the respective
headers) and then send the AJAX request to your script.
EDIT: here is a (rejected) jQuery bug report about this same problem.
Some more background info:
In angular, callbacks are managed automagically, so if your say this:
$http({
method: "JSONP",
url: "http://headers.jsontest.com?callback=JSON_CALLBACK",
}).success(function(data) {
console.log('Return value:');
console.log(data);
}).error(function(data) {
console.log('Error!');
console.log(data);
})
a <script> tag will be created that looks more or less like this:
<script type="application/javascript"
src="http://headers.jsontest.com/?callback=angular.callbacks._1">
</script>
The content of the response to http://headers.jsontest.com/?callback=angular.callbacks._1 will be:
angular.callbacks._1({key1: "value1", key2: "value2"});
angular.callbacks._1 will contain your success function, and it will be called with the data.
While what you have is supposed to work according to the docs, my experience has been a bit different. To get around this issue, we did the following:
Create a "base controller" that gets added to the page either on the body or html tag.
In that controller, make the assignment using $http instead of $httpProvider. Because your base controller loads when the initial page loads, it is there for all other controllers and services that will run in your app.
I don't know why this works and the proscribed method does not, and I'd love to see an answer to your question that is better than this work-around, but at least this can get you moving forward with development again.
The following works for me - however, I do that during "runtime" with $http and I am not using $httpProvider during bootstrapping.
function SomeCtrl($http) {
$http.defaults.transformRequest.push(function (data, headersGetter) {
headersGetter().Accept = "application/json, text/javascript";
return data;
});
}
Edit
Here is a working jsFiddle version. Check the request which is done with Developer Tools/Firebug and see that "application/json, text/javascript" is requested.

Is it considered bad practice to perform HTTP POST without entity body?

I need to invoke a process which doesn't require any input from the user, just a trigger. I plan to use POST /uri without a body to trigger the process. I want to know if this is considered bad from both HTTP and REST perspectives?
I asked this question on the IETF HTTP working group a few months ago. The short answer is: NO, it's not a bad practice (but I suggest reading the thread for more details).
Using a POST instead of a GET is perfectly reasonable, since it also instructs the server (and gateways along the way) not to return a cached response.
POST is completely OK. In difference of GET with POST you are changing the state of the system (most likely your trigger is "doing" something and changing data).
I used POST already without payload and it "feels" OK. One thing you should do when using POST without payload: Pass header Content-Length: 0. I remember problems with some proxies when I api-client didn't pass it.
If you use POST /uri without a body it is something like using a function which does not take an argument .e.g int post (void); so it is reasonable to have function to your resource class which can change the state of an object without having an argument. If you consider to implement the Unix touch function for a URI, is not it be good choice?
Yes, it's OK to send a POST request without a body and instead use query string parameters. But be careful if your parameters contain characters that are not HTTP valid you will have to encode them.
For example if you need to POST 'hello world' to and end point you would have to make it look like this: http://api.com?param=hello%20world
Support for the answers that POST is OK in this case is that in Python's case, the OpenAPI framework "FastAPI" generates a Swagger GUI (see image) that doesn't contain a Body section when a method (see example below) doesn't have a parameter to accept a body.
the method "post_disable_db" just accepts a path parameter "db_name" and doesn't have a 2nd parameter which would imply a mandatory body.
#router.post('/{db_name}/disable',
status_code=HTTP_200_OK,
response_model=ResponseSuccess,
summary='',
description=''
)
async def post_disable_db(db_name: str):
try:
response: ResponseSuccess = Handlers.databases_handler.post_change_db_enabled_state(db_name, False)
except HTTPException as e:
raise (e)
except Exception as e:
logger.exception(f'Changing state of DB to enabled=False failed due to: {e.__repr__()}')
raise HTTPException(HTTP_500_INTERNAL_SERVER_ERROR, detail=e.__repr__())
return response

Resources