Skip to content
Snippets Groups Projects
Commit 206e2553 authored by Marcos Spessatto Defendi's avatar Marcos Spessatto Defendi Committed by Rodrigo Nascimento
Browse files

[NEW] Add permission to enable personal access token to specific roles (#12309)

* Add permission to enable personal access token to specific roles

* Update v136.js

* Update v136.js
parent dc70e803
No related branches found
No related tags found
No related merge requests found
Showing
with 36 additions and 48 deletions
...@@ -12,7 +12,7 @@ const PersonalAccessTokens = new Mongo.Collection('personal_access_tokens'); ...@@ -12,7 +12,7 @@ const PersonalAccessTokens = new Mongo.Collection('personal_access_tokens');
Template.accountTokens.helpers({ Template.accountTokens.helpers({
isAllowed() { isAllowed() {
return RocketChat.settings.get('API_Enable_Personal_Access_Tokens'); return RocketChat.authz.hasAllPermission(['create-personal-access-tokens']);
}, },
tokens() { tokens() {
return (PersonalAccessTokens.find({}).fetch()[0] && PersonalAccessTokens.find({}).fetch()[0].tokens) || []; return (PersonalAccessTokens.find({}).fetch()[0] && PersonalAccessTokens.find({}).fetch()[0].tokens) || [];
...@@ -46,7 +46,7 @@ Template.accountTokens.events({ ...@@ -46,7 +46,7 @@ Template.accountTokens.events({
return toastr.error(t(error.error)); return toastr.error(t(error.error));
} }
showSuccessModal(token); showSuccessModal(token);
instance.find('#input-token-name').value = ''; instance.find('#tokenName').value = '';
}); });
}, },
'click .remove-personal-access-token'() { 'click .remove-personal-access-token'() {
......
...@@ -7,8 +7,8 @@ Meteor.methods({ ...@@ -7,8 +7,8 @@ Meteor.methods({
if (!Meteor.userId()) { if (!Meteor.userId()) {
throw new Meteor.Error('not-authorized', 'Not Authorized', { method: 'personalAccessTokens:generateToken' }); throw new Meteor.Error('not-authorized', 'Not Authorized', { method: 'personalAccessTokens:generateToken' });
} }
if (!RocketChat.settings.get('API_Enable_Personal_Access_Tokens')) { if (!RocketChat.authz.hasPermission(Meteor.userId(), 'create-personal-access-tokens')) {
throw new Meteor.Error('error-personal-access-tokens-are-current-disabled', 'Personal Access Tokens are currently disabled', { method: 'personalAccessTokens:generateToken' }); throw new Meteor.Error('not-authorized', 'Not Authorized', { method: 'personalAccessTokens:generateToken' });
} }
const token = Random.secret(); const token = Random.secret();
......
...@@ -5,8 +5,8 @@ Meteor.methods({ ...@@ -5,8 +5,8 @@ Meteor.methods({
if (!Meteor.userId()) { if (!Meteor.userId()) {
throw new Meteor.Error('not-authorized', 'Not Authorized', { method: 'personalAccessTokens:regenerateToken' }); throw new Meteor.Error('not-authorized', 'Not Authorized', { method: 'personalAccessTokens:regenerateToken' });
} }
if (!RocketChat.settings.get('API_Enable_Personal_Access_Tokens')) { if (!RocketChat.authz.hasPermission(Meteor.userId(), 'create-personal-access-tokens')) {
throw new Meteor.Error('error-personal-access-tokens-are-current-disabled', 'Personal Access Tokens are currently disabled', { method: 'personalAccessTokens:regenerateToken' }); throw new Meteor.Error('not-authorized', 'Not Authorized', { method: 'personalAccessTokens:regenerateToken' });
} }
const tokenExist = RocketChat.models.Users.findPersonalAccessTokenByTokenNameAndUserId({ const tokenExist = RocketChat.models.Users.findPersonalAccessTokenByTokenNameAndUserId({
......
...@@ -5,8 +5,8 @@ Meteor.methods({ ...@@ -5,8 +5,8 @@ Meteor.methods({
if (!Meteor.userId()) { if (!Meteor.userId()) {
throw new Meteor.Error('not-authorized', 'Not Authorized', { method: 'personalAccessTokens:removeToken' }); throw new Meteor.Error('not-authorized', 'Not Authorized', { method: 'personalAccessTokens:removeToken' });
} }
if (!RocketChat.settings.get('API_Enable_Personal_Access_Tokens')) { if (!RocketChat.authz.hasPermission(Meteor.userId(), 'create-personal-access-tokens')) {
throw new Meteor.Error('error-personal-access-tokens-are-current-disabled', 'Personal Access Tokens are currently disabled', { method: 'personalAccessTokens:removeToken' }); throw new Meteor.Error('not-authorized', 'Not Authorized', { method: 'personalAccessTokens:removeToken' });
} }
const tokenExist = RocketChat.models.Users.findPersonalAccessTokenByTokenNameAndUserId({ const tokenExist = RocketChat.models.Users.findPersonalAccessTokenByTokenNameAndUserId({
userId: Meteor.userId(), userId: Meteor.userId(),
......
import './api/methods'; import './api/methods';
import './settings';
import './models'; import './models';
import './publications'; import './publications';
......
...@@ -4,7 +4,7 @@ Meteor.publish('personalAccessTokens', function() { ...@@ -4,7 +4,7 @@ Meteor.publish('personalAccessTokens', function() {
if (!this.userId) { if (!this.userId) {
return this.ready(); return this.ready();
} }
if (!RocketChat.settings.get('API_Enable_Personal_Access_Tokens')) { if (!RocketChat.authz.hasPermission(this.userId, 'create-personal-access-tokens')) {
return this.ready(); return this.ready();
} }
const self = this; const self = this;
......
RocketChat.settings.addGroup('General', function() {
this.section('REST API', function() {
this.add('API_Enable_Personal_Access_Tokens', false, { type: 'boolean', public: true });
});
});
...@@ -498,8 +498,8 @@ RocketChat.API.v1.addRoute('users.regeneratePersonalAccessToken', { authRequired ...@@ -498,8 +498,8 @@ RocketChat.API.v1.addRoute('users.regeneratePersonalAccessToken', { authRequired
RocketChat.API.v1.addRoute('users.getPersonalAccessTokens', { authRequired: true }, { RocketChat.API.v1.addRoute('users.getPersonalAccessTokens', { authRequired: true }, {
get() { get() {
if (!RocketChat.settings.get('API_Enable_Personal_Access_Tokens')) { if (!RocketChat.authz.hasPermission(this.userId, 'create-personal-access-tokens')) {
throw new Meteor.Error('error-personal-access-tokens-are-current-disabled', 'Personal Access Tokens are currently disabled'); throw new Meteor.Error('not-authorized', 'Not Authorized');
} }
const loginTokens = RocketChat.models.Users.getLoginTokensByUserId(this.userId).fetch()[0]; const loginTokens = RocketChat.models.Users.getLoginTokensByUserId(this.userId).fetch()[0];
const getPersonalAccessTokens = () => loginTokens.services.resume.loginTokens const getPersonalAccessTokens = () => loginTokens.services.resume.loginTokens
......
...@@ -21,6 +21,7 @@ Meteor.startup(function() { ...@@ -21,6 +21,7 @@ Meteor.startup(function() {
{ _id: 'create-c', roles : ['admin', 'user', 'bot'] }, { _id: 'create-c', roles : ['admin', 'user', 'bot'] },
{ _id: 'create-d', roles : ['admin', 'user', 'bot'] }, { _id: 'create-d', roles : ['admin', 'user', 'bot'] },
{ _id: 'create-p', roles : ['admin', 'user', 'bot'] }, { _id: 'create-p', roles : ['admin', 'user', 'bot'] },
{ _id: 'create-personal-access-tokens', roles : ['admin', 'user'] },
{ _id: 'create-user', roles : ['admin'] }, { _id: 'create-user', roles : ['admin'] },
{ _id: 'clean-channel-history', roles : ['admin'] }, { _id: 'clean-channel-history', roles : ['admin'] },
{ _id: 'delete-c', roles : ['admin', 'owner'] }, { _id: 'delete-c', roles : ['admin', 'owner'] },
......
...@@ -278,8 +278,6 @@ ...@@ -278,8 +278,6 @@
"API_Enable_CORS": "Enable CORS", "API_Enable_CORS": "Enable CORS",
"API_Enable_Direct_Message_History_EndPoint": "Enable Direct Message History Endpoint", "API_Enable_Direct_Message_History_EndPoint": "Enable Direct Message History Endpoint",
"API_Enable_Direct_Message_History_EndPoint_Description": "This enables the `/api/v1/im.history.others` which allows the viewing of direct messages sent by other users that the caller is not part of.", "API_Enable_Direct_Message_History_EndPoint_Description": "This enables the `/api/v1/im.history.others` which allows the viewing of direct messages sent by other users that the caller is not part of.",
"API_Enable_Personal_Access_Tokens": "Enable Personal Access Tokens to REST API",
"API_Enable_Personal_Access_Tokens_Description": "Enable personal access tokens for use with the REST API",
"API_Enable_Shields": "Enable Shields", "API_Enable_Shields": "Enable Shields",
"API_Enable_Shields_Description": "Enable shields available at `/api/v1/shield.svg`", "API_Enable_Shields_Description": "Enable shields available at `/api/v1/shield.svg`",
"API_GitHub_Enterprise_URL": "Server URL", "API_GitHub_Enterprise_URL": "Server URL",
......
...@@ -15,7 +15,7 @@ Template.accountFlex.helpers({ ...@@ -15,7 +15,7 @@ Template.accountFlex.helpers({
return RocketChat.settings.get('Accounts_AllowUserProfileChange'); return RocketChat.settings.get('Accounts_AllowUserProfileChange');
}, },
accessTokensEnabled() { accessTokensEnabled() {
return RocketChat.settings.get('API_Enable_Personal_Access_Tokens'); return RocketChat.authz.hasAllPermission(['create-personal-access-tokens']);
}, },
encryptionEnabled() { encryptionEnabled() {
return RocketChat.settings.get('E2E_Enable'); return RocketChat.settings.get('E2E_Enable');
......
RocketChat.Migrations.add({
version: 136,
up() {
const personalTokensEnabled = RocketChat.settings.get('API_Enable_Personal_Access_Tokens');
const roles = RocketChat.models.Roles.find({ scope: 'Users' }).fetch().map((role) => role._id);
if (personalTokensEnabled) {
RocketChat.models.Permissions.upsert({ _id: 'create-personal-access-tokens' }, { $set: { roles } });
}
RocketChat.models.Settings.remove({
_id: 'API_Enable_Personal_Access_Tokens',
});
},
});
...@@ -1247,17 +1247,7 @@ describe('[Users]', function() { ...@@ -1247,17 +1247,7 @@ describe('[Users]', function() {
describe('Personal Access Tokens', () => { describe('Personal Access Tokens', () => {
const tokenName = `${ Date.now() }token`; const tokenName = `${ Date.now() }token`;
describe('successful cases', () => { describe('successful cases', () => {
it('Enable "API_Enable_Personal_Access_Tokens" setting...', (done) => { it('Grant necessary permission "create-personal-accss-tokens" to user', (done) => updatePermission('create-personal-access-tokens', ['admin']).then(done));
request.post('/api/v1/settings/API_Enable_Personal_Access_Tokens')
.set(credentials)
.send({ value: true })
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
})
.end(done);
});
describe('[/users.generatePersonalAccessToken]', () => { describe('[/users.generatePersonalAccessToken]', () => {
it('should return a personal access token to user', (done) => { it('should return a personal access token to user', (done) => {
request.post(api('users.generatePersonalAccessToken')) request.post(api('users.generatePersonalAccessToken'))
...@@ -1359,18 +1349,8 @@ describe('[Users]', function() { ...@@ -1359,18 +1349,8 @@ describe('[Users]', function() {
}); });
}); });
describe('unsuccessful cases', () => { describe('unsuccessful cases', () => {
it('disable "API_Enable_Personal_Access_Tokens" setting...', (done) => { it('Remove necessary permission "create-personal-accss-tokens" to user', (done) => updatePermission('create-personal-access-tokens', []).then(done));
request.post('/api/v1/settings/API_Enable_Personal_Access_Tokens') describe('should return an error when the user dont have the necessary permission "create-personal-access-tokens"', () => {
.set(credentials)
.send({ value: false })
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
})
.end(done);
});
describe('should return an error when setting "API_Enable_Personal_Access_Tokens" is disabled for the following routes', () => {
it('/users.generatePersonalAccessToken', (done) => { it('/users.generatePersonalAccessToken', (done) => {
request.post(api('users.generatePersonalAccessToken')) request.post(api('users.generatePersonalAccessToken'))
.set(credentials) .set(credentials)
...@@ -1381,7 +1361,7 @@ describe('[Users]', function() { ...@@ -1381,7 +1361,7 @@ describe('[Users]', function() {
.expect(400) .expect(400)
.expect((res) => { .expect((res) => {
expect(res.body).to.have.property('success', false); expect(res.body).to.have.property('success', false);
expect(res.body.errorType).to.be.equal('error-personal-access-tokens-are-current-disabled'); expect(res.body.errorType).to.be.equal('not-authorized');
}) })
.end(done); .end(done);
}); });
...@@ -1395,7 +1375,7 @@ describe('[Users]', function() { ...@@ -1395,7 +1375,7 @@ describe('[Users]', function() {
.expect(400) .expect(400)
.expect((res) => { .expect((res) => {
expect(res.body).to.have.property('success', false); expect(res.body).to.have.property('success', false);
expect(res.body.errorType).to.be.equal('error-personal-access-tokens-are-current-disabled'); expect(res.body.errorType).to.be.equal('not-authorized');
}) })
.end(done); .end(done);
}); });
...@@ -1406,7 +1386,7 @@ describe('[Users]', function() { ...@@ -1406,7 +1386,7 @@ describe('[Users]', function() {
.expect(400) .expect(400)
.expect((res) => { .expect((res) => {
expect(res.body).to.have.property('success', false); expect(res.body).to.have.property('success', false);
expect(res.body.errorType).to.be.equal('error-personal-access-tokens-are-current-disabled'); expect(res.body.errorType).to.be.equal('not-authorized');
}) })
.end(done); .end(done);
}); });
...@@ -1420,7 +1400,7 @@ describe('[Users]', function() { ...@@ -1420,7 +1400,7 @@ describe('[Users]', function() {
.expect(400) .expect(400)
.expect((res) => { .expect((res) => {
expect(res.body).to.have.property('success', false); expect(res.body).to.have.property('success', false);
expect(res.body.errorType).to.be.equal('error-personal-access-tokens-are-current-disabled'); expect(res.body.errorType).to.be.equal('not-authorized');
}) })
.end(done); .end(done);
}); });
...@@ -1434,7 +1414,7 @@ describe('[Users]', function() { ...@@ -1434,7 +1414,7 @@ describe('[Users]', function() {
.expect(400) .expect(400)
.expect((res) => { .expect((res) => {
expect(res.body).to.have.property('success', false); expect(res.body).to.have.property('success', false);
expect(res.body.errorType).to.be.equal('error-personal-access-tokens-are-current-disabled'); expect(res.body.errorType).to.be.equal('not-authorized');
}) })
.end(done); .end(done);
}); });
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment