Bug 958861 - Support passing auth information without having to use HTTP Authorization header
Summary: Support passing auth information without having to use HTTP Authorization header
Keywords:
Status: CLOSED NOTABUG
Alias: None
Product: oVirt
Classification: Retired
Component: ovirt-engine-api
Version: unspecified
Hardware: Unspecified
OS: Unspecified
unspecified
unspecified
Target Milestone: ---
: ---
Assignee: Michael Pasternak
QA Contact:
URL:
Whiteboard: infra
Depends On:
Blocks: 958874
TreeView+ depends on / blocked
 
Reported: 2013-05-02 14:40 UTC by Vojtech Szocs
Modified: 2014-01-13 00:39 UTC (History)
9 users (show)

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of:
: 958874 (view as bug list)
Environment:
Last Closed: 2013-09-30 12:58:11 UTC
oVirt Team: ---
Embargoed:


Attachments (Terms of Use)

Description Vojtech Szocs 2013-05-02 14:40:06 UTC
The purpose of this RFE is to improve REST API integration in web applications (running JavaScript in web browser).

Unlike traditional HTTP clients, web applications don't have full control over HTTP request/response processing. Instead, the web browser is the "proxy" between JavaScript trying to send/receive requests, and the actual web server that serves these requests. Web browsers typically implement some standard conventions and behaviors on top of request/response processing, one of them is HTTP Authorization header behavior described below.

Since REST API expects (HTTP Basic) auth information to be passed using HTTP Authorization header, web application trying to integrate with REST API must set this header. However, after setting HTTP Authorization header by web application (i.e. via XmlHttpRequest) for the first request, the browser *remembers* this header and always sends it for subsequent requests, until the browser window is closed. Because of this, implementing logout functionality in web application is really hard when using HTTP Authorization header.

