No means of authenticating redirects

In `requests/requests-kerberos` we use GSSAPI to not only authenticate to the server, but also authenticate the server as well. It's called mutual authentication. The way that `Session.send` resolves redirects doesn't allow us to authenticate the redirects. 

This is a problem because if a user sends a request to `host_a` which redirects us to `host_b` and we authenticate `host_b` successfully, that really doesn't mean anything to the user if he can't actually trust that the process which issued the redirect was actually `host_a`.

This means that if we want to require mutual authentication, we cannot follow redirects at all, even if the servers are capable of authenticating their redirects.

Would it be possible to either:
1. Dispatch the `response` hook on redirects
2. Create a new kind of hook which authentication mechanisms can install specifically for handling redirects?

I see problems with option 1. If we'd be amenable to option 2, I'll work on a pull request for it. Unless someone says otherwise I'd call the hook `redirect`.


Some more details are in the commit message at https://github.com/mkomitee/requests-kerberos/commit/954ae437d7748a61748503bb77ff77a2d662c731


Have you seen issue #1160? It's kind of similar to this one, isn't it?


@piotr-dobrogost, this is about not allowing redirects in certain cases. That is about modifying things passed via the `params` parameter because they only get `PreparedRequest`s.

I'm inclined to say that the `response` hook should be called on redirects. The initial response should be assuming that there isn't a redirect in that first request. I think we expect a 401 upon which we authenticate. With that we get a response with a request attribute. That request attribute has the original hooks. I'll take a look at how we re-send the request with the proper authentication.


Oh, I forgot to mention that the latter suggestion is not going to be accepted due to the feature freeze in requests.


So you're forced to use the Adapter's `send` method because you don't have access to the session. The best we can do is import `dispatch_hook` from `requests.hooks` and use that do dispatch the hook on the request since the request already has its hooks. But I'm not sure if that would help you.


That doesn't help. We need to get called with the redirect so that we can determine whether or not it's to be trusted and followed because we may not want to follow it.


I think it would probably be reasonable to call the response hook on redirects.

Quite aside from that, I don't think it's unreasonable to say that if you're concerned about unauthenticated redirects, you should turn redirects off and manage them yourself.


I'm okay with handling redirects myself. 

I just don't want to spoil the API to do so:

HTTP for humans -- I'd really rather not have to instruct people that they have to turn redirects off in their request and then configure a duplicate flag on their request object. That kind of spoils the 'one obvious way to do it' concept and the entire philosophy behind requests. 

This is also similar to the reasoning behind why `verify=True` by default, so forcing people to read a bunch of documentation and flip a bunch of switches to get secure behavior -- which but for this could be the default -- is also against the philosophy.


So @mkomitee, I've thought about this some more. Where are you concerned about redirects? In the initial request? If so, I understand your concern. If you're instead concerned about redirects after the 401 has been handled, you can prevent those yourself. You have access over the response at that point I believe.


I'm concerned about it in the initial request.

On Tue, Feb 12, 2013 at 12:36 PM, Ian Cordasco notifications@github.com
wrote:

> ## So @mkomitee, I've thought about this some more. Where are you concerned about redirects? In the initial request? If so, I understand your concern. If you're instead concerned about redirects after the 401 has been handled, you can prevent those yourself. You have access over the response at that point I believe.
> 
> Reply to this email directly or view it on GitHub:
> https://github.com/kennethreitz/requests/issues/1183#issuecomment-13444844


Ah, I see what you mean. We resolve redirects before dispatching hooks. If that came before the redirect resolution, that would mean you could catch the redirect, correct?

Semantically I think it should be there anyway. If a redirect is resolved, every request except the first has the hook called on it (because each subsequent request calls `send` with `allow_redirects=False`). It should before the resolution unless @kennethreitz or @Lukasa disagree.


Yes.

That said (and I've been keeping it out of scope for this specific discussion -- once this is resolved I'll be opening another Issue/Feature Request) it would be very helpful if I had access to the kwargs originally passed to `requests.get` so that I could actually use the user requested options which don't get added to the request when I send future requests during authentication (e.g. verify, proxies, cert, allow_redirects etc). It would also be nice to have access to the `requests.Session` itself so that I can use the already well known, understood, and tested `resolve_redirects` code.


@mkomitee I have no real opinion about forcing Auth providers to accept all of those parameters, but I doubt it will be accepted. On that topic though, `allow_redirects` should be handled by the Session without a doubt. The Auth providers should have no reason to worry about that. I can understand needing the `proxies`, `timeout`, `stream` and `cert` parameters, but I thoroughly disagree that it is the responsibility of the auth provider to handle  redirects. With that said (twice), there shouldn't be a need to send the `Session` object itself.


If authentication is required for the redirect, the 401 goes to the auth provider and there's no way back to the redirect handling code. That's all out of scope for this issue though.

On Tue, Feb 12, 2013 at 6:22 PM, Ian Cordasco notifications@github.com
wrote:

> ## @mkomitee I have no real opinion about forcing Auth providers to accept all of those parameters, but I doubt it will be accepted. On that topic though, `allow_redirects` should be handled by the Session without a doubt. The Auth providers should have no reason to worry about that. I can understand needing the `proxies`, `timeout`, `stream` and `cert` parameters, but I thoroughly disagree that it is the responsibility of the auth provider to handle  redirects. With that said (twice), there shouldn't be a need to send the `Session` object itself.
> 
> Reply to this email directly or view it on GitHub:
> https://github.com/kennethreitz/requests/issues/1183#issuecomment-13465713


@mkomittee. Assuming that we move the call to `dispatch_hook` it would occur before being redirected. So what would happen is the following:

```
Session.send(prepared_request, **kwargs):
-> Initial Request
<- Response 401
    dispatch_hook
    -> handled authenticated request
    <- Response which gets returned to Session.send
(i.e.,
r = adapter.send(...)
r = dispatch_hook('response', request, r)
resolve_redirects
```

So after this change, if there is a 302 returned, (assuming the auth handler doesn't call `dispatch_hooks` itself) then Session's send method will handle it.