Skip to content

feat: Create admin protected endpoint for creating users #981

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
88 changes: 88 additions & 0 deletions packages/git-proxy-cli/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,59 @@
}
}

/**
* Create a new user
* @param {string} username The username for the new user
* @param {string} password The password for the new user
* @param {string} email The email for the new user
* @param {string} gitAccount The git account for the new user
* @param {boolean} [admin=false] Whether the user should be an admin (optional)
*/
async function createUser(username, password, email, gitAccount, admin = false) {
if (!fs.existsSync(GIT_PROXY_COOKIE_FILE)) {
console.error('Error: Create User: Authentication required');
process.exitCode = 1;
return;
}

try {
const cookies = JSON.parse(fs.readFileSync(GIT_PROXY_COOKIE_FILE, 'utf8'));

const response = await axios.post(

Check failure on line 351 in packages/git-proxy-cli/index.js

View workflow job for this annotation

GitHub Actions / Linting

'response' is assigned a value but never used
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Linter issue here:

  351:11  error  'response' is assigned a value but never used  no-unused-vars

`${baseUrl}/api/auth/create-user`,
{
username,
password,
email,
gitAccount,
admin,
},
{
headers: { Cookie: cookies },
},
);

console.log(`User '${username}' created successfully`);
} catch (error) {
let errorMessage = `Error: Create User: '${error.message}'`;
process.exitCode = 2;

if (error.response) {
switch (error.response.status) {
case 401:
errorMessage = 'Error: Create User: Authentication required';
process.exitCode = 3;
break;
case 400:
errorMessage = `Error: Create User: ${error.response.data.message}`;
process.exitCode = 4;
break;
}
}
console.error(errorMessage);
}
}

// Parsing command line arguments
yargs(hideBin(process.argv)) // eslint-disable-line @typescript-eslint/no-unused-expressions
.command({
Expand Down Expand Up @@ -465,6 +518,41 @@
description: 'Reload GitProxy configuration without restarting',
action: reloadConfig,
})
.command({
command: 'create-user',
describe: 'Create a new user',
builder: {
username: {
describe: 'Username for the new user',
demandOption: true,
type: 'string',
},
password: {
describe: 'Password for the new user',
demandOption: true,
type: 'string',
},
email: {
describe: 'Email for the new user',
demandOption: true,
type: 'string',
},
gitAccount: {
describe: 'Git account for the new user',
demandOption: true,
type: 'string',
},
admin: {
describe: 'Whether the user should be an admin (optional)',
demandOption: false,
type: 'boolean',
default: false,
},
},
handler(argv) {
createUser(argv.username, argv.password, argv.email, argv.gitAccount, argv.admin);
},
})
.demandCommand(1, 'You need at least one command before moving on')
.strict()
.help().argv;
108 changes: 108 additions & 0 deletions packages/git-proxy-cli/test/testCli.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,114 @@ describe('test git-proxy-cli', function () {
});
});

// *** create user ***

