Skip to content

Commit

Permalink
Added AWS config and identity store (#2208)
Browse files Browse the repository at this point in the history
* aws setup

* lint-fix

* fixed linting issues

* Removed the flow to take credentials from .aws folder in local

* resolving merge conflicts

* added unit tests for the code

* aws setup

* Revert "aws setup"

This reverts commit e447b63.

* added integration tests

* refactored the route and removed console log

* updated the integration tests and added fixture

* changes
1. Fixed all integration tests
2. changed error status to 400
3. removed unnessary code:

* resolving PR comments

* resolving PR comments

* Fixed test cases and added test case for User not found case

* added feature flag to backend API and updated test cases

* Changes
1. changed route to /aws/groups/access
2. refactored code

* code refactor and removed one comment

* Returning the error response to the user

* refactored the condition

---------

Co-authored-by: Achintya Chatterjee <[email protected]>
Co-authored-by: Prakash Choudhary <[email protected]>
  • Loading branch information
3 people authored Nov 16, 2024
1 parent 1060bea commit 75f22dd
Show file tree
Hide file tree
Showing 14 changed files with 1,379 additions and 5 deletions.
16 changes: 16 additions & 0 deletions config/custom-environment-variables.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,22 @@ module.exports = {
__name: "PORT",
__format: "number",
},

aws: {
region: {
__name: "AWS_REGION",
},
access_key: {
__name: "AWS_ACCESS_KEY",
},
secret_key: {
__name: "AWS_SECRET_KEY",
},
identity_store_id: {
__name: "IDENTITY_STORE_ID",
},
},

enableFileLogs: {
__name: "ENABLE_FILE_LOGS",
__format: "boolean",
Expand Down
7 changes: 7 additions & 0 deletions config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ module.exports = {
org: "Real-Dev-Squad",
},

aws: {
region: "<aws-region>",
access_key: "<aws-access-key>",
secret_key: "<aws-secret-key>",
identity_store_id: "<identity-store-id>",
},

githubOauth: {
clientId: "<clientId>",
clientSecret: "<clientSecret>",
Expand Down
2 changes: 2 additions & 0 deletions constants/urls.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export const GITHUB_URL = "https://github.com";
export const PROFILE_SVC_GITHUB_URL = "https://github.com/Real-Dev-Squad/sample-profile-service";

module.exports = {
GITHUB_URL,
PROFILE_SVC_GITHUB_URL,
};
2 changes: 1 addition & 1 deletion constants/userDataLevels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const ACCESS_LEVEL = {

const ROLE_LEVEL = {
private: ["super_user"],
internal: ["super_user"],
internal: ["super_user", "cloudfare_worker"],
confidential: ["super_user"],
};

Expand Down
46 changes: 46 additions & 0 deletions controllers/awsAccess.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { PROFILE_SVC_GITHUB_URL } from "../constants/urls";
import {addUserToGroup, createUser, fetchAwsUserIdByUsername} from "../utils/awsFunctions";
const dataAccess = require("../services/dataAccessLayer");
const userDataLevels = require('../constants/userDataLevels');

export const addUserToAWSGroup = async (req, res) => {
const { groupId, userId } = req.body;

try {
const userInfoData = await dataAccess.retrieveUsers({ discordId: userId, level: userDataLevels.ACCESS_LEVEL.INTERNAL, role: 'cloudfare_worker'});
if (!userInfoData.userExists) {
return res.status(400).json({ error: "User not found" });
} else if(!userInfoData.user.email) {
return res.status(400).json({ error: `User email is required to create an AWS user. Please update your email by setting up Profile service, url : ${PROFILE_SVC_GITHUB_URL}` });
}

let awsUserId = await fetchAwsUserIdByUsername(userInfoData.user.username);

let userCreationResponse = null;

if (awsUserId === null){
// We need to create the user in AWS before and then fetch its Id
userCreationResponse = await createUser(userInfoData.user.username, userInfoData.user.email);
awsUserId = userCreationResponse.UserId;
}

let userAdditionResponse = await addUserToGroup(groupId, awsUserId)

if (userAdditionResponse){
if (userAdditionResponse.conflict){
return res.status(200).json({
message: `User ${userId} is already part of the AWS group, please try signing in.`
})
} else {
return res.status(200).json({
message: `User ${userId} successfully added to group ${groupId}.`
});
}
}
} catch (error) {
logger.error(`Error in adding user - ${userId} to AWS group - ${groupId} error - ${error}`);
return res.status(500).json({
error: `Something went wrong, please try again`
});
}
};
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"tdd:watch": "sh scripts/tests/tdd.sh"
},
"dependencies": {
"@aws-sdk/client-identitystore": "^3.665.0",
"@types/nodemailer": "^6.4.15",
"axios": "1.7.2",
"cloudinary": "2.0.3",
Expand Down
8 changes: 8 additions & 0 deletions routes/awsAccess.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import express from "express"
import { addUserToAWSGroup } from "../controllers/awsAccess";
const router = express.Router();
const { verifyDiscordBot } = require("../middlewares/authorizeBot");

router.post("/access", verifyDiscordBot, addUserToAWSGroup);

module.exports = router;
1 change: 1 addition & 0 deletions routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import express from "express";
const app = express.Router();
import { devFlagMiddleware } from "../middlewares/devFlag";

app.use("/aws/groups", devFlagMiddleware, require("./awsAccess"))
app.use("/answers", require("./answers"));
app.use("/auctions", require("./auctions"));
app.use("/arts", require("./arts"));
Expand Down
7 changes: 7 additions & 0 deletions test/config/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ module.exports = {
clientId: "clientId",
clientSecret: "clientSecret",
},
aws: {
region: "us-east-1",
access_key: "test-access-key",
secret_key: "test-secret-key",
identity_store_id: "test-identity-store-id",
},

firestore: `{
"type": "service_account",
"project_id": "test-project-id-for-emulator",
Expand Down
1 change: 0 additions & 1 deletion test/fixtures/user/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ module.exports = () => {
twitter_id: "whatifi",
discordJoinedAt: "2023-04-06T01:47:34.488000+00:00",
phone: "1234567891",
email: "[email protected]",
picture: {
publicId: "profile/mtS4DhUvNYsKqI7oCWVB/aenklfhtjldc5ytei3ar",
url: "https://res.cloudinary.com/realdevsquad/image/upload/v1667685133/profile/mtS4DhUvNYsKqI7oCWVB/aenklfhtjldc5ytei3ar.jpg",
Expand Down
149 changes: 149 additions & 0 deletions test/integration/awsAccess.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import chai, {expect} from "chai";
import sinon from 'sinon';
import chaiHttp from 'chai-http';
import * as awsFunctions from '../../utils/awsFunctions';
import bot from "../utils/generateBotToken";
import { PROFILE_SVC_GITHUB_URL } from '../../constants/urls';

const app = require("../../server");
const userData = require("../fixtures/user/user")();
const authorizeBot = require("../../middlewares/authorizeBot");
const addUser = require("../utils/addUser");
const cleanDb = require("../utils/cleanDb");
const { CLOUDFLARE_WORKER } = require("../../constants/bot")

chai.use(chaiHttp);

describe('addUserToAWSGroup', function(){
let req: any;
const AWS_ACCESS_API_URL = `/aws/groups/access?dev=true`

beforeEach(async () => {
await addUser(userData[0]);
await addUser(userData[1]);
sinon.restore();
req = {
headers: {},
};
const jwtToken = bot.generateToken({ name: CLOUDFLARE_WORKER });
req.headers.authorization = `Bearer ${jwtToken}`;
})

afterEach(async () => {
await cleanDb();
});

it('should return 400 and user not found with wrong discord Id passed', function(done){
const res = chai
.request(app)
.post(AWS_ACCESS_API_URL)
.set('Authorization', req.headers.authorization)
.send({
groupId: 'test-group-id',
userId: '3000230293'
})
.end((err, res) => {
if (err) {
return done(err);
}
expect(res.status).to.be.equal(400);
expect(res.body).to.have.property('error')
.that.equals(`User not found`);
return done();
})
});

it('should return 400 when user email is missing', function(done) {
const res = chai
.request(app)
.post(AWS_ACCESS_API_URL)
.set('Authorization', req.headers.authorization)
.send({
groupId: 'test-group-id',
userId: '1234567890'
})
.end((err, res) => {
if (err) {
return done(err);
}
expect(res.status).to.be.equal(400);
expect(res.body).to.have.property('error')
.that.equals(`User email is required to create an AWS user. Please update your email by setting up Profile service, url : ${PROFILE_SVC_GITHUB_URL}`);
return done();
});
});


it("Should create user and add to group, if the user is not present in AWS already", function(done){
sinon.stub(awsFunctions, "createUser").resolves({ UserId: "new-aws-user-id" });
sinon.stub(awsFunctions, "addUserToGroup").resolves({ conflict: false });
sinon.stub(awsFunctions, "fetchAwsUserIdByUsername").resolves(null);

const res = chai
.request(app)
.post(AWS_ACCESS_API_URL)
.set('Authorization', req.headers.authorization)
.send({
groupId: 'test-group-id',
userId: '12345'
})
.end((err, res) => {
if (err) {
return done(err);
}
expect(res.status).to.be.equal(200);
expect(res.body).to.have.property('message',
`User 12345 successfully added to group test-group-id.`
);
return done();
});
});

it("Should add the user to the group if the user is already part of AWS account", function(done){
sinon.stub(awsFunctions, "addUserToGroup").resolves({ conflict: false });
sinon.stub(awsFunctions, "fetchAwsUserIdByUsername").resolves("existing-user-id-123");

const res = chai
.request(app)
.post(AWS_ACCESS_API_URL)
.set('Authorization', req.headers.authorization)
.send({
groupId: 'test-group-id',
userId: '12345'
})
.end((err, res) => {
if (err) {
return done(err);
}
expect(res.status).to.be.equal(200)
expect(res.body).to.have.property('message',
'User 12345 successfully added to group test-group-id.'
);
return done();
});
});

it("Should return the signin URL if the user is already added to the group", function(done) {
sinon.stub(awsFunctions, "addUserToGroup").resolves({ conflict: true });
sinon.stub(awsFunctions, "fetchAwsUserIdByUsername").resolves("existing-user-id-123");

const res = chai
.request(app)
.post(AWS_ACCESS_API_URL)
.set('Authorization', req.headers.authorization)
.send({
groupId: 'test-group-id',
userId: '12345'
})
.end((err, res) => {
if (err) {
return done(err);
}
expect(res.status).to.be.equal(200);
expect(res.body).to.have.property('message',
'User 12345 is already part of the AWS group, please try signing in.'
);
return done();
});
});
});
Loading

0 comments on commit 75f22dd

Please sign in to comment.