-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Only allow http request from Electron's own browser-window. Token is generated within electron-main, which also sets it as a cookie within browser-windows. Token is passed to the backend via environment variables. The backend is looking for this specific token to authorize requests. Signed-off-by: Paul Maréchal <paul.marechal@ericsson.com>
- Loading branch information
1 parent
4d4f6c2
commit a6def7c
Showing
10 changed files
with
240 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/******************************************************************************** | ||
* Copyright (C) 2020 Ericsson and others. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Eclipse Public License v. 2.0 which is available at | ||
* http://www.eclipse.org/legal/epl-2.0. | ||
* | ||
* This Source Code may also be made available under the following Secondary | ||
* Licenses when the conditions for such availability set forth in the Eclipse | ||
* Public License v. 2.0 are satisfied: GNU General Public License, version 2 | ||
* with the GNU Classpath Exception which is available at | ||
* https://www.gnu.org/software/classpath/license.html. | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 | ||
********************************************************************************/ | ||
|
||
/** | ||
* This token is unique the the current running instance. It is used by the backend | ||
* to make sure it is an electron browser window that is connecting to its services. | ||
* | ||
* The identifier is a string, which makes it usable as a key for cookies or similar. | ||
*/ | ||
export const ElectronSecurityToken = 'x-theia-electron-token'; | ||
export interface ElectronSecurityToken { | ||
value: string; | ||
}; |
74 changes: 74 additions & 0 deletions
74
packages/core/src/electron-node/token/electron-token-backend-contribution.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
/******************************************************************************** | ||
* Copyright (C) 2020 Ericsson and others. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Eclipse Public License v. 2.0 which is available at | ||
* http://www.eclipse.org/legal/epl-2.0. | ||
* | ||
* This Source Code may also be made available under the following Secondary | ||
* Licenses when the conditions for such availability set forth in the Eclipse | ||
* Public License v. 2.0 are satisfied: GNU General Public License, version 2 | ||
* with the GNU Classpath Exception which is available at | ||
* https://www.gnu.org/software/classpath/license.html. | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 | ||
********************************************************************************/ | ||
|
||
import * as ws from 'ws'; | ||
import * as http from 'http'; | ||
import express = require('express'); | ||
import { injectable, inject } from 'inversify'; | ||
import { BackendApplicationContribution } from '../../node'; | ||
import { MessagingContribution } from '../../node/messaging/messaging-contribution'; | ||
import { ElectronTokenValidator } from './electron-token-validator'; | ||
|
||
/** | ||
* This component contributes a middleware that will refuse all requests that do not include a specific token. | ||
*/ | ||
@injectable() | ||
export class ElectronTokenBackendContribution implements BackendApplicationContribution { | ||
|
||
@inject(ElectronTokenValidator) | ||
protected readonly tokenValidator: ElectronTokenValidator; | ||
|
||
configure(app: express.Application): void { | ||
app.use(this.expressMiddleware.bind(this)); | ||
} | ||
|
||
/** | ||
* Only allow token-bearers. | ||
*/ | ||
protected expressMiddleware(req: express.Request, res: express.Response, next: express.NextFunction): void { | ||
if (this.tokenValidator.allowRequest(req)) { | ||
next(); | ||
} else { | ||
console.error(`refused an http request: ${req.connection.remoteAddress}`); | ||
res.sendStatus(403); | ||
} | ||
} | ||
|
||
} | ||
|
||
/** | ||
* Override the browser MessagingContribution class to refuse connections that do not include a specific token. | ||
*/ | ||
@injectable() | ||
export class ElectronMessagingContribution extends MessagingContribution { | ||
|
||
@inject(ElectronTokenValidator) | ||
protected readonly tokenValidator: ElectronTokenValidator; | ||
|
||
/** | ||
* The Browser API doesn't allow us to define custom headers. | ||
* Then, in order to authorize a connect, we will expect the first message to contain a token. | ||
*/ | ||
protected handleConnection(socket: ws, request: http.IncomingMessage): void { | ||
if (this.tokenValidator.allowRequest(request)) { | ||
super.handleConnection(socket, request); | ||
} else { | ||
console.error(`refused a websocket connection: ${request.connection.remoteAddress}`); | ||
socket.close(); | ||
} | ||
} | ||
|
||
} |
36 changes: 36 additions & 0 deletions
36
packages/core/src/electron-node/token/electron-token-backend-module.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
/******************************************************************************** | ||
* Copyright (C) 2020 Ericsson and others. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Eclipse Public License v. 2.0 which is available at | ||
* http://www.eclipse.org/legal/epl-2.0. | ||
* | ||
* This Source Code may also be made available under the following Secondary | ||
* Licenses when the conditions for such availability set forth in the Eclipse | ||
* Public License v. 2.0 are satisfied: GNU General Public License, version 2 | ||
* with the GNU Classpath Exception which is available at | ||
* https://www.gnu.org/software/classpath/license.html. | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 | ||
********************************************************************************/ | ||
|
||
import { ContainerModule } from 'inversify'; | ||
import { MessagingContribution } from '../../node/messaging/messaging-contribution'; | ||
import { ElectronSecurityToken } from '../../electron-common/electron-token'; | ||
import { ElectronMessagingContribution, ElectronTokenBackendContribution } from './electron-token-backend-contribution'; | ||
import { BackendApplicationContribution, MessagingService } from '../../node'; | ||
import { ElectronTokenValidator } from './electron-token-validator'; | ||
|
||
export default new ContainerModule((bind, unbind, isBound, rebind) => { | ||
bind<Promise<ElectronSecurityToken>>(Promise).toDynamicValue(async () => | ||
JSON.parse(process.env[ElectronSecurityToken]!) | ||
).inSingletonScope().whenTargetNamed(ElectronSecurityToken); | ||
|
||
bind<ElectronTokenValidator>(ElectronTokenValidator).toSelf().inSingletonScope(); | ||
bind<ElectronTokenBackendContribution>(ElectronTokenBackendContribution).toSelf().inSingletonScope(); | ||
for (const contribution of [ElectronTokenBackendContribution, ElectronTokenValidator]) { | ||
bind<BackendApplicationContribution>(BackendApplicationContribution).toService(contribution); | ||
} | ||
|
||
rebind<MessagingContribution>(MessagingService.Identifier).to(ElectronMessagingContribution).inSingletonScope(); | ||
}); |
66 changes: 66 additions & 0 deletions
66
packages/core/src/electron-node/token/electron-token-validator.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
/******************************************************************************** | ||
* Copyright (C) 2020 Ericsson and others. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Eclipse Public License v. 2.0 which is available at | ||
* http://www.eclipse.org/legal/epl-2.0. | ||
* | ||
* This Source Code may also be made available under the following Secondary | ||
* Licenses when the conditions for such availability set forth in the Eclipse | ||
* Public License v. 2.0 are satisfied: GNU General Public License, version 2 | ||
* with the GNU Classpath Exception which is available at | ||
* https://www.gnu.org/software/classpath/license.html. | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 | ||
********************************************************************************/ | ||
|
||
import * as http from 'http'; | ||
import * as cookie from 'cookie'; | ||
import { injectable, inject, named } from 'inversify'; | ||
import { ElectronSecurityToken } from '../../electron-common/electron-token'; | ||
import { BackendApplicationContribution } from '../../node'; | ||
|
||
/** | ||
* On Electron, we want to make sure that only electron windows access the backend services. | ||
*/ | ||
@injectable() | ||
export class ElectronTokenValidator implements BackendApplicationContribution { | ||
|
||
@inject(Promise) @named(ElectronSecurityToken) | ||
protected readonly electronSecurityTokenPromise: Promise<ElectronSecurityToken>; | ||
|
||
/** | ||
* `electronSecurityToken` can be undefined while the value is being resolved. | ||
*/ | ||
protected electronSecurityToken: ElectronSecurityToken | undefined; | ||
|
||
async onStart(): Promise<void> { | ||
this.electronSecurityToken = await this.electronSecurityTokenPromise; | ||
} | ||
|
||
allowRequest(request: http.IncomingMessage): boolean { | ||
const token = this.extractTokenFromRequest(request); | ||
return typeof token !== 'undefined' && this.isTokenValid(token); | ||
} | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
isTokenValid(token: any): boolean { | ||
return typeof token === 'object' && token.value === this.electronSecurityToken!.value; | ||
} | ||
|
||
/** | ||
* Expects the token to be passed via cookies by default. | ||
*/ | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
protected extractTokenFromRequest(request: http.IncomingMessage): any { | ||
const cookieHeader = request.headers.cookie; | ||
if (typeof cookieHeader === 'string') { | ||
const token = cookie.parse(cookieHeader)[ElectronSecurityToken]; | ||
if (typeof token === 'string') { | ||
return JSON.parse(token); | ||
} | ||
} | ||
return undefined; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters