Skip to content

Commit

Permalink
Merge branch 'Open-EO:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
m-mohr authored Oct 16, 2024
2 parents 5b202e0 + 00fc917 commit 91fd51d
Show file tree
Hide file tree
Showing 55 changed files with 2,205 additions and 906 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Example: <https://editor.openeo.org?server=https://earthengine.openeo.org&discov
Here we collection information for back-end implementors that want to improve the experience with the Web Editor by fine-tuning their implementation.

* [GeoTiff / COG support](docs/geotiff.md)
* [OIDC setup](docs/oidc.md)
* and more...

## Contributions
Expand Down
9 changes: 7 additions & 2 deletions config.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default {
mapZoom: 4,

// OSM Nominatim compliant geocoder URL, remove to disable
geocoder: "https://nominatim.openstreetmap.org/search/",
geocoder: "https://nominatim.openstreetmap.org/search",

// A message shown on the login page
loginMessage: '',
Expand Down Expand Up @@ -55,6 +55,7 @@ export default {

// List of supported web service sharing services
supportedWebServiceSharingServices: [
'ShareEditor',
'CopyUrl',
'TwitterShare'
],
Expand Down Expand Up @@ -117,6 +118,10 @@ export default {

// refresh interval for jobs/user data/services etc. in minutes - doesn't apply to logs.
// It's recommended to use a value between 1 and 5 minutes.
dataRefreshInterval: 2
dataRefreshInterval: 2,

// Show or hide experimental and/or deprecated entites by default (e.g. processes, collections)
showExperimentalByDefault: false,
showDeprecatedByDefault: false,

};
8 changes: 4 additions & 4 deletions docs/geotiff.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ What is required by back-ends to give users an ideal experience with GeoTiff ima
5. The [`PhotometricInterpretation`](https://www.awaresystems.be/imaging/tiff/tifftags/photometricinterpretation.html) of the image should be set to `1` (BlackIsZero) if an RGB interpretation is not clear. If RGB is set as interpretation (`2`) and you have more than 3 samples per pixel ([`SamplesPerPixel`](https://www.awaresystems.be/imaging/tiff/tifftags/samplesperpixel.html)), the [`ExtraSamples`](https://www.awaresystems.be/imaging/tiff/tifftags/extrasamples.html) should be set.
6. [`ColorMap`](https://www.awaresystems.be/imaging/tiff/tifftags/colormap.html)s are supported.
7. For batch jobs, the STAC metadata is recommended to contain per asset:
1. The no-data value either in `file:nodata` (deprecated) or in `nodata` in `raster:bands`
2. The `minimum` and `maximum` values per band in the `statistics` object in `raster:bands`
3. A band `name` either in `raster:bands` (unspecified) or `eo:bands`
4. The projection in `proj:epsg` (recommended), `proj:wkt2` (not well suported by OpenLayers) or `proj:proj4` (deprecated by STAC)
1. The no-data value either in `file:nodata` (deprecated) or in `nodata` in `bands`
2. The `minimum` and `maximum` values per band in the `statistics` object in `bands`
3. A band `name` in `bands`
4. The projection in `proj:code` (recommended), `proj:wkt2` (not well suported by OpenLayers) or `proj:proj4` (deprecated by STAC)
5. The `type` must be set to the corresponding media type (see below)
8. For synchronous execution, the `Content-Type` in the header of the response must be set to the corresponding media type (see below)

Expand Down
72 changes: 72 additions & 0 deletions docs/oidc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# OIDC setup guidelines for usage with the Web Editor

The standard authentication mechanism in openEO is OpenID Connect (OIDC).
The openEO Web Editor, being a standard web application, uses the corresponding OIDC flows such as the
[Authorization Code Flow](https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth)
to authenticate the user.

To provide an optimal OIDC authentication user experience in the openEO Web Editor,
it is important for an openEO back-end to properly set up a couple of things:

- Determine what **OIDC provider(s)** to support.
One can choose from existing OIDC provider services,
or set up their own custom OIDC provider,
(e.g. using [Keycloak](https://www.keycloak.org/)).

- For at least one (and preferably all) of the supported OIDC providers:
create an OIDC client that can be used as the **default OIDC client**
by users that do not manage their own OIDC client.

How this OIDC client has to be configured practically,
heavily depends on the OIDC provider,
but here are some general guidelines and constraints
for the OIDC client configuration:

- (At least) support the **Authorization Code Flow** without client secrets
(which is sometimes labeled as a "public client").
Support for PKCE (Proof Key for Code Exchange) is recommended.

- **Allow-list the proper redirect URIs** related to your openEO Web Editor deployment.

For example, if you host the web editor at `https://editor.openeo.example.org/`,
you should allow the redirect URI `https://editor.openeo.example.org`.

Note that the redirect URIs should be allow-listed *without trailing slashes*.

Make sure to cover all possible Web Editor domains you want to support with the client.
For example, consider allow-listing:
- `http://localhost:8080` for local development of the web editor
- `https://editor.openeo.org` so that your back-end can be used with the official openEO Web Editor.

- **Allow-list the proper origins** of your openEO Web Editor deployment.
(In Keycloak based providers, this setting is typically called "Web Origins".)
This ensures that the OIDC provider sets the proper **CORS headers**
so that the openEO Web Editor web app can access the tokens after authentication.
In the rare case that you host the web editor and the OIDC provider on the same domain,
you probably don't have to allow-list any origins.

For example, if you host the web editor at `https://openeo.example.org/editor`,
you should allow the origin `https://openeo.example.org`.

Note that an origin by definition is only scheme + domain and optionally a port.
Don't include a path (like `/editor` in the example above),
not even a trailing slash.

As with the redirect URIs, consider including:
- `http://localhost:8080`
- `https://editor.openeo.org`

- Handle the `GET /credentials/oidc` endpoint in your openEO back-end,
based on the OIDC providers and OIDC clients discussed above.

Apart from the full details discussed
in the [`GET /credentials/oidc` specification](https://api.openeo.org/#tag/Account-Management/operation/authenticate-oidc)
consider these additional notes on the `default_clients` items:

- Include the appropriate grant type under the `grant_types` field:
- `authorization_code` for the Authorization Code Flow
- `authorization_code+pkce` for the Authorization Code Flow with PKCE
- `implicit` for the Implicit Flow (**discouraged**)
- List the same redirect URIs discussed above again under the `redirect_urls` field.
This listing allows the openEO Web Editor to hide authentication options
that won't work because redirect URIs configuration.
24 changes: 15 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@openeo/web-editor",
"version": "0.12.5",
"version": "0.14.0-beta.2",
"apiVersions": [
"1.0.0-rc.2",
"1.0.0",
Expand Down Expand Up @@ -36,6 +36,10 @@
"type": "git",
"url": "https://github.com/Open-EO/openeo-web-editor.git"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/m-mohr"
},
"scripts": {
"build:database": "node src/build-database.js",
"start": "npm run build:database && npx vue-cli-service serve",
Expand All @@ -44,23 +48,25 @@
"dependencies": {
"@kirtandesai/ol-geocoder": "^5.0.6",
"@musement/iso-duration": "^1.0.0",
"@openeo/js-client": "^2.5.1",
"@openeo/js-commons": "^1.4.1",
"@openeo/js-processgraphs": "^1.3.0",
"@openeo/vue-components": "^2.14.0",
"@openeo/js-client": "^2.6.0",
"@openeo/js-commons": "^1.5.0",
"@openeo/js-processgraphs": "^1.4.1",
"@openeo/vue-components": "^2.17.0",
"@radiantearth/stac-fields": "^1.5.0-beta.2",
"@radiantearth/stac-migrate": "^2.0.0-beta.1",
"@tmcw/togeojson": "^5.5.0",
"ajv": "^6.12.6",
"axios": "^0.24.0",
"axios": "^1.0.0",
"chart.js": "^3.7.1",
"chartjs-adapter-luxon": "^1.1.0",
"codemirror": "^5.58.2",
"content-type": "^1.0.4",
"core-js": "^3.7.0",
"jsonlint-mod": "^1.7.6",
"luxon": "^2.4.0",
"node-polyfill-webpack-plugin": "^2.0.0",
"ol": "^7.2.2",
"ol-ext": "^4.0.4",
"node-polyfill-webpack-plugin": "^4.0.0",
"ol": "^9.2.0",
"ol-ext": "^4.0.21",
"proj4": "^2.7.5",
"splitpanes": "^2.3.6",
"v-clipboard": "^2.2.3",
Expand Down
6 changes: 5 additions & 1 deletion src/Page.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import EventBusMixin from './components/EventBusMixin.js';
import Utils from './utils';
import ConnectForm from './components/ConnectForm.vue';
import axios from 'axios';
import AddMapDataModal from './components/modals/AddMapDataModal.vue';
// Making axios available globally for the OpenEO JS client
window.axios = axios;
Expand All @@ -30,6 +31,7 @@ export default {
components: {
ConnectForm,
IDE: () => import('./components/IDE.vue'),
AddMapDataModal: () => import('./components/modals/AddMapDataModal.vue'),
CollectionModal: () => import('./components/modals/CollectionModal.vue'),
DataModal: () => import('./components/modals/DataModal.vue'),
DownloadAssetsModal: () => import('./components/modals/DownloadAssetsModal.vue'),
Expand Down Expand Up @@ -70,10 +72,12 @@ export default {
});
this.setCollectionPreview(Utils.param('preview-collection'));
let resultUrl = Utils.param('result');
const resultUrl = Utils.param('result');
const resultType = Utils.param('result-type') || 'job';
if (resultUrl) {
this.setAppMode({
resultUrl,
resultType,
...Utils.paramsForPrefix('app')
});
}
Expand Down
37 changes: 23 additions & 14 deletions src/components/ConnectForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -123,15 +123,8 @@ export default {
...Utils.mapState(['connectionError', 'authProviders', 'isAuthenticated']),
...Utils.mapGetters(['isConnected', 'isDiscovered', 'title']),
...Utils.mapState('editor', ['storedServers']),
isLocal() {
return Boolean(
window.location.hostname === 'localhost' ||
window.location.hostname === '[::1]' ||
window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/)
);
},
httpsUrl() {
if (this.$config.showHttpWarning && !this.isLocal && window.location.protocol === 'http:') {
if (this.$config.showHttpWarning && !this.isLocalUrl(window.location) && window.location.protocol === 'http:') {
return window.location.toString()
.replace(/^http:/i, 'https:')
.replace(/([\?&]server=http)(:|%3A)/, '$1s$2');
Expand Down Expand Up @@ -244,6 +237,14 @@ export default {
...Utils.mapMutations(['reset']),
...Utils.mapMutations('editor', ['addServer', 'removeServer']),
isLocalUrl(url) {
return Boolean(
url.hostname === 'localhost' ||
url.hostname === '[::1]' ||
url.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/)
);
},
showHelp() {
if (!this.isConnected) {
this.broadcast('showTour', 'connect');
Expand Down Expand Up @@ -314,11 +315,14 @@ export default {
if (!serverUrl.match(/^https?:\/\//i)) {
serverUrl = `https://${serverUrl}`;
}
if (!Utils.isUrl(serverUrl)) {
Utils.error(this, 'The server given is not a valid URL.');
return;
}
else if (window.location.protocol === 'https:' && serverUrl.toLowerCase().substr(0,6) !== 'https:') {
const url = new URL(serverUrl);
if (window.location.protocol === 'https:' && url.protocol !== 'https:' && !this.isLocalUrl(url)) {
Utils.error(this, 'You are trying to connect to a server with HTTP instead of HTTPS, which is insecure and prohibited by web browsers. Please use HTTPS instead.');
return;
}
Expand Down Expand Up @@ -355,10 +359,15 @@ export default {
await provider.login(this.username, this.password);
}
else if (authType === 'oidc') {
let offlineScope = true;
if (this.oidcClientId) {
this.provider.setClientId(this.oidcClientId);
}
await provider.login(this.oidcOptions, true);
else {
const client = provider.detectDefaultClient();
offlineScope = client && Array.isArray(client.grant_types) && client.grant_types.includes('refresh_token');
}
await provider.login(this.oidcOptions, offlineScope);
provider.addListener('AccessTokenExpired', () => Utils.warn(this, "User session has expired, please login again."));
provider.addListener('SilentRenewError', () => Utils.error(this, "You'll be switching to Guest mode in less than a minute.", "Session renewal failed"));
}
Expand Down Expand Up @@ -423,20 +432,20 @@ export default {
showServerSelector() {
this.broadcast(
'showListModal',
"showListModal",
"Select previously used server",
this.storedServers,
[
{
callback: (url) => {
callback: url => {
this.serverUrl = url;
return true; // return true to close the modal
}
},
{
callback: (url) => this.removeServer(url),
callback: url => this.removeServer(url),
icon: 'trash',
title: 'Delete entry from history'
title: 'Delete'
}
]
);
Expand Down
2 changes: 1 addition & 1 deletion src/components/CustomProcessPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export default {
);
},
addProcess(process) {
this.create({parameters: [process.id, process]})
this.create([process.id, process])
.catch(error => Utils.exception(this, error, 'Store Process Error' + (process.id ? `: ${process.id}` : '')));
},
processInfo(process) {
Expand Down
Loading

0 comments on commit 91fd51d

Please sign in to comment.