Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added /gitops-graphql - replaced appAuth with componentAuth #473

Merged
merged 2 commits into from
Dec 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .env-cmdrc-template
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"SWITCHER_API_DOMAIN": "MOCK_SWITCHER_API_DOMAIN",
"SWITCHER_API_ENVIRONMENT": "default",

"SWITCHER_SLACK_JWT_SECRET": "MOCK_SWITCHER_SLACK_JWT_SECRET"
"SWITCHER_SLACK_JWT_SECRET": "MOCK_SWITCHER_SLACK_JWT_SECRET",
"SWITCHER_GITOPS_JWT_SECRET": "MOCK_SWITCHER_GITOPS_JWT_SECRET"
}
}
1 change: 1 addition & 0 deletions .github/workflows/master.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ jobs:
JWT_CLIENT_TOKEN_EXP_TIME: 5m
JWT_SECRET: ${{ secrets.JWT_SECRET }}
SWITCHER_SLACK_JWT_SECRET: ${{ secrets.SWITCHER_SLACK_JWT_SECRET }}
SWITCHER_GITOPS_JWT_SECRET: ${{ secrets.SWITCHER_GITOPS_JWT_SECRET }}
GOOGLE_RECAPTCHA_SECRET: ${{ secrets.GOOGLE_RECAPTCHA_SECRET }}
GOOGLE_SKIP_AUTH: false
MAX_STRATEGY_OPERATION: 100
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/re-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ jobs:
JWT_CLIENT_TOKEN_EXP_TIME: 5m
JWT_SECRET: ${{ secrets.JWT_SECRET }}
SWITCHER_SLACK_JWT_SECRET: ${{ secrets.SWITCHER_SLACK_JWT_SECRET }}
SWITCHER_GITOPS_JWT_SECRET: ${{ secrets.SWITCHER_GITOPS_JWT_SECRET }}
GOOGLE_RECAPTCHA_SECRET: ${{ secrets.GOOGLE_RECAPTCHA_SECRET }}
GOOGLE_SKIP_AUTH: false
MAX_STRATEGY_OPERATION: 100
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ jobs:
JWT_CLIENT_TOKEN_EXP_TIME: 5m
JWT_SECRET: ${{ secrets.JWT_SECRET }}
SWITCHER_SLACK_JWT_SECRET: ${{ secrets.SWITCHER_SLACK_JWT_SECRET }}
SWITCHER_GITOPS_JWT_SECRET: ${{ secrets.SWITCHER_GITOPS_JWT_SECRET }}
GOOGLE_RECAPTCHA_SECRET: ${{ secrets.GOOGLE_RECAPTCHA_SECRET }}
GOOGLE_SKIP_AUTH: false
MAX_STRATEGY_OPERATION: 100
Expand Down
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ services:
- SWITCHER_API_ENVIRONMENT=${SWITCHER_API_ENVIRONMENT}