Furthermore, web application cannot take advantage of REST API session mechanism [http://wiki.ovirt.org/Features/RESTSessionManagement] because this mechanism expects HTTP Authorization header to be sent by client only for the *first* (create session) request, which is impossible due to browser-specific HTTP Authorization header handling as mentioned above.

To summarize, web application doesn't have full control over HTTP Authorization header, so REST API should provide some alternative to pass auth information.

Proposed solution:
Client (web application) can use "Prefer: custom-auth-header" to indicate preference of using custom HTTP header instead of standard HTTP Authorization header.

For example:

    GET /api HTTP/1.1
    Host: ovirt-engine
    Prefer: custom-auth-header
    Custom-Authorization: xxx

Example that works with REST API session mechanism (create session):

    GET /api HTTP/1.1
    Host: ovirt-engine
    Prefer: persistent-auth,custom-auth-header
    Custom-Authorization: xxx

Comment 1 Einav Cohen 2013-05-02 15:10:27 UTC
adding reference to the first e-mail in the related engine-devel thread:
http://lists.ovirt.org/pipermail/engine-devel/2013-April/004235.html

Comment 2 Vojtech Szocs 2013-05-14 14:21:18 UTC
@Michael: is there some RFE/document for your "URI based authentication" proposal?

Assuming user credentials (also possibly JSESSIONID value) could be passed via URI, we could use this as a workaround to avoid dealing with HTTP 'Authorization' header entirely (also possibly to avoid dealing with cookies entirely).

In other words, with "URI based authentication" implemented, we could just skip the 'Custom-Authorization' header entirely (originally proposed for this RFE).

Comment 3 Michael Pasternak 2013-09-15 13:36:41 UTC
AFAICS, fixing Bug 1007444 solves the issue mentioned here?!, i.e


all you need for session re-initation take place (when old session is expires),
is to keep authorization header in request (what is happens anyway in browsers),
i.e existence of the authorization header in request, does not turn off
session based authentication any more.


[1] https://bugzilla.redhat.com/show_bug.cgi?id=1007444#c1

Comment 4 Vojtech Szocs 2013-09-26 12:23:47 UTC
This is great news, thanks Michael!

If I understand correctly, when client sends request like this:

  Pass "Authorization" header
  Pass "Prefer:persistent-auth" header
  Pass "Cookie" header with JSESSIONID

Then it should behave like this:

  * if JSESSIONID maps to live (active) session, i.e. `SessionUtils.getCurrentSession(false) != null`, this session won't be re-created (JSESSIONID value stays the same!) but just validated during request processing
  * if JSESSIONID maps to dead (inactive) session, i.e. `SessionUtils.getCurrentSession(false) == null`, new session will be re-created during request processing

If I read patch [http://gerrit.ovirt.org/#/c/19244/] correctly, "Prefer:persistent-auth" header must be specified in order to attempt to re-use (validate) existing session. This makes much more sense than condition `... && !hasAuthorizationHeader` in Challenger.preProcess method. Session functionality should be tied to "Prefer:persistent-auth" header anyway, since "Authorization" header serves a conceptually different purpose and isn't really related to session functionality.

So the JavaScript client can now just send requests like shown above and extract JSESSIONID either from cookie or "JSESSIONID" response header (the JSESSIONID value might change due to re-creation of dead session) without fear of causing unintentional session re-creation (in case of live session).

Michael is right, if my understanding is correct, it would solve this BZ. Michael, can you please confirm my notes above? (thanks!)

Comment 5 Michael Pasternak 2013-09-29 10:04:14 UTC
(In reply to vszocs from comment #4)
> This is great news, thanks Michael!
> 
> If I understand correctly, when client sends request like this:
> 
>   Pass "Authorization" header
>   Pass "Prefer:persistent-auth" header
>   Pass "Cookie" header with JSESSIONID
> 
> Then it should behave like this:
> 
>   * if JSESSIONID maps to live (active) session, i.e.
> `SessionUtils.getCurrentSession(false) != null`, this session won't be
> re-created (JSESSIONID value stays the same!) but just validated during
> request processing
>   * if JSESSIONID maps to dead (inactive) session, i.e.
> `SessionUtils.getCurrentSession(false) == null`, new session will be
> re-created during request processing
> 
> If I read patch [http://gerrit.ovirt.org/#/c/19244/] correctly,
> "Prefer:persistent-auth" header must be specified in order to attempt to
> re-use (validate) existing session. This makes much more sense than
> condition `... && !hasAuthorizationHeader` in Challenger.preProcess method.
> Session functionality should be tied to "Prefer:persistent-auth" header
> anyway, since "Authorization" header serves a conceptually different purpose
> and isn't really related to session functionality.
> 
> So the JavaScript client can now just send requests like shown above and
> extract JSESSIONID either from cookie or "JSESSIONID" response header (the
> JSESSIONID value might change due to re-creation of dead session) without
> fear of causing unintentional session re-creation (in case of live session).
> 
> Michael is right, if my understanding is correct, it would solve this BZ.
> Michael, can you please confirm my notes above? (thanks!)

+1

Comment 6 Vojtech Szocs 2013-09-30 12:31:33 UTC
Thanks Michael, I think we can close this BZ now.

Auth info can still be passed via HTTP Authorization header. If the client doesn't have full control over HTTP Authorization header, it can still pass "Prefer:persistent-auth" + "Cookie" header to reuse the session (if it's still active), without fear of causing session re-creation (if the session is still active).

Comment 7 Vojtech Szocs 2013-09-30 12:46:27 UTC
As for passing JSESSIONID value from client to server alongside each request, for a JavaScript-based application running in web browser, the browser should handle the "Cookie" header automatically, as soon as "Set-Cookie" header was detected in a response from server.

So for JavaScript vs. REST API integration:

1. webapp makes initial request ("Authorization" + "Prefer:persistent-auth") and extracts JSESSIONID value from "JSESSIONID" response header (Note: cannot read cookie value due to cookie being set for different path, i.e. "/webadmin" vs. "/api")

2. webapp makes subsequent requests ("Authorization" + "Prefer:persistent-auth") and relies on browser to include "Cookie" header in each request (Note: initial response contained "Set-Cookie" header so browser will send "Cookie" header for each request from now on)

So webapp just needs to check response after each REST API call to see if there's new JSESSIONID value. If the response has "JSESSIONID" header, webapp will use this value if it needs to pass session ID to other systems.


Note You need to log in before you can comment on or make changes to this bug.