Skip to content

[SR] Adjust app permissions#39966

Merged
jen-huang merged 6 commits intoelastic:masterfrom
jen-huang:fix/sr-permissions
Jul 1, 2019
Merged

[SR] Adjust app permissions#39966
jen-huang merged 6 commits intoelastic:masterfrom
jen-huang:fix/sr-permissions

Conversation

@jen-huang
Copy link
Copy Markdown
Contributor

@jen-huang jen-huang commented Jun 28, 2019

Summary

This PR adjusts the app permissions for Snapshot and Restore to reflect additional features done in #39193.

Overall app permissions now need these cluster privileges because the UI now supports additional actions with snapshots (as opposed to readonly view):

[
  'cluster:admin/snapshot',
  'cluster:admin/repository',
]

An index privilege is now also checked, monitor. Not having this privilege on at least one index will not block the user's access to the app, but will block the Restore Status content from being shown. Prior to this PR, the UX was not very nice:

image


Testing

This PR can be tested by creating a new user role (and a user who uses that role plus kibana_user) and adjusting its privileges to see the various UX changes:

Missing cluster privilege, no app access

POST _security/role/sr_user
{
  "cluster": ["cluster:admin/repository"]
}

image

Missing index privilege, app access but no Recovery Status access

POST _security/role/sr_user
{
  "cluster": ["cluster:admin/repository", "cluster:admin/snapshot"]
}

image

Some indices privilege, app access and Recovery Status access for just those indices

POST _security/role/sr_user
{
  "cluster": ["cluster:admin/repository", "cluster:admin/snapshot"],
  "index" : [
    {
      "names": ["logstash-1", "logstash-2"],
      "privileges": ["monitor"]
    }
  ]
}

image

All indices privilege (or superuser), app access and full Recovery Status access

POST _security/role/sr_user
{
  "cluster": ["cluster:admin/repository", "cluster:admin/snapshot"],
  "index" : [
    {
      "names": ["*"],
      "privileges": ["monitor"]
    }
  ]
}

image

@jen-huang jen-huang added Team:Kibana Management Dev Tools, Index Management, Upgrade Assistant, ILM, Ingest Node Pipelines, and more t// release_note:skip Skip the PR/issue when compiling release notes Feature:Snapshot and Restore Elasticsearch snapshots and repositories UI v7.3.0 v7.4.0 labels Jun 28, 2019
@elasticmachine
Copy link
Copy Markdown
Contributor

Pinging @elastic/es-ui

