Skip to content

Commit

Permalink
feat: add routes, auth check
Browse files Browse the repository at this point in the history
- scram router module for authentication, logout, and auth check
- no op for no auth
- extend auth support to provide additional functions to all modules
for checking auth, logging out

Contributes-to: strimzi#106

Signed-off-by: Nic Townsend <[email protected]>
  • Loading branch information
nictownsend committed Nov 27, 2020
1 parent 77ee7a3 commit 41a4bee
Show file tree
Hide file tree
Showing 32 changed files with 510 additions and 218 deletions.
6 changes: 3 additions & 3 deletions config/static.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ const client: Config<Literal> = {};
const server: Config<Literal> = {
defaultServerConfig: {
configValue: {
authentication: {
type: 'none',
},
client: {
configOverrides: {},
transport: {},
Expand All @@ -35,6 +32,9 @@ const server: Config<Literal> = {
contextRoot: '/',
port: 9080,
transport: {},
authentication: {
type: 'none',
},
},
session: {
name: 'strimzi-ui',
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,13 @@
"apollo-link-http": "^1.5.17",
"apollo-server-express": "^2.18.2",
"axios": "^0.21.0",
"body-parser": "^1.19.0",
"compression-webpack-plugin": "^4.0.0",
"express": "^4.17.1",
"express-session": "^1.17.1",
"express-static-gzip": "^2.1.0",
"graphql": "^15.4.0",
"graphql-tag": "^2.11.0",
"graphql-ws": "^1.14.0",
"helmet": "^4.2.0",
"html-webpack-plugin": "^4.5.0",
Expand Down
38 changes: 19 additions & 19 deletions server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,22 @@ This directory contains all server code for the Strimzi UI - ie code which is re

As described in [the configuration approach](../docs/Architecture.md#configuration-and-feature-flagging), the UI server's configuration is provided via a file, which is then watched at runtime for modification. This configuration file is expected to be called `server.config.json` (available in the same directory as the `node` executable is run from), but this can be configured at runtime via environment variable `configPath`, dictating a different path and file name. The file must be either valid JSON or JS. The server also hosts configuration for discovery by the client via the `config` module. The configuration options for the server provided in the previously mentioned configuration file are as follows:

| Configuration | Required | Default | Purpose |
| ---------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| authentication.strategy | No | `none` | What authentication strategy to use to authenticate users. See [the security section](#security) for details of the available options. |
| authentication.configuration | No | `{}` | Any additional configuration required for the provided authentication strategy `authentication.strategy` . See [the security section](#security) for details of the available options. |
| client.configOverrides | No | `{}` | Overrides to send to the client. See [client configuration for further details](#client-configuration). These values will take precedence over any others provided. |
| client.publicDir | No | `/dist/client` | The location of the built client to serve. |
| client.transport.cert | No | N/A - if one of `client.transport.cert` or `client.transport.key` are not provided, server will be HTTP | PEM certificate presented to browsers on connecting to the UI server. |
| client.transport.key | No | N/A - if one of `client.transport.cert` or `client.transport.key` are not provided, server will be HTTP | PEM certificate private key for the certificate provided in `client.transport.cert`. |
| client.transport.ciphers | No | default set from [node's tls module](https://nodejs.org/api/tls.html#tls_modifying_the_default_tls_cipher_suite) | TLS ciphers used/supported by the HTTPS server for client negotiation. Only applies if starting an HTTPS server. |
| client.transport.minTLS | No | `TLSv1.2` | Minimum TLS version supported by the server. Only applies if starting an HTTPS server. Set to `TLSv1.2` for browser compatibility. |
| featureFlags | No | `{}` | Feature flag overrides to set. The configuration is as per the format specified [here](#feature-flags). These values will take precedence over any others provided. |
| hostname | No | '0.0.0.0' | The hostname the UI server will be bound to. |
| logging | No | TBD | Logging configuration settings. Format to be defined in https://github.com/strimzi/strimzi-ui/issues/24 |
| modules | No | Object - [enabled modules and configuration can be found here](../docs/Architecture.md#router-controller-data-pattern) | The modules which are either enabled or disabled. |
| port | No | 3000 | The port the UI server will be bound to. |
| proxy.transport.cert | No | If not provided, SSL certificate validation of the upstream admin server is disabled | CA certificate in PEM format of the backend admin server api requests are to be sent to. |
| proxy.hostname | Yes | N/A | The hostname of the admin server to send api requests to. |
| proxy.port | Yes | N/A | The port of the admin server to send api requests to. |
| session.name | no | `strimzi-ui` | The name used to identify the session cookie |
| Configuration | Required | Default | Purpose |
| ---------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| client.configOverrides | No | `{}` | Overrides to send to the client. See [client configuration for further details](#client-configuration). These values will take precedence over any others provided. |
| client.publicDir | No | `/dist/client` | The location of the built client to serve. |
| client.transport.cert | No | N/A - if one of `client.transport.cert` or `client.transport.key` are not provided, server will be HTTP | PEM certificate presented to browsers on connecting to the UI server. |
| client.transport.key | No | N/A - if one of `client.transport.cert` or `client.transport.key` are not provided, server will be HTTP | PEM certificate private key for the certificate provided in `client.transport.cert`. |
| client.transport.ciphers | No | default set from [node's tls module](https://nodejs.org/api/tls.html#tls_modifying_the_default_tls_cipher_suite) | TLS ciphers used/supported by the HTTPS server for client negotiation. Only applies if starting an HTTPS server. |
| client.transport.minTLS | No | `TLSv1.2` | Minimum TLS version supported by the server. Only applies if starting an HTTPS server. Set to `TLSv1.2` for browser compatibility. |
| featureFlags | No | `{}` | Feature flag overrides to set. The configuration is as per the format specified [here](#feature-flags). These values will take precedence over any others provided. |
| hostname | No | '0.0.0.0' | The hostname the UI server will be bound to. |
| logging | No | TBD | Logging configuration settings. Format to be defined in https://github.com/strimzi/strimzi-ui/issues/24 |
| modules | No | Object - [enabled modules and configuration can be found here](../docs/Architecture.md#router-controller-data-pattern) | The modules which are either enabled or disabled. |
| port | No | 3000 | The port the UI server will be bound to. |
| proxy.transport.cert | No | If not provided, SSL certificate validation of the upstream admin server is disabled | CA certificate in PEM format of the backend admin server api requests are to be sent to. |
| proxy.hostname | Yes | N/A | The hostname of the admin server to send api requests to. |
| proxy.port | Yes | N/A | The port of the admin server to send api requests to. |
| proxy.authentication.type | No | `none` | What authentication strategy to use to authenticate users. See [the security section](#security) for details of the available options. |
| proxy.authentication.configuration | No | `{}` | Any additional configuration required for the provided authentication strategy `authentication.strategy` . See [the security section](#security) for details of the available options. |
| session.name | no | `strimzi-ui` | The name used to identify the session cookie |
4 changes: 2 additions & 2 deletions server/client/client.feature
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ Feature: client module
# if the route (not file) is not matched, we redirect to index.html. Hence / and someroute response
Examples:
| Asset | StatusCode |
| /index.html | 200 |
| /index.html | 302 |
| /images/picture.svg | 200 |
| /doesnotexist.html | 404 |
| /someroute | 302 |
| /protected.html | 302 |
| / | 200 |
| / | 302 |
16 changes: 2 additions & 14 deletions server/client/client.steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,8 @@
* License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
*/
import merge from 'lodash.merge';
import { And, Then, Fusion } from 'jest-cucumber-fusion';
import {
stepWithWorld,
stepWhichUpdatesWorld,
} from 'test_common/commonServerSteps';
import { And, Fusion } from 'jest-cucumber-fusion';
import { stepWhichUpdatesWorld } from 'test_common/commonServerSteps';

And(
'There are no files to serve',
Expand All @@ -27,13 +24,4 @@ And('There are files to serve', () => {
// NO_OP - the `client_only` configuration is already configured to serve fixture files
});

Then(
/I get the expected status code '(.+)' response/,
stepWithWorld((world, statusCode) => {
const expectedStatus = parseInt(statusCode as string);
const { request } = world;
return request.expect(expectedStatus);
})
);

Fusion('client.feature');
31 changes: 15 additions & 16 deletions server/client/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,29 @@
* License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
*/

import { resolve, sep } from 'path';
import { existsSync, readdirSync } from 'fs';
import { resolve, sep } from "path";
import { existsSync, readdirSync } from "fs";

// function to recursively get all files from a directory
const getFilesInDirectory: (directory: string) => Array<string> = (directory) =>
existsSync(directory)
? readdirSync(directory, { withFileTypes: true }).reduce((acc, fileObj) => {
return fileObj.isFile()
? acc.concat([`${directory}${sep}${fileObj.name}`])
: acc.concat(
getFilesInDirectory(`${directory}${sep}${fileObj.name}`)
);
}, [] as string[])
return fileObj.isFile()
? acc.concat([`${directory}${sep}${fileObj.name}`])
: acc.concat(
getFilesInDirectory(`${directory}${sep}${fileObj.name}`)
);
}, [] as string[])
: [];

// mark a subset of files as public - this means any user can access them. These entries will be used in a regex - if the test passes, it will be considered public
const publicFiles = [
'images/*',
'fonts/*',
'favicon.ico',
'index.html',
'main.css',
'main.bundle.js',
'main.bundle.js.gz',
"images/*",
"fonts/*",
"favicon.ico",
"main.css",
"main.bundle.js",
"main.bundle.js.gz",
];

export const getFiles: (
Expand Down Expand Up @@ -57,7 +56,7 @@ export const getFiles: (

return {
totalNumberOfFiles: allFilesInClientDirectory.length,
hasIndexFile: allFilesInClientDirectory.includes('/index.html'),
hasIndexFile: allFilesInClientDirectory.includes("/index.html"),
protectedFiles: protectedFiles,
builtClientDir,
};
Expand Down
8 changes: 5 additions & 3 deletions server/client/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const ClientModule: UIServerModule = {

// add the auth middleware to all non public files
protectedFiles.forEach((file) => routerForModule.get(`${file}`, checkAuth));
routerForModule.get('/', checkAuth);

// host all files from the client dir
routerForModule.get(
Expand All @@ -40,9 +41,10 @@ export const ClientModule: UIServerModule = {

// if no match, not a file (path contains '.'), and we have an index.html file, redirect to it (ie return index so client navigation logic kicks in). Else do nothing (404 unless another module handles it)
hasIndexFile &&
routerForModule.get(/^((?!\.).)+$/, (req, res) =>
res.redirect(`/index.html`)
);
routerForModule.get(/^((?!\.).)+$/, (req, res) => {
logger.info('Redirecting to index');
res.redirect(`/`);
});

return exit({ mountPoint: '/', routerForModule });
},
Expand Down
Loading

0 comments on commit 41a4bee

Please sign in to comment.