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

prevent the last manager from removing manager role #557

Merged
merged 4 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from 3 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
2 changes: 2 additions & 0 deletions packages/apollo/src/assets/i18n/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,8 @@
"tooltip_peer_name": "Enter a peer name. This field is only used to identify the peer in this console.",
"tooltip_msp_id": "This is the organization MSP ID that was specified when the peer was deployed. Get this value from the peer administrator.",
"tooltip_proxy_url": "The gRPC web proxy URL for the peer.",
"only_manager_title": "You are the only Manager",
"only_manager_desc": "As You are the only Manager for this console, you are not allowed to modify your roles",
"edit_tooltip_peer_name": "Modify the name you want to use to refer to this peer in this console.",
"edit_tooltip_msp_id": "Modify the organization MSP ID. This value was specified when the peer was deployed.",
"edit_tooltip_proxy_url": "The gRPC web proxy URL for the peer.",
Expand Down
32 changes: 27 additions & 5 deletions packages/apollo/src/components/Access/Access.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import * as constants from '../../utils/constants';
const SCOPE = 'access';
const Log = new Logger(SCOPE);
let login_interval = null;
let admin_count = 0;

export class Access extends Component {
cName = 'Access';
Expand Down Expand Up @@ -72,6 +73,8 @@ export class Access extends Component {
roles: resp2.users[id].roles,
disabled: true,
});
if (resp2.users[id].roles.includes('manager'))
{ admin_count = admin_count + 1; }
delete resp2.users[id];
break;
}
Expand Down Expand Up @@ -100,6 +103,8 @@ export class Access extends Component {
created: new Date(resp2.users[id].created).toDateString(),
roles: resp2.users[id].roles,
});
if (resp2.users[id].roles.includes('manager'))
{ admin_count = admin_count + 1; }
}