@jen-huang jen-huang added v8.0.0 and removed v7.4.0 labels Jun 28, 2019
// Update app state with permissions data
useEffect(
() => {
dispatch({
Copy link
Copy Markdown
Contributor Author

@jen-huang jen-huang Jun 28, 2019

Choose a reason for hiding this comment

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

@elastic/es-ui
I think permissions is a good candidate for the type of data that should be stored in React context. Here, the permissions are fetched when the app mounts and I dispatch the resulting data into the app state so that other components can access it without having to send another request to get permissions info. This can let us get really granular with the way the UI behaves at different permission levels. I've only used it in one section of this app for now, but it would be relatively easy to check for more granular permissions and disable buttons such as Delete and Restore.
What do you think?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Agreed @jen-huang. And should be a reusable solution across our apps. Once the Provider wraps the app, I see something like this in our components

import { Authorize } from 'plugins/our_shared_es_ui_plugin/permissions';

const SomeComponent = () => (
  <Authorize role="someRole">
    <EuiButton>Only visible to users with enough privileges</EuiButton>
  </Authorize>
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think permissions is a good candidate for the type of data that should be stored in React context.

Yes, I agree. I think a compelling rationale is also that this lets us design the app so that users are free to navigate throughout it while the permissions request is still resolving. As you pointed out, discrete parts of the app will be gated on permissions. These specific parts of the UI can show a spinner while the user uses the parts of the app that are not gated on permissions.

EDIT: I re-read your comment and it sounds like maybe we're saying the same thing in different ways. :)

@elasticmachine
Copy link
Copy Markdown
Contributor

💔 Build Failed

@elasticmachine
Copy link
Copy Markdown
Contributor

💚 Build Succeeded

@elasticmachine
Copy link
Copy Markdown
Contributor

💔 Build Failed

@jen-huang
Copy link
Copy Markdown
Contributor Author

Retest

@elasticmachine
Copy link
Copy Markdown
Contributor

💚 Build Succeeded

Copy link
Copy Markdown
Contributor

@cjcenizal cjcenizal left a comment

Choose a reason for hiding this comment

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

Tested locally, code LGTM! I found a few typos and had a suggestion for making some code easier to follow.

};

export const APP_PERMISSIONS = ['create_snapshot', 'cluster:admin/repository'];
export const APP_REQUIRED_CLUSTER_PRIVILAGES = [
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Typo nit in a few places: PRIVILAGES -> PRIVILEGES

// Update app state with permissions data
useEffect(
() => {
dispatch({
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think permissions is a good candidate for the type of data that should be stored in React context.

Yes, I agree. I think a compelling rationale is also that this lets us design the app so that users are free to navigate throughout it while the permissions request is still resolving. As you pointed out, discrete parts of the app will be gated on permissions. These specific parts of the UI can show a spinner while the user uses the parts of the app that are not gated on permissions.

EDIT: I re-read your comment and it sounds like maybe we're saying the same thing in different ways. :)

method: 'GET',
});

// Check if they have at the required index privilages for at least one index
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

privilages -> privileges

As a side note, the more I read this word, this more it looks wrong to me!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

privileges doesn't feel like a real word to me any more 😆

method: 'GET',
});

// Check if they have at the required index privilages for at least one index
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

typo: at -> all?

const oneIndexWithAllPrivileges = indices.find(({ privileges }: { privileges: string[] }) => {
return (
privileges.includes('all') ||
APP_RESTORE_INDEX_PRIVILAGES.filter(privilage => !privileges.includes(privilage)).length === 0
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I had to read through this a few times to figure out the logic. Could we extract this condition and add a variable to communicate meaning? Here's my suggestion, it's a couple more lines but I find it easier to understand. (Warning, I haven't tested it!)

  // Check if they have all the required index privilages for at least one index
  const hasIndexWithRestorePrivileges = indices.find(({ privileges }: { privileges: string[] }) => {
    if (privileges.includes('all')) {
      return true;
    }
    
    const indexHasRestorePrivileges = APP_RESTORE_INDEX_PRIVILEGES.every(restorePrivilege => privileges.includes(restorePrivilege));
    return indexHasRestorePrivileges;
  });

I know we could eliminate a line by getting rid of the indexHasRestorePrivileges variable, but its name makes it so much easier for me to follow the logic. :)

@elasticmachine
Copy link
Copy Markdown
Contributor

💚 Build Succeeded

@jen-huang jen-huang merged commit f60b536 into elastic:master Jul 1, 2019
@jen-huang jen-huang deleted the fix/sr-permissions branch July 1, 2019 21:41
jen-huang added a commit to jen-huang/kibana that referenced this pull request Jul 1, 2019
* Adjust SR app permissions for new features

* Fix app state and reducer typings

* Fix i18n key

* Fix typos

* Make logic more clear
jen-huang added a commit that referenced this pull request Jul 1, 2019
* Adjust SR app permissions for new features

* Fix app state and reducer typings

* Fix i18n key

* Fix typos

* Make logic more clear
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature:Snapshot and Restore Elasticsearch snapshots and repositories UI release_note:skip Skip the PR/issue when compiling release notes Team:Kibana Management Dev Tools, Index Management, Upgrade Assistant, ILM, Ingest Node Pipelines, and more t// v7.3.0 v8.0.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants