Skip to content

Commit

Permalink
WebService route overhaul and deployment folder restructure:
Browse files Browse the repository at this point in the history
# app name is now primary part of URL http://server/manager (realm only supported on API endpoint calls) console and static routes left in place to prevent breaking existing apps
# Manager app now requires URL picker or support for realm somewhere else in the URL
# Deployment folder now structured as app,ui,
# Manager app now expected in deployment app folder
# Moved consoles/apps from bower to NPM/Yarn (polymer 2.x npm packages are crappy so horrible temp hack in ManagerWebService to rewrite an import request URL)
  • Loading branch information
richturner committed Nov 23, 2018
1 parent 363dcff commit 4861eb9
Show file tree
Hide file tree
Showing 59 changed files with 560 additions and 383 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
import java.util.logging.Logger;
import java.util.regex.Pattern;

import static org.openremote.container.web.WebService.JSAPI_PATH;
import static org.openremote.container.web.WebService.pathStartsWithHandler;
import static org.openremote.model.Constants.PROTOCOL_NAMESPACE;

/**
Expand Down Expand Up @@ -115,7 +115,7 @@ public abstract class AbstractHttpServerProtocol extends AbstractProtocol {
*/
public static final Pattern PATH_REGEX = Pattern.compile("^[\\w/_]+$", Pattern.CASE_INSENSITIVE);


