+++ This bug was initially created as a clone of Bug #958861 +++ 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
adding reference to the first e-mail in the related engine-devel thread: http://lists.ovirt.org/pipermail/engine-devel/2013-April/004235.html
BTW: I don't understand why we discussing this in downstream and not upstream (bug#958861)... Regardless of this specific RFE I would like to write that I don't like the REST API session mechanism [http://wiki.ovirt.org/Features/RESTSessionManagement] solution, as it relays on cookies and not explicit API interaction. I would have expected a 'ticket' to be retrieved and that 'ticket' to be disconnected from the application server objects. Although we can refer the 'cookie' as a ticket, however the requirement to parse it should not be required, there be a conflict between two separate applications running on same server, and there may be a problem to transfer credentials between servers. If we modify authentication we should support more authentication types, at least SPNEGO. In order to allow SPNEGO and other authentication mechanisms, we better force people to use single URI to perform the login and return authenticated 'ticket' to continue interaction with application. This will be much simpler implementation at the api side and much more efficient, and as we are discussion application-to-application interaction there should be no user experience visible issues. What I recommend is purely applicative rest login command... --- Input: authentication type, authentication credentials authentication=http authentication=password credentials: user=user password=password [OPTIONALLY] HTTP authentication headers Output: ticket ticket issue time (required to avoid clock sync) ticket expiration time Logic: if authentication is http, use http authentication headers to establish user authentication. This will allow future SSO. if authentication is password, use embedded credentials. --- For every other rest call add http header: oVirt-Authentication-Ticket: <ticket> The backend side will attach the correct security context to the action if the header is received. No need for the prefer mechanism nor multiple authentications. It should be easy for javascript implementation to perform the authentication via the designated URI, and then pass the ticket if not expired, when expired to perform re-authentication with or without involving the user.
this is doesn't have to be discussed at Bugzilla at all, here [1] is a upstream thread. [1] http://lists.ovirt.org/pipermail/engine-devel/2013-May/004489.html
what will happen when we want to add things like kerberos authentication?
Vojtech, You should be able accessing /api session cookie via "Cross-Origin Resource Sharing", from the javascript, please review spec [1] for this, are there any other restrictions besides this one? (assume omit of the auth. header can be easily solved) [1] http://www.w3.org/TR/cors/
(In reply to Michael Pasternak from comment #5) > Vojtech, > > You should be able accessing /api session cookie via "Cross-Origin Resource > Sharing", from the javascript, please review spec [1] for this, > > are there any other restrictions besides this one? > (assume omit of the auth. header can be easily solved) > > [1] http://www.w3.org/TR/cors/ Yes, CORS is indeed an option here, however I'm not sure if JBoss AS7 supports CORS spec [2]. In general, CORS implies that both browser and server support the spec. In addition, CORS is about sharing resources between different origins - in our case, WebAdmin and REST API are both on same origin, but browser enforces "same-cookie-path" restriction anyway, I'm not sure it would solve our problem, but it's worth a try. Another approach is to simply introduce another (custom, non-Cookie) header and instruct AS7 to recognize this header, in addition to recognizing JSESSIONID cookie. Doing this by customizing bundled Tomcat's Manager seems to be quite problematic in AS7 [3]. However, [4] shows that if we somehow get a reference to default Manager, we can do "createSession(sessionId)" via some custom filter, unless I miss something. [2] https://github.com/wildfly/wildfly/pull/4349 [3] https://community.jboss.org/thread/220840 [4] http://tomcat.apache.org/tomcat-6.0-doc/api/org/apache/catalina/Manager.html
(In reply to Itamar Heim from comment #4) > what will happen when we want to add things like kerberos authentication? In that case we'll have to revisit current auth strategy (HTTP Basic Auth) and extend/modify it to support Kerberos auth.
(In reply to vszocs from comment #6) ... > Another approach is to simply introduce another (custom, non-Cookie) header > and instruct AS7 to recognize this header, in addition to recognizing > JSESSIONID cookie. Doing this by customizing bundled Tomcat's Manager seems > to be quite problematic in AS7 [3]. However, [4] shows that if we somehow > get a reference to default Manager, we can do "createSession(sessionId)" via > some custom filter, unless I miss something. > another approach is with the revamping of the URI's, to also map /api under /webadmin/api, so you won't have an issue with same-path policy issues.
(In reply to Itamar Heim from comment #9) > another approach is with the revamping of the URI's, to also map /api under > /webadmin/api, so you won't have an issue with same-path policy issues. Good idea, this is definitely worth a try, but we have to make sure that: - /webadmin/api properly redirects to /api - REST API sets its cookie according to current request path, i.e. /webadmin/api I'd suggest to start with this one, putting this on my task list since /webadmin/* means GWT/Frontend part.
since api has relative uri's, API may need to be adjusted to return entities based on relative URIs as well (not that code writers necessarily write their code correctly and probably make some assumptions on the URLs). (while at it, reminder that part of the URI change is about making webadmin also relocateable to be under /ovirt-engine or something like that)
(In reply to Itamar Heim from comment #11) > since api has relative uri's, API may need to be adjusted to return entities > based on relative URIs as well (not that code writers necessarily write > their code correctly and probably make some assumptions on the URLs). > > (while at it, reminder that part of the URI change is about making webadmin > also relocateable to be under /ovirt-engine or something like that) In general, web application code shouldn't rely on (or make any assumptions of) specific value of its own context root, i.e. /api For example, if we decide to change context root of REST API from /api to /foo then REST API itself should still work properly at /foo. Of course, we'd still have to modify code that uses REST API to reflect new context root.
I believe that the REST API application doesn't rely or makes assumptions about the value of the context root. If you deploy it to /foo it will start to generate paths starting with /foo, as it should. The problem is that if you redirect requests from /api to /webadmin/api (with the application server or with the web server, doesn't matter) the application will still, rightfully, generate paths starting with /api instead of /webadmin/api, because the application doesn't have any knowledge that the requests are being re-directed. If we want to support these re-directions then we need to modify the application so that it takes the /webadmin/api (or /foo, or whatever) from some place other than the request itself, we will probably need to put some logic in the configuration of the application server (or a valve in the application server) that in addition to re-direct adds a header to indicate what was the path of the original request. The REST API application will need then to generate paths from this header if available, or from the context path where the application is deployed if the header isn't provided.
Thanks Juan, I agree that with redirects, REST API should contain logic to adjust resource paths accordingly. [Our original motivation was to do /webadmin/api -> /api redirect in order for REST API's JSESSIONID cookie to be set for path=/webadmin/api which is readable by WebAdmin/JavaScript code, unlike path=/api] It would be great if a custom header containing original request path would be added automatically via JBoss or Apache as part of the redirect. REST API could pick up this header and adjust resource paths accordingly, but more importantly, adjust JSESSIONID cookie path according to this header.
The XHR behavior you observed looks like a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=654348 Have you tested various browser combinations?
See discussion "[REST-API] Support passing auth information without having to use HTTP Authorization header #958874"[1] [1] http://comments.gmane.org/gmane.comp.emulators.ovirt.engine.devel/4028
*** This bug has been marked as a duplicate of bug 1009843 ***
fixing Bug 1007444 eliminated the need in this type of authentication, for more details see [1]. [1] https://bugzilla.redhat.com/show_bug.cgi?id=958861#c3