From d01c89a9fad5c1295752e8597aaafe53b699be73 Mon Sep 17 00:00:00 2001 From: Stijn van der Vegt Date: Fri, 22 Jan 2021 16:07:06 +0100 Subject: [PATCH 1/9] add github workflows --- .github/workflows/gitops.yml | 79 ++++++++++++++++++++++++++++++++++++ gitops_push | 24 +++++++++++ 2 files changed, 103 insertions(+) create mode 100644 .github/workflows/gitops.yml create mode 100644 gitops_push diff --git a/.github/workflows/gitops.yml b/.github/workflows/gitops.yml new file mode 100644 index 00000000..babc0d6d --- /dev/null +++ b/.github/workflows/gitops.yml @@ -0,0 +1,79 @@ +name: GitopsDev + +# Run this workflow every time a new commit pushed to your repository +on: + workflow_dispatch: + inputs: + environmentValuesFile: + description: 'Gitops environment values file' + required: true + default: 'dev' + push: + branches: + - master + - development + - feature/* + - release/* + - release + +jobs: + gitops: + environment: gitops + env: + HELM_REPO_NAME: openstad-kubernetes + HELM_CHART_FOLDER: k8s/openstad + GIT_USER_EMAIL: github@ci.push + GIT_USER_NAME: GitHub + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} + HELM_REPO: ${{ secrets.HELM_REPO }} + HELM_REPO_WITH_TOKEN: ${{ secrets.HELM_REPO_WITH_TOKEN }} + GITOPS_RELEASE_BRANCH: ${{ secrets.GITOPS_RELEASE_BRANCH }} + BRANCH_REF: ${{ github.ref }} + GITOPS_VALUES_FILE: k8s/openstad/environments/dev.values.yaml + + name: gitops commit + runs-on: ubuntu-latest + + services: + docker: + image: docker + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set environment to acc + id: acc_values_file + shell: bash + if: contains(github.ref, 'release') + run: echo "GITOPS_VALUES_FILE=k8s/openstad/environments/acc.values.yaml" >> $GITHUB_ENV + + - name: Set environment to production + id: prod_values_file + shell: bash + if: startsWith(github.ref, 'refs/tags/') || github.ref == 'refs/heads/master' + run: echo "GITOPS_VALUES_FILE=k8s/openstad/environments/prod.values.yaml" >> $GITHUB_ENV + + - name: Set commit SHA & current branch + id: vars + shell: bash + run: | + echo "::set-output name=sha_short::$(git rev-parse --short HEAD)" + echo "::set-output name=current_branch::$(git branch --show-current | sed "s/\//-/g")" + + - name: Install yq + run: sudo snap install yq --channel=v3/stable + + + - name: Run build script + run: docker build -t ${{ secrets.DOCKER_PUBLIC_USERNAME }}/${{ secrets.DOCKER_IMAGE_NAME }}:${{ steps.vars.outputs.current_branch }}-${{ steps.vars.outputs.sha_short }}-${{ github.run_id}} . + shell: bash + + - name: Run docker push script + run: | + sudo chmod a+x ./gitops_push + ./gitops_push + shell: bash + env: + IMAGE_TAG: ${{ secrets.DOCKER_PUBLIC_USERNAME }}/${{ secrets.DOCKER_IMAGE_NAME }}:${{ steps.vars.outputs.current_branch }}-${{ steps.vars.outputs.sha_short }}-${{ github.run_id}} diff --git a/gitops_push b/gitops_push new file mode 100644 index 00000000..a75bf869 --- /dev/null +++ b/gitops_push @@ -0,0 +1,24 @@ +#!/bin/bash + +echo "DOCKER LOGIN" +echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin; +echo "DOCKER PUSH TAG" +echo ${IMAGE_TAG} +docker push ${IMAGE_TAG} + +git config --global user.email ${GIT_USER_EMAIL} +git config --global user.name ${GIT_USER_NAME} + +git clone ${HELM_REPO} && cd ${HELM_REPO_NAME} && \ + +git remote add origin-ci ${HELM_REPO_WITH_TOKEN} > /dev/null 2>&1 + +git checkout ${GITOPS_RELEASE_BRANCH} + +/snap/bin/yq write -i ${GITOPS_VALUES_FILE} auth.deploymentContainer.image ${IMAGE_TAG} && \ + +git add ${GITOPS_VALUES_FILE} && \ + +git commit -am "Release ${IMAGE_TAG}" && \ + +git push --quiet --set-upstream origin-ci ${GITOPS_RELEASE_BRANCH} From 7b7e7e6c18fc3f2b7f46ff4cf549862791edba6f Mon Sep 17 00:00:00 2001 From: Rudi van Hierden Date: Tue, 22 Nov 2022 11:18:16 +0100 Subject: [PATCH 2/9] chore: add debug logs --- app-init.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/app-init.js b/app-init.js index 319fa0c3..f8d47f55 100644 --- a/app-init.js +++ b/app-init.js @@ -116,7 +116,6 @@ app.use(passport.initialize()); app.use(passport.session()); app.use(expressValidator()); -/* app.use((req, res, next) => { console.log('=====> REQUEST: ', req.originalUrl); console.log('=====> query: ', req.query); @@ -124,7 +123,6 @@ app.use((req, res, next) => { console.log('=====> session: ', req.session); next(); }); -*/ // Passport configuration require('./auth'); From 83f43ea45b061b1115b60467f0f64573c8d4eda7 Mon Sep 17 00:00:00 2001 From: Rudi van Hierden Date: Tue, 22 Nov 2022 14:18:38 +0100 Subject: [PATCH 3/9] chore: add ip to log --- app-init.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app-init.js b/app-init.js index f8d47f55..6954e0e1 100644 --- a/app-init.js +++ b/app-init.js @@ -119,6 +119,7 @@ app.use(expressValidator()); app.use((req, res, next) => { console.log('=====> REQUEST: ', req.originalUrl); console.log('=====> query: ', req.query); + console.log('=====> ip: ', req.headers['x-forwarded-for'] || req.socket.remoteAddress, req.ip); console.log('=====> body: ', req.body); console.log('=====> session: ', req.session); next(); From a939e1e02ae1749807c4b84385a482c43f4f286e Mon Sep 17 00:00:00 2001 From: Rudi van Hierden Date: Mon, 28 Nov 2022 10:00:45 +0100 Subject: [PATCH 4/9] feat: add blocker for cisco umbrella requests This routes /url/authenticate requests from the Cisco Umbrella CIDRs to a different page. This prevents Cisco from 'logging in' and preventing the user from logging in. --- middleware/blocker.js | 29 +++++++++++++++++++++++++++++ package-lock.json | 18 ++++++++++++++++-- package.json | 3 ++- routes/routes.js | 3 ++- 4 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 middleware/blocker.js diff --git a/middleware/blocker.js b/middleware/blocker.js new file mode 100644 index 00000000..8b3b13ee --- /dev/null +++ b/middleware/blocker.js @@ -0,0 +1,29 @@ +const Netmask = require('netmask').Netmask; + +exports.preventCiscoRequest = (req, res, next) => { + + // Fix for local IP + if (req.ip == '::1') { + return next(); + } + + // CIDRs for Cisco Umbrella + // See https://support.umbrella.com/hc/en-us/articles/360059292052-Additional-Egress-IP-Address-Range + const cidrs = ['146.112.0.0/16', '155.190.0.0/16']; + + // Check if IP is in cidr + const isIpInCidr = cidrs.some(cidr => { + const block = new Netmask(cidr); + return block.contains(req.ip); + }); + + if (!isIpInCidr) { + return next(); + } + + console.log('IP is in CIDRs to block', req.ip, cidrs, isIpInCidr); + + req.flash('error', {msg: 'De url is geen geldige login url, wellicht is deze verlopen'}); + return res.redirect(`/auth/url/login?clientId=${req.query.clientId}`); + +} diff --git a/package-lock.json b/package-lock.json index 14d4b068..1646473e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "openstad-oauth2-server", - "version": "0.40.0", + "version": "0.41.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "openstad-oauth2-server", - "version": "0.40.0", + "version": "0.41.0", "license": "MIT", "dependencies": { "bcrypt": "^5.0.1", @@ -36,6 +36,7 @@ "moment": "^2.29.3", "moment-timezone": "^0.5.23", "mysql": "^2.16.0", + "netmask": "^2.0.2", "node-2fa": "^2.0.2", "node-fetch": "^2.6.7", "nodemailer": "^6.6.1", @@ -9484,6 +9485,14 @@ "node": ">= 0.6" } }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -20413,6 +20422,11 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" }, + "netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==" + }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", diff --git a/package.json b/package.json index 9bf9f305..7b78be37 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "moment": "^2.29.3", "moment-timezone": "^0.5.23", "mysql": "^2.16.0", + "netmask": "^2.0.2", "node-2fa": "^2.0.2", "node-fetch": "^2.6.7", "nodemailer": "^6.6.1", @@ -76,8 +77,8 @@ "eslint-plugin-import": "^2.26.0", "eslint-plugin-jsx-a11y": "^6.6.1", "eslint-plugin-react": "^7.30.1", - "mock-knex": "^0.4.11", "jest": "^27.2.5", + "mock-knex": "^0.4.11", "request": "^2.48.x", "sqlite3": "^5.0.4", "supertest": "^4.0.2" diff --git a/routes/routes.js b/routes/routes.js index b6f16bbd..58c3860a 100644 --- a/routes/routes.js +++ b/routes/routes.js @@ -23,6 +23,7 @@ const bruteForce = require('../middleware/bruteForce'); const authMw = require('../middleware/auth'); const passwordResetMw = require('../middleware/passwordReset'); const logMw = require('../middleware/log'); +const blocker = require('../middleware/blocker'); //UTILS const getClientIdFromRequest = require('../utils/getClientIdFromRequest'); @@ -237,7 +238,7 @@ module.exports = function (app) { app.get('/auth/url/login/:priviligedRoute?', clientMw.setAuthType('Url'), clientMw.validate, csrfProtection, addCsrfGlobal, authUrl.login); app.get('/auth/url/confirmation', clientMw.setAuthType('Url'), csrfProtection, addCsrfGlobal, authUrl.confirmation); app.post('/auth/url/login/:priviligedRoute?', clientMw.setAuthType('Url'), csrfProtection, emailUrlBruteForce, authUrl.postLogin); - app.get('/auth/url/authenticate', clientMw.setAuthType('Url'), csrfProtection, addCsrfGlobal, authUrl.authenticate); + app.get('/auth/url/authenticate', blocker.preventCiscoRequest, clientMw.setAuthType('Url'), csrfProtection, addCsrfGlobal, authUrl.authenticate); app.post('/auth/url/authenticate', clientMw.setAuthType('Url'), csrfProtection, emailUrlBruteForce, authUrl.postAuthenticate); From d01769220761b0fa5d5ec161826ba61e3fb8ab25 Mon Sep 17 00:00:00 2001 From: Rudi van Hierden Date: Wed, 19 Apr 2023 09:10:14 +0200 Subject: [PATCH 5/9] fix: add try/catch to prevent hard type error --- controllers/auth/local.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/controllers/auth/local.js b/controllers/auth/local.js index 450f5894..fdfd675d 100644 --- a/controllers/auth/local.js +++ b/controllers/auth/local.js @@ -128,8 +128,12 @@ exports.logout = async (req, res) => { const config = req.client.config; const allowedDomains = req.client.allowedDomains ? req.client.allowedDomains : false; let redirectURL = req.query.redirectUrl; - const redirectUrlHost = redirectURL ? new URL(redirectURL).hostname : false; - redirectURL = redirectUrlHost && allowedDomains && allowedDomains.indexOf(redirectUrlHost) !== -1 ? redirectURL : false; + try { + const redirectUrlHost = redirectURL ? new URL(redirectURL).hostname : false; + redirectURL = redirectUrlHost && allowedDomains && allowedDomains.indexOf(redirectUrlHost) !== -1 ? redirectURL : false; + } catch (e) { + // + } if (!redirectURL) { redirectURL = config && config.logoutUrl ? config.logoutUrl : req.client.siteUrl From 47a83421e8a7f3a24022d68adcf6aa3013bff559 Mon Sep 17 00:00:00 2001 From: Rudi van Hierden Date: Wed, 2 Aug 2023 15:15:18 +0200 Subject: [PATCH 6/9] fix: add new Umbrella IP --- middleware/blocker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/middleware/blocker.js b/middleware/blocker.js index 8b3b13ee..915a6d91 100644 --- a/middleware/blocker.js +++ b/middleware/blocker.js @@ -9,7 +9,7 @@ exports.preventCiscoRequest = (req, res, next) => { // CIDRs for Cisco Umbrella // See https://support.umbrella.com/hc/en-us/articles/360059292052-Additional-Egress-IP-Address-Range - const cidrs = ['146.112.0.0/16', '155.190.0.0/16']; + const cidrs = ['146.112.0.0/16', '155.190.0.0/16', '151.186.0.0/16']; // Check if IP is in cidr const isIpInCidr = cidrs.some(cidr => { From 5fe899f5b666bd583c1815e19012b9761568786a Mon Sep 17 00:00:00 2001 From: Rudi van Hierden Date: Wed, 2 Aug 2023 15:16:49 +0200 Subject: [PATCH 7/9] chore: update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09c1379b..e91ad02c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## UNRELEASED +* Add CIDR-based blocker to prevent e-mail filters (e.g. Cisco Umbrella) from invalidating a login link + ## 1.0.0 * Add env MYSQL_CA_CERT for MySQL SSL connection * Upgrade to node 16 From 6882d701f4d6d9b615ce887f4a77c6cf4b7eb281 Mon Sep 17 00:00:00 2001 From: Rudi van Hierden Date: Thu, 3 Aug 2023 13:43:34 +0200 Subject: [PATCH 8/9] feat: fetch block CIDRs from client You can now add `blockCidrs` to the client config. Example: ``` { "blockCidrs": [ "1.2.3.4/16", "4.4.4.4/16" ] } ``` When the `blockCidrs` key does not exist in the client config, the block cidrs default to the Cisco umbrella CIDRs. Note: This means that if you want to add CIDRs to the block CIDRs, and you want to keep the Cisco Umbrello CIDRs, you have to add those to the client config as well. --- middleware/blocker.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/middleware/blocker.js b/middleware/blocker.js index 915a6d91..0e4558b0 100644 --- a/middleware/blocker.js +++ b/middleware/blocker.js @@ -7,12 +7,12 @@ exports.preventCiscoRequest = (req, res, next) => { return next(); } - // CIDRs for Cisco Umbrella + // Get CIDRs from client config. If the `blockCidrs` key doesn't exist fall back to Cisco Umbrella CIDRs // See https://support.umbrella.com/hc/en-us/articles/360059292052-Additional-Egress-IP-Address-Range - const cidrs = ['146.112.0.0/16', '155.190.0.0/16', '151.186.0.0/16']; + const blockCidrs = req && req.client && req.client.config && req.client.config.blockCidrs ? req.client.config.blockCidrs : ['146.112.0.0/16', '155.190.0.0/16', '151.186.0.0/16']; // Check if IP is in cidr - const isIpInCidr = cidrs.some(cidr => { + const isIpInCidr = blockCidrs.some(cidr => { const block = new Netmask(cidr); return block.contains(req.ip); }); @@ -21,7 +21,7 @@ exports.preventCiscoRequest = (req, res, next) => { return next(); } - console.log('IP is in CIDRs to block', req.ip, cidrs, isIpInCidr); + console.log('IP is in CIDRs to block', req.ip, blockCidrs, isIpInCidr); req.flash('error', {msg: 'De url is geen geldige login url, wellicht is deze verlopen'}); return res.redirect(`/auth/url/login?clientId=${req.query.clientId}`); From 31d710beebab1aec8eb917fea17149dff2670e92 Mon Sep 17 00:00:00 2001 From: Rudi van Hierden Date: Thu, 3 Aug 2023 13:47:03 +0200 Subject: [PATCH 9/9] chore: update readme & changelog --- CHANGELOG.md | 2 +- README.md | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e91ad02c..ec1acb09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # Changelog ## UNRELEASED -* Add CIDR-based blocker to prevent e-mail filters (e.g. Cisco Umbrella) from invalidating a login link +* Add CIDR-based blocker (configurable per client) to prevent e-mail filters (e.g. Cisco Umbrella) from invalidating a login link ## 1.0.0 * Add env MYSQL_CA_CERT for MySQL SSL connection diff --git a/README.md b/README.md index 793725e6..2c587162 100644 --- a/README.md +++ b/README.md @@ -128,3 +128,18 @@ By default the required fields have labels as defined in `config/user.js`. These ## MySQL with SSL When you want to connect to a MySQL server using SSL, a Certificate Authority certificate is required. The contents of this CA certificate can be passed into the `MYSQL_CA_CERT` environment variable. + +## Block CIDRs from invalidating the login e-mail link +In some cases, e-mail filters (such as Cisco Umbrella) will invalidate the login e-mail link, because all links are visited by the filter. +To combat this, the Cisco Umbrella CIDRs are blocked by default from visiting the `/auth/url/authenticate` route. + +If you need to add other CIDRs to this block, this can be done on a per client basis through the `clients` table under the `config` column: + +``` +"blockCidrs": [ + "1.2.3.4/16", + "4.4.4.4/16" +] +``` + +Note: When adding your own `blockCidrs` like this, the default Cisco umbrella CIDRs will be overwritten.