describe('test git-proxy-cli :: create-user', function () {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These functions fix one of the failing CLI tests:

Suggested change
describe('test git-proxy-cli :: create-user', function () {
describe('test git-proxy-cli :: create-user', function () {
before(async function () {
await helper.addRepoToDb(TEST_REPO_CONFIG);
await helper.addUserToDb('testuser', 'testpassword', '[email protected]', 'testGitAccount1');
});
after(async function () {
await helper.removeRepoFromDb(TEST_REPO_CONFIG.name);
await helper.removeUserFromDb('newuser');
await helper.removeUserFromDb('testuser');
});

it('attempt to create user should fail when server is down', async function () {
try {
// start server -> login -> stop server
await helper.startServer(service);
await helper.runCli(`npx -- @finos/git-proxy-cli login --username admin --password admin`);
} finally {
await helper.closeServer(service.httpServer);
}

const cli = `npx -- @finos/git-proxy-cli create-user --username newuser --password newpass --email [email protected] --gitAccount newgit`;
const expectedExitCode = 2;
const expectedMessages = null;
const expectedErrorMessages = ['Error: Create User:'];
await helper.runCli(cli, expectedExitCode, expectedMessages, expectedErrorMessages);
});

it('attempt to create user should fail when not authenticated', async function () {
await helper.removeCookiesFile();

const cli = `npx -- @finos/git-proxy-cli create-user --username newuser --password newpass --email [email protected] --gitAccount newgit`;
const expectedExitCode = 1;
const expectedMessages = null;
const expectedErrorMessages = ['Error: Create User: Authentication required'];
await helper.runCli(cli, expectedExitCode, expectedMessages, expectedErrorMessages);
});

it('attempt to create user should fail when not admin', async function () {
try {
await helper.startServer(service);
await helper.runCli(
`npx -- @finos/git-proxy-cli login --username testuser --password testpassword`,
);

const cli = `npx -- @finos/git-proxy-cli create-user --username newuser --password newpass --email [email protected] --gitAccount newgit`;
const expectedExitCode = 3;
const expectedMessages = null;
const expectedErrorMessages = ['Error: Create User: Authentication required'];
await helper.runCli(cli, expectedExitCode, expectedMessages, expectedErrorMessages);
} finally {
await helper.closeServer(service.httpServer);
}
});

it('attempt to create user should fail with missing required fields', async function () {
try {
await helper.startServer(service);
await helper.runCli(`npx -- @finos/git-proxy-cli login --username admin --password admin`);

const cli = `npx -- @finos/git-proxy-cli create-user --username newuser --email [email protected] --gitAccount newgit`;
const expectedExitCode = 4;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oddly, this fix didn't get applied previously (will fix the test):

Suggested change
const expectedExitCode = 4;
const expectedExitCode = 1;
const expectedMessages = null;
const expectedErrorMessages = ['Missing required argument: password];

const expectedMessages = null;
const expectedErrorMessages = ['Error: Create User: Missing required fields'];
await helper.runCli(cli, expectedExitCode, expectedMessages, expectedErrorMessages);
} finally {
await helper.closeServer(service.httpServer);
}
});

it('should successfully create a new user', async function () {
try {
await helper.startServer(service);
await helper.runCli(`npx -- @finos/git-proxy-cli login --username admin --password admin`);

const cli = `npx -- @finos/git-proxy-cli create-user --username newuser --password newpass --email [email protected] --gitAccount newgit`;
const expectedExitCode = 0;
const expectedMessages = ["User 'newuser' created successfully"];
const expectedErrorMessages = null;
await helper.runCli(cli, expectedExitCode, expectedMessages, expectedErrorMessages);

// Verify we can login with the new user
await helper.runCli(
`npx -- @finos/git-proxy-cli login --username newuser --password newpass`,
0,
[`Login "newuser" <[email protected]>: OK`],
null,
);
} finally {
await helper.closeServer(service.httpServer);
}
});

it('should successfully create a new admin user', async function () {
try {
await helper.startServer(service);
await helper.runCli(`npx -- @finos/git-proxy-cli login --username admin --password admin`);

const cli = `npx -- @finos/git-proxy-cli create-user --username newadmin --password newpass --email [email protected] --gitAccount newgit --admin`;
const expectedExitCode = 0;
const expectedMessages = ["User 'newadmin' created successfully"];
const expectedErrorMessages = null;
await helper.runCli(cli, expectedExitCode, expectedMessages, expectedErrorMessages);

// Verify we can login with the new admin user
await helper.runCli(
`npx -- @finos/git-proxy-cli login --username newadmin --password newpass`,
0,
[`Login "newadmin" <[email protected]> (admin): OK`],
null,
);
} finally {
await helper.closeServer(service.httpServer);
}
});
});

// *** tests require push in db ***

describe('test git-proxy-cli :: git push administration', function () {
Expand Down
31 changes: 31 additions & 0 deletions src/service/routes/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,37 @@ router.get('/me', async (req, res) => {
}
});

router.post('/create-user', async (req, res) => {
if (!req.user || !req.user.admin) {
return res.status(401).send({
message: 'You are not authorized to perform this action...',
});
}

try {
const { username, password, email, gitAccount, admin: isAdmin = false } = req.body;

if (!username || !password || !email || !gitAccount) {
return res.status(400).send({
message: 'Missing required fields: username, password, email, and gitAccount are required',
});
}

await db.createUser(username, password, email, gitAccount, isAdmin);
res.status(201).send({
message: 'User created successfully',
username,
});
} catch (error) {
console.error('Error creating user:', error);
res.status(400).send({
message: error.message || 'Failed to create user',
});
}
});

module.exports = router;

module.exports = {
router,
loginSuccessHandler
Expand Down
Loading
Loading