this.props.updateState(SCOPE, {
Expand Down Expand Up @@ -159,11 +164,23 @@ export class Access extends Component {
};

openEditUserModal = user => {
this.props.updateState(SCOPE, {
showAddUserModal: true,
editMode: true,
user: user,
});
if (admin_count < 2 && user.roles.includes('manager'))
{
this.props.updateState(SCOPE, {
showAddUserModal: true,
editMode: true,
user: user,
disableUpdate: true,
});
}
else {
this.props.updateState(SCOPE, {
showAddUserModal: true,
editMode: true,
user: user,
disableUpdate: false,
});
}
};

openResetPasswordModal = user => {
Expand Down Expand Up @@ -452,6 +469,7 @@ export class Access extends Component {
} else {
const emails = data;
this.props.showSuccess(emails.length === 1 ? 'user_add_successful' : 'users_add_successful', { email: emails.join(', ') }, SCOPE);
admin_count = 0;
this.getAuthDetails(true);
}
}}
Expand All @@ -464,8 +482,10 @@ export class Access extends Component {
existingUsers={this.props.all_users.map(details => details.id)}
userDetails={this.props.user}
onClose={this.closeAddUserModal}
disableUpdate={this.props.disableUpdate}
onComplete={email => {
this.props.showSuccess('user_update_successful', { email }, SCOPE);
admin_count = 0;
this.getAuthDetails(true);
}}
/>
Expand Down Expand Up @@ -533,6 +553,7 @@ export class Access extends Component {
this.props.showSuccess((Array.isArray(removedItems) && removedItems.length > 1) ?
'users_removed_successful' : 'user_removed_successful', { email: removedItems.join(', ') }, SCOPE
);
admin_count = 0;
this.getAuthDetails(true);
}
}}
Expand Down Expand Up @@ -655,6 +676,7 @@ const dataProps = {
userInfo: PropTypes.object,
isManager: PropTypes.bool,
isWriter: PropTypes.bool,
disableUpdate: PropTypes.bool,
auth_scheme: PropTypes.string,
user: PropTypes.object,
editMode: PropTypes.bool,
Expand Down
12 changes: 10 additions & 2 deletions packages/apollo/src/components/AddUserModal/AddUserModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import EmailChips from '../EmailChips/EmailChips';
import Form from '../Form/Form';
import ImportantBox from '../ImportantBox/ImportantBox';
import SidePanel from '../SidePanel/SidePanel';
import SidePanelWarning from '../SidePanelWarning/SidePanelWarning';

const SCOPE = 'addUsers';

Expand Down Expand Up @@ -229,7 +230,7 @@ export class AddUserModal extends Component {
}

render = () => {
let disableSubmit = this.props.disableSave || this.props.submitting || !this.props.roles || !this.props.roles.length;
let disableSubmit = this.props.disableSave || this.props.submitting || !this.props.roles || !this.props.roles.length || this.props.disableUpdate;
disableSubmit = this.props.isEditing ? disableSubmit : disableSubmit || !this.props.newUsers || !this.props.newUsers.length;
const disableSubmitApiKey = !this.props.apikey_name || !Array.isArray(this.props.roles) || this.props.roles.length === 0;
const translate = this.props.translate;
Expand Down Expand Up @@ -322,7 +323,13 @@ export class AddUserModal extends Component {
/>
</div>
)}

{this.props.isEditing && this.props.disableUpdate && (
<div className="ibp-error-panel">
<SidePanelWarning title="only_manager_title"
subtitle="only_manager_desc"
/>
</div>
)}
<div className="ibp-auth-settings-roles-title ibp-tooltip-wrap">
<span className="ibp-user-tooltip">
<BlockchainTooltip type="definition"
Expand All @@ -339,6 +346,7 @@ export class AddUserModal extends Component {
className="ibp-auth-settings-role-label"
labelText={translate('manager')}
checked={this.props.roles && this.props.roles.includes('manager')}
disabled={this.props.disableUpdate}
onClick={event => {
this.onChangeRole('manager', event);
}}
Expand Down
38 changes: 32 additions & 6 deletions packages/athena/libs/permissions_lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -224,13 +224,39 @@ module.exports = function (logger, ev, t) {
if (!email) {
input_errors.push('uuid does not exist: ' + encodeURI(uuid));
} else {
settings_doc.access_list[email].roles = lc_roles; // edit the user object
if (settings_doc.access_list[email].roles.includes('manager') && !lc_roles.includes('manager'))
{
let admin_count = 0;
for (let user in settings_doc.access_list) {
if (user.roles.includes('manager'))
Copy link
Contributor

Choose a reason for hiding this comment

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

user isn't what you think it is, its just the key of the access_list object, so its just a string. to get to the properies of that user, it should be:

for (let id in settings_doc.access_list) {
	let user = settings_doc.access_list[id]; 
	if (user && user.roles && user.roles.includes('manager')) {
			admin_count = admin_count + 1;
	}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@dshuffma-ibm , I have updated the code as mentioned

{
admin_count = admin_count + 1;
}
}
if (admin_count < 2)
{
input_errors.push('[only manager] as you are the only manager for this console, you are not allowed to modify your roles');
}
else {
settings_doc.access_list[email].roles = lc_roles; // edit the user object

// build a notification doc
const notice = {
message: 'editing roles for user ' + t.misc.censorEmail(email) + ' - setting ' + lc_roles.join(', '),
};
t.notifications.procrastinate(req, notice);
}
}
else
{
settings_doc.access_list[email].roles = lc_roles; // edit the user object

// build a notification doc
const notice = {
message: 'editing roles for user ' + t.misc.censorEmail(email) + ' - setting ' + lc_roles.join(', '),
};
t.notifications.procrastinate(req, notice);
// build a notification doc
const notice = {
message: 'editing roles for user ' + t.misc.censorEmail(email) + ' - setting ' + lc_roles.join(', '),
};
t.notifications.procrastinate(req, notice);
}
}
}

Expand Down
Loading