public static final String JSAPI_PATH = "/jsapi";
public static final String DEFAULT_ALLOWED_METHODS = "OPTIONS, GET, POST, DELETE, PUT, PATCH";
public static final String DEFAULT_DEPLOYMENT_NAME_FORMAT = "HttpServer %1$s Deployment %2$d";
private static final Logger LOG = Logger.getLogger(AbstractHttpServerProtocol.class.getName());
Expand All @@ -126,7 +126,7 @@ public abstract class AbstractHttpServerProtocol extends AbstractProtocol {
protected static AlreadyGzippedWriterInterceptor alreadtGzippedWriterInterceptor;
protected static ClientErrorExceptionHandler clientErrorExceptionHandler;
protected static WebServiceExceptions.ServletUndertowExceptionHandler undertowExceptionHandler;
protected static final Map<AttributeRef, List<Pair<DeploymentInfo, HttpHandler>>> deployments = new HashMap<>();
protected static final Map<AttributeRef, List<Pair<DeploymentInfo, WebService.RequestHandler>>> deployments = new HashMap<>();
protected int deploymentCounter = 0;
protected Container container;
protected boolean devMode;
Expand Down Expand Up @@ -382,23 +382,24 @@ protected void deploy(DeploymentInfo deploymentInfo, AssetAttribute protocolConf

try {
httpHandler = manager.start();
WebService.RequestHandler requestHandler = pathStartsWithHandler(deploymentInfo.getDeploymentName(), deploymentInfo.getContextPath(), httpHandler);
List<Pair<DeploymentInfo, WebService.RequestHandler>> deploymentList = deployments.getOrDefault(protocolConfiguration.getReferenceOrThrow(), new ArrayList<>());

List<Pair<DeploymentInfo, HttpHandler>> deploymentList = deployments.getOrDefault(protocolConfiguration.getReferenceOrThrow(), new ArrayList<>());
deploymentList.add(new Pair<>(deploymentInfo, httpHandler));
deploymentList.add(new Pair<>(deploymentInfo, requestHandler));
deployments.put(protocolConfiguration.getReferenceOrThrow(), deploymentList);

LOG.info("Registering HTTP Server Protocol request handler '"
+ this.getClass().getSimpleName()
+ "' for request path: "
+ deploymentInfo.getContextPath());
webService.getRequestPathHandler().addPrefixPath(deploymentInfo.getContextPath(), httpHandler);
webService.getRequestHandlers().add(requestHandler);
} catch (ServletException e) {
LOG.severe("Failed to deploy deployment: " + deploymentInfo.getDeploymentName());
}
}

protected void undeploy(AssetAttribute protocolConfiguration) {
for (Pair<DeploymentInfo, HttpHandler> deploymentInfoHttpHandlerPair : deployments.get(protocolConfiguration.getReferenceOrThrow())) {
for (Pair<DeploymentInfo, WebService.RequestHandler> deploymentInfoHttpHandlerPair : deployments.get(protocolConfiguration.getReferenceOrThrow())) {
if (deploymentInfoHttpHandlerPair == null) {
LOG.info("Deployment doesn't exist for protocol configuration: " + protocolConfiguration);
return;
Expand All @@ -411,7 +412,7 @@ protected void undeploy(AssetAttribute protocolConfiguration) {
+ this.getClass().getSimpleName()
+ "' for request path: "
+ deploymentInfo.getContextPath());
webService.getRequestPathHandler().removePrefixPath(deploymentInfo.getContextPath());
webService.getRequestHandlers().remove(deploymentInfoHttpHandlerPair.value);
DeploymentManager manager = Servlets.defaultContainer().getDeployment(deploymentInfo.getDeploymentName());
manager.stop();
manager.undeploy();
Expand Down
4 changes: 2 additions & 2 deletions client/src/main/webapp/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
<link rel="icon" type="image/png" href="/static/img/favicon.png"/>

<script src="/static/bower_components/webcomponentsjs/webcomponents-lite.js"></script>
<script src="/static/node_modules/@webcomponents/webcomponentsjs/webcomponents-lite.js"></script>

<link rel="import" href="/static/src/or-app/or-app.html">
<link rel="import" href="/static/src/manager/or-manager-console-apps/or-manager-console-apps-view.html">
Expand All @@ -22,7 +22,7 @@
app.load.css("/static/3rdparty/mapbox-gl-js/0.42.2/mapbox-gl.css"),
app.load.js("/static/3rdparty/mapbox-gl-js/0.42.2/mapbox-gl.js"),

app.load.js("/static/bower_components/chart.js/dist/Chart.js"),
app.load.js("/static/node_modules/chart.js/dist/Chart.js"),

app.load.js("/static/3rdparty/sprintf/1.0.3/sprintf.min.js")
]).then(() => {
Expand Down
6 changes: 3 additions & 3 deletions client/src/main/webapp/js/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ window.startKeycloakAuthentication = function (realm, successCallback, failureCa

window.startBasicAuthentication = function (realm, successCallback, failureCallback, errorCallback) {
Promise.all([
load.js("/static/bower_components/webcomponentsjs/webcomponents-lite.min.js"),
load.import("/static/bower_components/iron-flex-layout/iron-flex-layout-classes.html"),
load.css("/static/bower_components/font-awesome/css/font-awesome.css"),
load.js("/static/node_modules/webcomponentsjs/webcomponents-lite.min.js"),
load.import("/static/node_modules/@polymer/iron-flex-layout/iron-flex-layout-classes.html"),
load.css("/static/node_modules/font-awesome/css/font-awesome.css"),

load.import("/static/css/style.html"),
load.import("/static/css/theme.html")
Expand Down
27 changes: 15 additions & 12 deletions client/src/main/webapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,29 @@
"name": "manager",
"version": "3.0.0",
"homepage": "http://openremote.com/",
"authors": [
"OpenRemote Inc. <support@openremote.io>"
],
"author": "OpenRemote",
"description": "OR Manager",
"main": "index.html",
"license": "APGLv3",
"license": "AGPL-3.0-or-later",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"polymer": "Polymer/polymer#^2.5.0",
"iron-flex-layout": "^2.0.3",
"app-localize-behavior": "PolymerElements/app-localize-behavior#^2.0.1",
"app-route": "PolymerElements/app-route#^2.0.3",
"moment": "moment#^2.20.1",
"intl": "intl#^1.2.5",
"@polymer/polymer": "^2.6.1",
"@webcomponents/webcomponentsjs": "^1.1.0",
"@polymer/iron-flex-layout": "^1.3.1-pre.3",
"@polymer/app-localize-behavior": "^0.10.1-pre.3",
"@polymer/app-route": "^0.9.3-pre.3",
"@webcomponents/shadycss": "^1.1.1",
"font-awesome": "^4.7.0",
"moment": "^2.20.1",
"intl": "^1.2.5",
"chart.js": "^2.7.0"
},
"resolutions": {
"@polymer/polymer": "^2.6.1",
"@polymer/promise-polyfill": "^1.0.1-pre.3"
}
}
16 changes: 8 additions & 8 deletions client/src/main/webapp/src/or-app/or-app-security.html
Original file line number Diff line number Diff line change
Expand Up @@ -183,15 +183,15 @@
ready() {
super.ready();

// If login is required, and we don't have a realm, get it from the URL path
if (this.login && !this.realm) {
if (!window.location.pathname || window.location.pathname.length <= 1) {
this.set("error", "No tenant realm configured and URL doesn't have any path elements");
return;
}
let realm = window.location.pathname.split('/')[1];
console.log("No tenant realm configured, using first URL path segment: " + realm);
this.set("realm", realm);
// TODO: Need a realm picker but for now hardcode to master
// if (!window.location.pathname || window.location.pathname.length <= 1) {
// this.set("error", "No tenant realm configured and URL doesn't have any path elements");
// return;
// }
// let realm = window.location.pathname.split('/')[1];
// console.log("No tenant realm configured, using first URL path segment: " + realm);
this.set("realm", "master");
}
}

Expand Down
4 changes: 2 additions & 2 deletions client/src/main/webapp/src/or-app/or-app.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<link rel="import" href="or-style.html">

<!-- App services/dependencies -->
<link rel="import" href="../../bower_components/iron-location/iron-query-params.html">
<link rel="import" href="../../node_modules/@polymer/iron-location/iron-query-params.html">
<link rel="import" href="or-busy-indicator.html">
<link rel="import" href="or-error-view.html">
<link rel="import" href="or-console.html">
Expand Down Expand Up @@ -437,7 +437,7 @@
}
);

requests.configure(this.hostConfiguration.protocol + "//" + this.hostConfiguration.host + "/" + this.tenantRealm);
requests.configure(this.hostConfiguration.protocol + "//" + this.hostConfiguration.host + "/api/" + this.tenantRealm);

this.set("requests", requests);
this.$.console.set("reguests", requests);
Expand Down
10 changes: 5 additions & 5 deletions client/src/main/webapp/src/or-app/or-component.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@
<script src="/static/3rdparty/sprintf/1.0.3/sprintf.min.js"></script>

<!-- Moment.js because we need a proper time/date API -->
<script src="/static/bower_components/moment/moment.js"></script>
<script src="/static/node_modules/moment/moment.js"></script>

<!-- URL/page routing -->
<link rel="import" href="/static/bower_components/app-route/app-location.html">
<link rel="import" href="/static/node_modules/@polymer/app-route/app-location.html">

<!-- Intl polyfill -->
<script src="/static/bower_components/intl/dist/Intl.js"></script>
<script src="/static/node_modules/intl/dist/Intl.js"></script>

<!-- Intl langage TODO How can we do this dynamically? -->
<script src="/static/bower_components/intl/locale-data/jsonp/en.js"></script>
<script src="/static/node_modules/intl/locale-data/jsonp/en.js"></script>

<!-- Provides Polymer.AppLocalizeBehavior -->
<link rel="import" href="/static/bower_components/app-localize-behavior/app-localize-behavior.html">
<link rel="import" href="/static/node_modules/@polymer/app-localize-behavior/app-localize-behavior.html">

<dom-module id="or-component">
<script>
Expand Down
2 changes: 1 addition & 1 deletion client/src/main/webapp/src/or-app/or-style.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<link rel="import" href="or-theme.html">
<link rel="import" href="or-icons.html">

<link rel="import" href="../../bower_components/iron-flex-layout/iron-flex-layout-classes.html">
<link rel="import" href="../../node_modules/@polymer/iron-flex-layout/iron-flex-layout-classes.html">

<dom-module id="or-style">
<template>
Expand Down
124 changes: 124 additions & 0 deletions client/src/main/webapp/yarn.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


"@polymer/app-localize-behavior@^0.10.1-pre.3":
version "0.10.1-pre.3"
resolved "https://registry.yarnpkg.com/@polymer/app-localize-behavior/-/app-localize-behavior-0.10.1-pre.3.tgz#9856ccbf9cee66631c6f4a869d146089b14f55f8"
integrity sha1-mFbMv5zuZmMcb0qGnRRgibFPVfg=
dependencies:
"@polymer/iron-ajax" preview
"@polymer/polymer" preview
intl-messageformat "^1.0.0"

"@polymer/app-route@^0.9.3-pre.3":
version "0.9.3-pre.3"
resolved "https://registry.yarnpkg.com/@polymer/app-route/-/app-route-0.9.3-pre.3.tgz#42ec32497d30e15592ecbbb3604d40e244caef15"
integrity sha1-QuwySX0w4VWS7LuzYE1A4kTK7xU=
dependencies:
"@polymer/iron-location" preview
"@polymer/polymer" preview

"@polymer/iron-ajax@preview":
version "1.4.3-pre.3"
resolved "https://registry.yarnpkg.com/@polymer/iron-ajax/-/iron-ajax-1.4.3-pre.3.tgz#a3b31b5622ca85be6d73bb60b8902bdc1c85b08c"
integrity sha1-o7MbViLKhb5tc7tguJAr3ByFsIw=
dependencies:
"@polymer/polymer" preview
"@polymer/promise-polyfill" gloo

"@polymer/iron-flex-layout@^1.3.1-pre.3":
version "1.3.1-pre.3"
resolved "https://registry.yarnpkg.com/@polymer/iron-flex-layout/-/iron-flex-layout-1.3.1-pre.3.tgz#4545f11ff2f3817098ec128c7d62779864b3c1bc"
integrity sha1-RUXxH/LzgXCY7BKMfWJ3mGSzwbw=
dependencies:
"@polymer/polymer" preview

"@polymer/iron-location@preview":
version "0.8.11-pre.3"
resolved "https://registry.yarnpkg.com/@polymer/iron-location/-/iron-location-0.8.11-pre.3.tgz#9ab735812eb4505f9efa19b8374e71446a153a1d"
integrity sha1-mrc1gS60UF+e+hm4N05xRGoVOh0=
dependencies:
"@polymer/polymer" preview

"@polymer/polymer@^2.6.1", "@polymer/polymer@preview":
version "2.6.1"
resolved "https://registry.yarnpkg.com/@polymer/polymer/-/polymer-2.6.1.tgz#d233d0676cd634057a673fd8c2e62100d3b5a4e6"
integrity sha512-XBzaKlSZ094i8zfkOgczn08Gk4TWPLtGh3leANGIKLuzboid4totBt2RkBgHjRl8DgY6Up3+Jm+3lHz6W8QA+g==

"@polymer/promise-polyfill@^1.0.1-pre.3", "@polymer/promise-polyfill@gloo":
version "1.0.1-pre.3"
resolved "https://registry.yarnpkg.com/@polymer/promise-polyfill/-/promise-polyfill-1.0.1-pre.3.tgz#3f534df183648c78c48f93d678a7db37be7e81fb"
integrity sha1-P1NN8YNkjHjEj5PWeKfbN75+gfs=
dependencies:
"@polymer/polymer" preview

"@webcomponents/shadycss@^1.1.1":
version "1.6.0"
resolved "https://registry.yarnpkg.com/@webcomponents/shadycss/-/shadycss-1.6.0.tgz#2aeb0703983137a733bdb5c06fff125aa1f8c5c1"
integrity sha512-iURGZZU6BaiRJtGgjMn208QxPkY11QwT/VmuHNa4Yb+kJxU/WODe4C8b0LDOtnk4KJzJg50hCfwvPRAjePEzbA==

"@webcomponents/webcomponentsjs@^1.1.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@webcomponents/webcomponentsjs/-/webcomponentsjs-1.3.0.tgz#57983165d8651e742bdd14c2718f8cc6c228496e"
integrity sha512-x7x4rfXfX+xlg0Cdy752IVC8SjjOuMfjSNi1Vy7GKfWCm/MKSc42wGubngPl6/nO7w+nHM/MvfhTD/aEngA7/w==

chart.js@^2.7.0:
version "2.7.3"
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.7.3.tgz#cdb61618830bf216dc887e2f7b1b3c228b73c57e"
integrity sha512-3+7k/DbR92m6BsMUYP6M0dMsMVZpMnwkUyNSAbqolHKsbIzH2Q4LWVEHHYq7v0fmEV8whXE0DrjANulw9j2K5g==
dependencies:
chartjs-color "^2.1.0"
moment "^2.10.2"

chartjs-color-string@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/chartjs-color-string/-/chartjs-color-string-0.5.0.tgz#8d3752d8581d86687c35bfe2cb80ac5213ceb8c1"
integrity sha512-amWNvCOXlOUYxZVDSa0YOab5K/lmEhbFNKI55PWc4mlv28BDzA7zaoQTGxSBgJMHIW+hGX8YUrvw/FH4LyhwSQ==
dependencies:
color-name "^1.0.0"

chartjs-color@^2.1.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/chartjs-color/-/chartjs-color-2.2.0.tgz#84a2fb755787ed85c39dd6dd8c7b1d88429baeae"
integrity sha1-hKL7dVeH7YXDndbdjHsdiEKbrq4=
dependencies:
chartjs-color-string "^0.5.0"
color-convert "^0.5.3"

color-convert@^0.5.3:
version "0.5.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-0.5.3.tgz#bdb6c69ce660fadffe0b0007cc447e1b9f7282bd"
integrity sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=

color-name@^1.0.0:
version "1.1.4"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==

font-awesome@^4.7.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/font-awesome/-/font-awesome-4.7.0.tgz#8fa8cf0411a1a31afd07b06d2902bb9fc815a133"
integrity sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM=

intl-messageformat-parser@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-1.2.0.tgz#5906b7f953ab7470e0dc8549097b648b991892ff"
integrity sha1-WQa3+VOrdHDg3IVJCXtki5kYkv8=

intl-messageformat@^1.0.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-1.3.0.tgz#f7d926aded7a3ab19b2dc601efd54e99a4bd4eae"
integrity sha1-99kmre16OrGbLcYB79VOmaS9Tq4=
dependencies:
intl-messageformat-parser "1.2.0"

intl@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/intl/-/intl-1.2.5.tgz#82244a2190c4e419f8371f5aa34daa3420e2abde"
integrity sha1-giRKIZDE5Bn4Nx9ao02qNCDiq94=

moment@^2.10.2, moment@^2.20.1:
version "2.22.2"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66"
integrity sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@
import java.util.Deque;

import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION;
import static org.openremote.container.web.WebService.REQUEST_HEADER_REALM;
import static org.openremote.model.Constants.REQUEST_HEADER_REALM;

/**
* If a client can't set Authorization header (e.g. Javascript websocket API), use a request
* parameter. This handler grabs the parameter and sets it as a regular header. This handler
* will also grab {@link org.openremote.container.web.WebService#REQUEST_HEADER_REALM} as
* will also grab {@link org.openremote.model.Constants#REQUEST_HEADER_REALM} as
* a request parameter and set it as a regular header.
*/
public class AuthOverloadHandler implements HttpHandler {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@
import static org.openremote.container.util.MapAccess.getInteger;
import static org.openremote.container.util.MapAccess.getString;
import static org.openremote.container.web.WebClient.getTarget;
import static org.openremote.container.web.WebService.pathStartsWithHandler;
import static org.openremote.model.Constants.REQUEST_HEADER_REALM;

public abstract class KeycloakIdentityProvider implements IdentityProvider {

Expand Down Expand Up @@ -164,7 +166,7 @@ public KeycloakIdentityProvider(String clientId, UriBuilder externalServerUri, C

keycloakConfigResolver = request -> {
// The realm we authenticate against must be available as a request header
String realm = request.getHeader(WebService.REQUEST_HEADER_REALM);
String realm = request.getHeader(REQUEST_HEADER_REALM);
if (realm == null || realm.length() == 0) {
LOG.fine("No realm in request, no authentication will be attempted: " + request.getURI());
return notAuthenticatedKeycloakDeployment;
Expand Down Expand Up @@ -365,8 +367,12 @@ public KeycloakDeployment load(KeycloakRealmClient keycloakRealmClient) {
protected void enableAuthProxy(WebService webService) {
if (authProxyHandler == null)
throw new IllegalStateException("Initialize this service first");

LOG.info("Enabling auth reverse proxy (passing requests through to Keycloak) on web context: /" + KeycloakResource.KEYCLOAK_CONTEXT_PATH);
webService.getPrefixRoutes().put("/" + KeycloakResource.KEYCLOAK_CONTEXT_PATH, authProxyHandler);
webService.getRequestHandlers().add(0, pathStartsWithHandler(
"Keycloak auth proxy",
"/" + KeycloakResource.KEYCLOAK_CONTEXT_PATH,
authProxyHandler));
}

protected ClientRepresentation createClientApplication(String realm, String clientId, String appName, boolean devMode) {
Expand Down
Loading

0 comments on commit 4861eb9

Please sign in to comment.