-
-
Notifications
You must be signed in to change notification settings - Fork 243
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
make webui work with non-root context path #1305
base: main
Are you sure you want to change the base?
Conversation
Job #378: Bundle Size — 10.64MB (-0.53%).Changed metrics (4/10)
Changed assets by type (4/7)
|
You mean serving the index.html with a Java servlet that would replace a placeholder (because that could be an option) or what you describe afterwards?
Eh, kudos for digging that one up, actually! 😲
Why not? If it's done "cleanly" like all
The main UI stores the OAuth refresh_token in localStorage. The refresh_token is used to get access tokens which allow in turn to query protected endpoints in the API. If you were to have rogue JS that would "steal" the refresh_token from the localStorage (very easy on the same domain), then the API would be compromised. The trick is that sessions open by the main UI also set a cookie that are only valid for the root path and HttpOnly:
It's not perfect, but it makes it a little bit harder. It would be possible to set these cookies to the base path set by the X-OPENHAB-BASEPATH cookie value to make it work (there could be minor security implications).
It's still there in case we decide to resuscitate it but it doesn't work even now, so don't worry about it. |
No, actually I mean what I described before 😄: Also, the app's main js gets added by scripting now (and not injected by Webpack at build time anymore).
It's not only about
Hm, not sure I can follow here. Afaik a cookie is valid for all subpaths as well, i.e. the X-OPENHAB-SESSIONID cookie is valid for the whole domain.
You missed to respond to this. From your response I assume there's general interest in finishing this PR? |
Ok I see, not sure how I feel about this, seems like a hack tbh... normally I'd prefer avoiding these kind of things and stick the most natural way, but if it has no adverse consequences, why not.
Ah, I see. Count this as another problem with the f7 router... I suppose it was primarily designed for mobile apps.
I have no fundamental issues with pursuing this, as offering the option to serve the web UI from a subpath is often encountered in all kinds of software, though one might argue that openHAB is somewhat "special" in that it comes with an application server and multiple UIs with very different codebases (Basic UI, HABPanel...). But I don't want to stifle your efforts, just thinking about the implications, which turn out to be quite a lot 🙂 |
So, I performed some basic tests for MainUI using Firefox and Chrome, iOS 14, Android 10 and to me it seems all good. I've had a closer look at authentication and I still don't understand how auth is supposed to work. I thought it's somewhat oauth based, but then I can't see why Cause like said I'm not too deep into security, I didn't dig any deeper and just made it work with this quick hack: openhab-core auth patchdiff --git a/bundles/org.openhab.core.io.http.auth/src/main/java/org/openhab/core/io/http/auth/internal/AuthorizePageServlet.java b/bundles/org.openhab.core.io.http.auth/src/main/java/org/openhab/core/io/http/auth/internal/AuthorizePageServlet.java
index 763401792..67370da7a 100644
--- a/bundles/org.openhab.core.io.http.auth/src/main/java/org/openhab/core/io/http/auth/internal/AuthorizePageServlet.java
+++ b/bundles/org.openhab.core.io.http.auth/src/main/java/org/openhab/core/io/http/auth/internal/AuthorizePageServlet.java
@@ -136 +136 @@ public class AuthorizePageServlet extends AbstractAuthPageServlet {
- String clientId = params.get("redirect_uri")[0];
+ String clientId = params.get("client_id")[0];
@@ -143,4 +142,0 @@ public class AuthorizePageServlet extends AbstractAuthPageServlet {
- if (!clientId.equals(baseRedirectUri)) {
- throw new IllegalArgumentException("unauthorized_client");
- }
-
@@ -210 +206 @@ public class AuthorizePageServlet extends AbstractAuthPageServlet {
- responseBody = responseBody.replace("{formAction}", "/auth");
+ responseBody = responseBody.replace("{formAction}", "auth");
diff --git a/bundles/org.openhab.core.io.rest.auth/src/main/java/org/openhab/core/io/rest/auth/internal/TokenResource.java b/bundles/org.openhab.core.io.rest.auth/src/main/java/org/openhab/core/io/rest/auth/internal/TokenResource.java
index f596e8cbb..30b012b3f 100644
--- a/bundles/org.openhab.core.io.rest.auth/src/main/java/org/openhab/core/io/rest/auth/internal/TokenResource.java
+++ b/bundles/org.openhab.core.io.rest.auth/src/main/java/org/openhab/core/io/rest/auth/internal/TokenResource.java
@@ -247,2 +247,2 @@ public class TokenResource implements RESTResource {
- NewCookie newCookie = new NewCookie(SESSIONID_COOKIE_NAME, null, "/", domainUri.getHost(), null, 0,
- false, true);
+ NewCookie newCookie = new NewCookie(SESSIONID_COOKIE_NAME, null, domainUri.getPath(),
+ domainUri.getHost(), null, 0, false, true);
@@ -350,6 +350,7 @@ public class TokenResource implements RESTResource {
- if (!("".equals(domainUri.getPath()) || "/".equals(domainUri.getPath()))) {
- throw new IllegalArgumentException(
- "Will not honor the request to set a session cookie for this client, because it's only allowed for root redirect URIs");
- }
- NewCookie newCookie = new NewCookie(SESSIONID_COOKIE_NAME, sessionId, "/", domainUri.getHost(), null,
- 2147483647, false, true);
+ // if (!("".equals(domainUri.getPath()) || "/".equals(domainUri.getPath()))) {
+ // throw new IllegalArgumentException(
+ // "Will not honor the request to set a session cookie for this client,
+ // because it's only allowed for root redirect URIs");
+ // }
+ NewCookie newCookie = new NewCookie(SESSIONID_COOKIE_NAME, sessionId, domainUri.getPath(),
+ domainUri.getHost(), null, 2147483647, false, true); I also had a look at HABPanel and as it seems HABPanel/Angular 1 seems to use only a single, never changing url path (index.html) and hashes for routing. By making all urls to the core relative as in All in all I'd say this PR is finished for me regarding MainUI and HABPanel. With required auth changes made to the core, I think it could be merged. openHAB might then still not "officially" support reverse proxying, but since these changes don't break anything they would help those many tinkerers out there subpathing openHAB on their own responsibility 😉. |
Ah, forgot something: While testing I found PWA to not work. Has that actually worked before? |
Very much so. I'm open to alternatives as long as they don't hinder the ability to "add as app" PWA functionality in the default case. |
Signed-off-by: Hubert Nusser <hubsif@gmx.de>
Signed-off-by: Hubert Nusser <hubsif@gmx.de>
So, I finally found some time to check PWA. So, the two limitations left are non-working links and non-working PWA, which I think is acceptable for many users that want to "inofficially" subpath the mainUI. |
Alright, thanks for the investigations, my main priorities for acceptability of this subpath feature are:
|
To be clear - the PR looks great so far and you'll get more feedback from me when I get some time to test it properly! |
I fully agree to both. The latter actually being the reason why I didn't pursue fixing the linking issue...
Sure, take your time. |
Any update on this? I'm having to move away from Home Assistant due to this exact issue, and now I'm seeing OpenHAB doesn't support it either. |
This is based on @altaroca's work in PR #1291 (issue #1290), opening a new PR since I don't have permission to push to his/her.
Summary:
This adds the possibility to run MainUI under a subpath using a reverse proxy. For it to work, the reverse proxy needs to inject a cookie called "X-OPENHAB-BASEURL" with the subpath as its value.
Detailed explanation:
First, to simulate a reverse proxy with the Webpack devserver, apply the following patch:
With this, MainUI should be reachable (and functional 😉) at http://localhost:8080/proxypath/.
How it works in detail, is that some js in
index.html
reads the cookieX-OPENHAB-BASEURL
, stores its value in the global variablebaseUrl
and creates a<base href={baseUrl}>
tag. This is to make all the images inindex.html
work, like favicon. Also, the app's main js gets added by scripting now (and not injected by Webpack at build time anymore). This is because theapp.js
would be loaded before the base tag is added, i.e. my browser always tried to load/js/app.js
first and then{baseUrl}/js/app.js
(which seems weird to me because it doesn't happen with the favicons etc., but it's just like that 🤷♂️). Sourcing the main js dynamically cleans that up.When the app is loaded, the first thing it does is to assign the base url to the global variable
__webpack_public_path__
. This feature from Webpack is basically the main key and makes the application run under the base url, i.e. makes the app load all assets from underneath the base url. This assignment is exported to an extra file, because otherwise it wouldn't work properly with fonts (for some unknown reason. Felt like it to me hours to find this!).Then for the Framework7 router and pushState to work properly with this, the base url gets assigned to
pushStateRoot
on load.To fix communication with the openHAB API, all "static" urls are prepended by the base url. The same goes for the few manual "redirects" that set
window.location
.That's basically it.
Limitations:
Due to the following open issues, until fixed, this PR can be considered as POC.
This is the main limitation, I think: If run under a subpath, "links" don't work anymore again. This seems to be a limitation from the design of the Framework7 router, which does make it possible to add the base url to links/routes (actually it might work if
baseUrl
is prepended to all router paths in the app, but that seems a little "undesirable" to me). Still, I think there might be quite some users that would drop this for being able to run MainUI subpathed.(edit) addition: the url in the browser's adress bar shows correctly, so creating links or bookmarks from there works just fine. It's just the tabbed browsing ("right-click-open-in-new-tab") that doesn't work.
this PR does not fix any issues with other UIs (yet), which are definitely present, e.g. in HABPanel
Authentication does not yet work with this. Though, to make it work only some slight changes in the core are required IMHO. Actually, the main limitation is within the core limiting redirects to a root url only. I actually don't quite understand why this is present, IMHO it's not required (but then I'm not a security expert). Also, the auth site from the core would need to redirect relatively (basically just change
/auth
toauth
here).Side notes
In this PR I've touched a few additional things:
res/
toimages/
cometvisu.png
, so I removed itLike said before, this PR is a POC. It doesn't yet touch the other UIs and it still needs a lot of testing on different clients (browsers, platforms i.e. iOS, ...) (BTW: @ghys is cordova actually being used and tested or can it be dropped?).
But before proceeding fixing open issues, with the above noted, I'd like to get feedback if this is something you'd actually like to go with and if there are maybe other limitations that could be showstoppers and need to be looked into first.