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

Show/Hide apps programmatically from plugin #10286

Closed
sscarduzio opened this issue Feb 10, 2017 · 23 comments
Closed

Show/Hide apps programmatically from plugin #10286

sscarduzio opened this issue Feb 10, 2017 · 23 comments
Labels
enhancement New value added to drive a business result stale Used to mark issues that were closed for being stale Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc

Comments

@sscarduzio
Copy link

I'm trying to write a Kibana plugin that implements role based access control, in which Kibana apps represent the resources users will have permissions to use (or not).

How can I programmatically show/hide apps from the left tabs according to the presence of some HTTP headers?

@epixa epixa added Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc release_note:enhancement labels Feb 23, 2017
@epixa
Copy link
Contributor

epixa commented Feb 23, 2017

/cc @stacey-gammon and @spalger since you were both talking about this recently.

@xycloud
Copy link

xycloud commented Feb 23, 2017

mark

@spalger
Copy link
Contributor

spalger commented Feb 24, 2017

WARNING: this just hides the links from the side bar like you asked, it does not prevent users from accessing them with a direct url or prevent them from being linked to in other ways.

In your plugin, try exporting a replaceInjectedVars function to inject vars based on the request headers:

// my_plugin/index.js
export default (kibana) => new kibana.Plugin({
  uiExports: {
    replaceInjectedVars(injectedVars, request) {
      if (/*some condition based on request.headers */) {
        injectedVars.hiddenAppIds = ['kibana:discover'];
      }

      return injectedVars
    },
    hacks: [
      'my_plugin/hacks/hide_nav'
    ]
  }
})

Then you could consume that injected vars and hide the app links with the ui/chrome module:

// my_plugin/public/hacks/hide_nav.js

import chrome from 'ui/chrome'
const hiddenAppIds = chrome.getInjected('hiddenAppIds') || []
hiddenAppIds.forEach(id => {
  chrome.getNavLinkById(id).hidden = true;
})

@sscarduzio
Copy link
Author

Cool! Thanks @spalger, this helps a lot.
So do you mean that if I wanted to prevent navigation to direct app URLs, that would be not possible from a plugin? Is there no server-side way to override the handlers of an arbitrary path a from plugin?

@spalger
Copy link
Contributor

spalger commented Feb 27, 2017

Is there no server-side way to override the handlers of an arbitrary path a from plugin?

You would need both a server-side and client-side hack that filtered all requests/route resolution. Client side you could potentially use a uiRoutes.addSetupWork() or uiRoutes.defaults(/.*/) call to add some default resolver to every route that checked that it was allowed. You would also have to do something similar server-side with an onRequest server extension (see hapi docs).

@xycloud
Copy link

xycloud commented Feb 28, 2017

could you show some demo code?

@spalger
Copy link
Contributor

spalger commented Feb 28, 2017

@sscarduzio if you get something working would you mind sharing?

@sscarduzio
Copy link
Author

@spalger sure, I'm having a taste of what's possible for now. Full explorative phase, will hack something up soon! Once again, thanks for the suggestions.

@xycloud
Copy link

xycloud commented Feb 28, 2017

@sscarduzio great!!, your demo code is expected

@sscarduzio
Copy link
Author

I made almost everything work, quite cool, it took just a day!

Client side: I can successfully hide any app icon via the suggested 'hack'. I understood the hack files are the go-to place where to apply anything that has a global scope in the UI functionality. Very handy.

Server side: I can prevent forced navigation to independent apps (i.e. accessing timelion from a bookmark) intercepting certain paths from the suggested onRequest hapi API, where I put this kind of logic:

 hiddenApps.forEach((ha) => {
     if (request.path.match('(.*/app/' + ha + '.*)|(.*/api/' + ha + '.*)')) {
         forbid = true;
     }
  })

Unfortunately I didn't find a way to prevent forced navigation to kibana sub-apps like kibana:discover. The navigation between kibana:discover, kibana:visualize, kibana:dev_tools, and kibana:management actually happens entirely on the client side (makes sense).

So I guess this can be handled via uiRoutes.<something>, but I'm stuck on how to use it, I'd like to prevent navigation if the destination is an unwanted app or sub-app.

