Skip to content

Commit

Permalink
Authentication with Google Account (experimental)
Browse files Browse the repository at this point in the history
  • Loading branch information
m-mohr committed Jan 19, 2024
1 parent bb7f1f9 commit 58ebe82
Show file tree
Hide file tree
Showing 26 changed files with 262 additions and 140 deletions.
2 changes: 0 additions & 2 deletions .eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ extends:
parserOptions:
ecmaVersion: 2022
sourceType: module
globals:
ee: readonly
rules:
n/no-extraneous-import:
- error
Expand Down
21 changes: 19 additions & 2 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
"certificate": null
},
"serviceAccountCredentialsFile": "privatekey.json",
"googleProjectId": "",
"id": "openeo-earthengine-driver",
"title": "Google Earth Engine Proxy for openEO",
"description": "This is the Google Earth Engine Driver for openEO.\n\nGoogle Earth Engine is a planetary-scale platform for Earth science data & analysis. It is powered by Google's cloud infrastructure and combines a multi-petabyte catalog of satellite imagery and geospatial datasets with planetary-scale analysis capabilities. Google makes it available for scientists, researchers, and developers to detect changes, map trends, and quantify differences on the Earth's surface. Google Earth Engine is free for research, education, and nonprofit use.",
Expand All @@ -26,5 +25,23 @@
}
]
},
"otherVersions": []
"otherVersions": [],
"googleAuthClients": [
{
"id": "287740315825-ljdked58pdpehf1cnfj3sk0fd0hs6hpt.apps.googleusercontent.com",
"grant_types": [
"implicit"
],
"redirect_urls": [
"https://editor.openeo.org/",
"http://localhost/"
]
},
{
"id": "287740315825-lkccf4rge41dou7ublu13u8oln7o13nt.apps.googleusercontent.com",
"grant_types": [
"urn:ietf:params:oauth:grant-type:device_code+pkce"
]
}
]
}
33 changes: 28 additions & 5 deletions src/api/users.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ export default class UsersAPI {

beforeServerStart(server) {
server.addEndpoint('get', '/credentials/basic', this.getCredentialsBasic.bind(this));
// server.addEndpoint('get', '/credentials/oidc', this.getCredentialsOidc.bind(this));
if (this.context.googleAuthClients) {
server.addEndpoint('get', '/credentials/oidc', this.getCredentialsOidc.bind(this));
}
server.addEndpoint('get', '/me', this.getUserInfo.bind(this));

return Promise.resolve();
Expand All @@ -28,13 +30,34 @@ export default class UsersAPI {
try {
req.user = await this.storage.checkAuthToken(token);
} catch(err) {
res.send(Error.wrap(err));
res.send(Errors.wrap(err));
}
}

// getCredentialsOidc(req, res, next) {
// res.redirect('https://accounts.google.com/.well-known/openid-configuration', next);
// }
async getCredentialsOidc(req, res) {
if (!this.context.googleAuthClients) {
return res.send(501);
}

return res.send({
"providers": [
{
id: "google",
issuer: "https://accounts.google.com",
title: "Google",
description: "Login with your Google Earth Engine account.",
scopes: [
"openid",
"email",
"https://www.googleapis.com/auth/earthengine",
// "https://www.googleapis.com/auth/cloud-platform",
// "https://www.googleapis.com/auth/devstorage.full_control"
],
default_clients: this.context.googleAuthClients
}
]
});
}

async getCredentialsBasic(req, res) {
if (!req.authorization.scheme) {
Expand Down
3 changes: 1 addition & 2 deletions src/models/catalog.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@ export default class DataCatalog {
}

const storage = new Storage({
keyFile: './privatekey.json',
projectId: this.serverContext.googleProjectId
keyFile: './privatekey.json'
});
const bucket = storage.bucket('earthengine-stac');
const prefix = 'catalog/';
Expand Down
43 changes: 40 additions & 3 deletions src/models/userstore.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,9 @@ export default class UserStore {
return await this.db.insertAsync(userData);
}

async checkAuthToken(token) {
async authenticateBasic(token) {
const query = {
token: token.replace(/^basic\/\//, ''), // remove token prefix for basic
token,
validity: { $gt: Utils.getTimestamp() }
};

Expand All @@ -120,8 +120,45 @@ export default class UserStore {
reason: 'User account has been removed.'
});
}

return user;
}

async authenticateGoogle(token) {
const userData = this.emptyUser(false);
userData._id = "google-" + Utils.generateHash(8);
userData.token = token;
// Googles tokens are valid for roughly an hour, so we set it slightly lower
userData.token_valid_until = Utils.getTimestamp() + 59 * 60;
return userData;
}

async checkAuthToken(apiToken) {
const parts = apiToken.split('/', 3);
if (parts.length !== 3) {
throw new Errors.AuthenticationRequired({
reason: 'Token format invalid.'
});
}
const [type, provider, token] = parts;

if (type === 'basic') {
return this.authenticateBasic(token);
}
else if (type === 'oidc') {
if (provider === 'google') {
return this.authenticateGoogle(token);
}
else {
throw new Errors.AuthenticationRequired({
reason: 'Identity provider not supported.'
});
}
}
else {
throw new Errors.AuthenticationRequired({
reason: 'Authentication method not supported.'
});
}
}

}
3 changes: 2 additions & 1 deletion src/processes/aggregate_temporal_frequency.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,13 @@ export default class aggregate_temporal_frequency extends BaseProcess {
}

async execute(node) {
const ee = node.ee;
// STEP 1: Get parameters and set some variables
const dc = node.getDataCube('data');
const frequency = node.getArgument('frequency');

// STEP 2: prepare image collection with aggregation label
const images = Commons.setAggregationLabels(dc.imageCollection(), frequency);
const images = Commons.setAggregationLabels(node, dc.imageCollection(), frequency);

// STEP 3: aggregate based on aggregation label

Expand Down
4 changes: 2 additions & 2 deletions src/processes/anomaly.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ export default class anomaly extends BaseProcess {
async execute(node) {
const dc = node.getDataCube('data');
const normalsDataCube = node.getDataCube('normals');
const normalsLabels = ee.List(normalsDataCube.dimT().getValues());
const normalsLabels = node.ee.List(normalsDataCube.dimT().getValues());
const normalsCollection = normalsDataCube.imageCollection();
const normals = normalsCollection.toList(normalsCollection.size());
const frequency = node.getArgument('frequency');

let images = Commons.setAggregationLabels(dc.imageCollection(), frequency);
let images = Commons.setAggregationLabels(node, dc.imageCollection(), frequency);
images = images.map(image => {
const label = image.get('label');
const normal = normals.get(normalsLabels.indexOf(label));
Expand Down
6 changes: 4 additions & 2 deletions src/processes/climatological_normal.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { BaseProcess } from '@openeo/js-processgraphs';
import Commons from '../processgraph/commons.js';
import Utils from '../utils/utils.js';
import GeeUtils from '../processgraph/utils.js';

export default class climatological_normal extends BaseProcess {

async execute(node) {
const ee = node.ee;
const dc = node.getDataCube('data');
const frequency = node.getArgument('frequency');

Expand All @@ -25,7 +27,7 @@ export default class climatological_normal extends BaseProcess {
break;
case 'seasons':
// Define seasons + labels
seasons = Utils.seasons();
seasons = GeeUtils.seasons(node);
geeSeasons = ee.Dictionary(seasons);
labels = Object.keys(seasons);
range = geeSeasons.values();
Expand All @@ -41,7 +43,7 @@ export default class climatological_normal extends BaseProcess {
break;
case 'tropical_seasons':
// Define seasons + labels
seasons = Utils.tropicalSeasons();
seasons = GeeUtils.tropicalSeasons(node);
geeSeasons = ee.Dictionary(seasons);
labels = Object.keys(seasons);
range = geeSeasons.values();
Expand Down
2 changes: 1 addition & 1 deletion src/processes/create_raster_cube.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import DataCube from '../processgraph/datacube.js';
export default class create_raster_cube extends BaseProcess {

async execute(node) {
const dc = new DataCube();
const dc = new DataCube(node.ee);
dc.setLogger(node.getLogger());
return dc;
}
Expand Down
2 changes: 1 addition & 1 deletion src/processes/filter_bbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Commons from '../processgraph/commons.js';
export default class filter_bbox extends BaseProcess {

async execute(node) {
return Commons.filterBbox(node.getDataCube("data"), node.getArgument("extent"), this.id, 'extent');
return Commons.filterBbox(node, node.getDataCube("data"), node.getArgument("extent"), this.id, 'extent');
}

}
2 changes: 1 addition & 1 deletion src/processes/filter_spatial.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Commons from '../processgraph/commons.js';
export default class filter_spatial extends BaseProcess {

async execute(node) {
return Commons.filterGeoJSON(node.getData("data"), node.getArgument("geometries"), this.id, 'geometries');
return Commons.filterGeoJSON(node, node.getData("data"), node.getArgument("geometries"), this.id, 'geometries');
}

}
1 change: 1 addition & 0 deletions src/processes/first.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export default class first extends BaseProcess {
}

async execute(node) {
const ee = node.ee;
const data = node.getArgument('data');

if (Array.isArray(data)) {
Expand Down
2 changes: 1 addition & 1 deletion src/processes/if.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export default class If extends BaseProcess {
const accept = node.getArgument('accept');
const reject = node.getArgument('reject');

return ee.Algorithms.If(value, accept, reject);
return node.ee.Algorithms.If(value, accept, reject);
//if (value === true) {
// return accept;
//}
Expand Down
1 change: 1 addition & 0 deletions src/processes/last.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export default class last extends BaseProcess {
}

async execute(node) {
const ee = node.ee;
const data = node.getArgument('data');

if (Array.isArray(data)) {
Expand Down
9 changes: 5 additions & 4 deletions src/processes/load_collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import Commons from '../processgraph/commons.js';
export default class load_collection extends BaseProcess {

async execute(node) {
const ee = node.ee;
// Load data
const id = node.getArgument('id');
const collection = node.getContext().getCollection(id);
let dc = new DataCube();
let dc = new DataCube(ee);
dc.setLogger(node.getLogger());
let eeData;
if (collection['gee:type'] === 'image') {
eeData = ee.ImageCollection(ee.Image(id));
eeData = ee.Image(id);
}
else {
eeData = ee.ImageCollection(id);
Expand All @@ -32,10 +33,10 @@ export default class load_collection extends BaseProcess {
const spatial_extent = node.getArgument("spatial_extent");
if (spatial_extent !== null) {
if (spatial_extent.type) { // GeoJSON - has been validated before so `type` should be a safe indicator for GeoJSON
dc = Commons.filterGeoJSON(dc, spatial_extent, this.id, 'spatial_extent');
dc = Commons.filterGeoJSON(node, dc, spatial_extent, this.id, 'spatial_extent');
}
else { // Bounding box
dc = Commons.filterBbox(dc, spatial_extent, this.id, 'spatial_extent');
dc = Commons.filterBbox(node, dc, spatial_extent, this.id, 'spatial_extent');
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/processes/log.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default class log extends BaseProcess {
case 10:
return image.log10();
default:
return image.log().divide(ee.Image(base).log());
return image.log().divide(node.ee.Image(base).log());
}
},
x => {
Expand Down
Loading

0 comments on commit 58ebe82

Please sign in to comment.