- SWITCHER_SLACK_JWT_SECRET=${SWITCHER_SLACK_JWT_SECRET}
- SWITCHER_GITOPS_JWT_SECRET=${SWITCHER_GITOPS_JWT_SECRET}
depends_on:
- mongodb
volumes:
Expand Down
6 changes: 3 additions & 3 deletions src/api-docs/paths/path-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export default {
post: {
tags: ['Client API'],
description: 'Execute criteria query against the API settings',
security: [{ appAuth: [] }],
security: [{ componentAuth: [] }],
parameters: [
queryParameter('key', 'Switcher Key', true, 'string'),
queryParameter('showReason', 'Show criteria execution reason (default: true)', false, 'boolean'),
Expand Down Expand Up @@ -70,7 +70,7 @@ export default {
get: {
tags: ['Client API'],
description: 'Check if snapshot version is up to date',
security: [{ appAuth: [] }],
security: [{ componentAuth: [] }],
parameters: [
pathParameter('version', 'Snapshot version', true)
],
Expand Down Expand Up @@ -98,7 +98,7 @@ export default {
post: {
tags: ['Client API'],
description: 'Check if switcher keys are valid',
security: [{ appAuth: [] }],
security: [{ componentAuth: [] }],
requestBody: {
content: {
'application/json': {
Expand Down
2 changes: 1 addition & 1 deletion src/api-docs/swagger-document.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export default {
scheme: 'bearer',
bearerFormat: 'JWT'
},
appAuth: {
componentAuth: {
type: 'http',
scheme: 'bearer'
},
Expand Down
6 changes: 4 additions & 2 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import teamRouter from './routers/team';
import permissionRouter from './routers/permission';
import slackRouter from './routers/slack';
import schema from './client/schema';
import { appAuth, auth, resourcesAuth, slackAuth } from './middleware/auth';
import { componentAuth, auth, resourcesAuth, slackAuth, gitopsAuth } from './middleware/auth';
import { clientLimiter, defaultLimiter } from './middleware/limiter';
import { createServer } from './app-server';

Expand Down Expand Up @@ -59,11 +59,13 @@ const handler = (req, res, next) =>
createHandler({ schema, context: req })(req, res, next);

// Component: Client API
app.use('/graphql', appAuth, clientLimiter, handler);
app.use('/graphql', componentAuth, clientLimiter, handler);
// Admin: Client API
app.use('/adm-graphql', auth, defaultLimiter, handler);
// Slack: Client API
app.use('/slack-graphql', slackAuth, handler);
// GitOps: Client API
app.use('/gitops-graphql', gitopsAuth, handler);

/**
* API Docs and Health Check
Expand Down
2 changes: 1 addition & 1 deletion src/client/resolvers.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export async function resolveDomain(_id, name, activated, context) {
} else {
args._id = _id;
}
// When Component
// When Component / GitOps
} else if (context.domain) {
args._id = context.domain;
}
Expand Down
17 changes: 16 additions & 1 deletion src/middleware/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Admin from '../models/admin';
import Component from '../models/component';
import { getRateLimit } from '../external/switcher-api-facade';
import { responseExceptionSilent } from '../exceptions';
import { EnvType } from '../models/environment';

export async function auth(req, res, next) {
try {
Expand Down Expand Up @@ -54,7 +55,7 @@ export async function authRefreshToken(req, res, next) {
}
}

export async function appAuth(req, res, next) {
export async function componentAuth(req, res, next) {
try {
const token = req.header('Authorization').replace('Bearer ', '');
const decoded = jwt.verify(token, process.env.JWT_SECRET);
Expand Down Expand Up @@ -86,6 +87,20 @@ export async function slackAuth(req, res, next) {
}
}

export async function gitopsAuth(req, res, next) {
try {
const token = req.header('Authorization').replace('Bearer ', '');
const decoded = jwt.verify(token, process.env.SWITCHER_GITOPS_JWT_SECRET);

req.token = token;
req.domain = decoded.subject;
req.environment = EnvType.DEFAULT;
next();
} catch (err) {
responseExceptionSilent(res, err, 401, 'Invalid API token.');
}
}

export function resourcesAuth() {
return basicAuth({
users: {
Expand Down
8 changes: 4 additions & 4 deletions src/routers/client-api.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import express from 'express';
import jwt from 'jsonwebtoken';
import { checkConfig, checkConfigComponent, validate } from '../middleware/validators';
import { appAuth, appGenerateCredentials } from '../middleware/auth';
import { componentAuth, appGenerateCredentials } from '../middleware/auth';
import { resolveCriteria, checkDomain } from '../client/resolvers';
import { getConfigs } from '../services/config';
import { body, check, query } from 'express-validator';
Expand All @@ -13,7 +13,7 @@ const router = new express.Router();
// GET /check?key=KEY&showReason=true
// GET /check?key=KEY&showStrategy=true
// GET /check?key=KEY&bypassMetric=true
router.post('/criteria', appAuth, clientLimiter, [
router.post('/criteria', componentAuth, clientLimiter, [
query('key').isLength({ min: 1 }),
body('entry.*.input').isString()
], validate, checkConfig, checkConfigComponent, async (req, res) => {
Expand Down Expand Up @@ -43,7 +43,7 @@ router.post('/criteria', appAuth, clientLimiter, [
}
});

router.get('/criteria/snapshot_check/:version', appAuth, clientLimiter, async (req, res) => {
router.get('/criteria/snapshot_check/:version', componentAuth, clientLimiter, async (req, res) => {
try {
const domain = await checkDomain(req.domain);
const version = req.params.version;
Expand All @@ -62,7 +62,7 @@ router.get('/criteria/snapshot_check/:version', appAuth, clientLimiter, async (r
}
});

router.post('/criteria/switchers_check', appAuth, clientLimiter, [
router.post('/criteria/switchers_check', componentAuth, clientLimiter, [
check('switchers', 'Switcher Key is required').isArray().isLength({ min: 1 })
], validate, async (req, res) => {
try {
Expand Down
49 changes: 49 additions & 0 deletions tests/gitops.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import mongoose from 'mongoose';
import request from 'supertest';
import jwt from 'jsonwebtoken';
import app from '../src/app';
import * as graphqlUtils from './graphql-utils';
import {
setupDatabase,
domainId
} from './fixtures/db_client';

afterAll(async () => {
await new Promise(resolve => setTimeout(resolve, 1000));
await mongoose.disconnect();
});

const generateToken = (expiresIn) => {
return jwt.sign(({
iss: 'GitOps Service',
sub: '/resource',
subject: domainId.toString(),
}), process.env.SWITCHER_GITOPS_JWT_SECRET, {
expiresIn
});
};

describe('GitOps', () => {
beforeAll(setupDatabase);

test('GITOPS_SUITE - Should return snapshot payload from GraphQL API', async () => {
const token = generateToken('30s');
const req = await request(app)
.post('/gitops-graphql')
.set('Authorization', `Bearer ${token}`)
.send(graphqlUtils.domainQuery([['_id', domainId]], true, true, true));

expect(req.statusCode).toBe(200);
expect(JSON.parse(req.text)).toMatchObject(JSON.parse(graphqlUtils.expected102));
});

test('GITOPS_SUITE - Should return error when token is expired', async () => {
const token = generateToken('0s');
const req = await request(app)
.post('/gitops-graphql')
.set('Authorization', `Bearer ${token}`)
.send(graphqlUtils.domainQuery([['_id', domainId]], true, true, true));

expect(req.statusCode).toBe(401);
});
});