I found this example, but there's no "path" to make a conditional statement:

Suggestions on this last step?

@spalger
Copy link
Contributor

spalger commented Mar 1, 2017

uiRoutes is a wrapper around the default angular router that add methods specifically for this sort of thing.

uiRoutes.addSetupWork() will add a function that runs before each route starts working on it's resolve functions, so this would be an appropriate place to verify that the route is allowed and call notify.error() (to display an error notification about access controls) and kbnUrl.redirect() (to properly abort route resolution and redirect)

@xycloud
Copy link

xycloud commented Mar 2, 2017

yeah, cool. that was really great if anyone can give some client side code

@sscarduzio
Copy link
Author

@xycloud this is my current client side snippet (the "hack" file)

import chrome from "ui/chrome";

uiRoutes.addSetupWork(function ($http) {

  $http.get('../elasticsearch/').then((response) => {
    const hiddenAppIds = response.headers()['x-kibana-hide-apps']
    hiddenAppIds.split(",").forEach(id => {
      chrome.getNavLinkById(id.trim()).hidden = true;
    })
  })
})

@xycloud
Copy link

xycloud commented Mar 3, 2017

@sscarduzio then the plugin origin url cannot be access if they are hidden from client side code?

@sscarduzio
Copy link
Author

@xycloud the above is obtaining the list of apps to hide from a header and removing the icons from the UI. I'm still doing the part where I block the navigation on the client side (I'm having some issues with the build system ATM, I lost an entire day on it because I'm not so expert with this tools).

@xycloud
Copy link

xycloud commented Mar 6, 2017

@sscarduzio I am sorry, could you share your code if there is any movement

@jujis008
Copy link

jujis008 commented Apr 4, 2018

Hey guys,
I found a simple way in kibana 5.4.0 to hidden plugins from left panel and the plugin origin url can be accessed,
`export default function (kibana) {
return new kibana.Plugin({
require: ['elasticsearch'],
uiExports: {

  app: {
    title: 'Perf Step',
    description: 'An awesome Kibana plugin to show step',
    main: 'plugins/big_table_step/app',
    icon: 'plugins/kibana/assets/icon.svg',
    hidden: false,
    listed: false,
    disabled: true
  },


  translations: [
    resolve(__dirname, './translations/es.json')
  ],


  hacks: [
    'plugins/sf_big_table_step/hack'
  ]

},

config(Joi) {
  return Joi.object({
    enabled: Joi.boolean().default(true),
  }).default();
},


init(server, options) {
  // Add server routes and initalize the plugin here
  routes(server);
}

});
};
`
which will hide apps from left panel and also can be accessed.
set listed: false, disabled: true, I am using Kibana 5.4.0, hope helps!!!

@zallan114
Copy link

@sscarduzio , where I can get your work, I am trying to get knowledge on this, thanks

@zallan114
Copy link

finnaly, I found another way:

uiRoutes.addSetupWork(function ($http, $location, kbnUrl) {
if($location.$$path === "/dashboards---") {
let baseUrl = $location.$$absUrl;
baseUrl = baseUrl.substr(0, baseUrl.indexOf("/app"));
window.location.href=(baseUrl + "/app/myplugin#");
}
...

@epixa epixa added enhancement New value added to drive a business result and removed release_note:enhancement labels May 7, 2018
@alexfrancoeur
Copy link

Linking to the work being done for Granular Application Privileges in #20277

@alexfrancoeur
Copy link

@kobelb would feature controls (#20277) resolve this?

@kobelb
Copy link
Contributor

kobelb commented May 20, 2019

@alexfrancoeur Feature Controls are doing this exact behavior. The interface for doing so isn't properly documented for external consumers as the "Spaces" and "Security" plugins are the only ones doing so. However, I'd consider this request satisfied.

@francisco-hoo
Copy link

Hi guys, I don't know why but the Machine Learning App it's the only app that i can't hide. Does everybody have this issue? I think something on source code overrides my changes...

@joshdover joshdover added the stale Used to mark issues that were closed for being stale label Jan 14, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New value added to drive a business result stale Used to mark issues that were closed for being stale Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc
Projects
None yet
Development

No branches or pull requests

10 participants