diff --git a/pkg/api/api.go b/pkg/api/api.go index 3180364b8be..3b45d7477f7 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -106,7 +106,7 @@ func (hs *HTTPServer) registerRoutes() { r.Get("/admin/orgs", authorizeInOrg(ac.UseGlobalOrg, ac.OrgsAccessEvaluator), hs.Index) r.Get("/admin/orgs/edit/:id", authorizeInOrg(ac.UseGlobalOrg, ac.OrgsAccessEvaluator), hs.Index) r.Get("/admin/stats", authorize(ac.EvalPermission(ac.ActionServerStatsRead)), hs.Index) - r.Get("/admin/ldap", authorize(ac.EvalPermission(ac.ActionLDAPStatusRead)), hs.Index) + r.Get("/admin/authentication/ldap", authorize(ac.EvalPermission(ac.ActionLDAPStatusRead)), hs.Index) if hs.Features.IsEnabled(featuremgmt.FlagStorage) { r.Get("/admin/storage", reqSignedIn, hs.Index) r.Get("/admin/storage/*", reqSignedIn, hs.Index) @@ -213,10 +213,7 @@ func (hs *HTTPServer) registerRoutes() { r.Get("/user/auth-tokens/rotate", routing.Wrap(hs.RotateUserAuthTokenRedirect)) } - if hs.License.FeatureEnabled("saml") { - // TODO change the scope when we extend the auth UI to more providers - r.Get("/admin/authentication/", authorize(ac.EvalPermission(ac.ActionSettingsWrite, ac.ScopeSettingsSAML)), hs.Index) - } + r.Get("/admin/authentication/", authorize(evalAuthenticationSettings()), hs.Index) // authed api r.Group("/api", func(apiRoute routing.RouteRegister) { @@ -649,3 +646,10 @@ func (hs *HTTPServer) registerRoutes() { r.Get("/api/snapshots-delete/:deleteKey", reqSnapshotPublicModeOrSignedIn, routing.Wrap(hs.DeleteDashboardSnapshotByDeleteKey)) r.Delete("/api/snapshots/:key", reqSignedIn, routing.Wrap(hs.DeleteDashboardSnapshot)) } + +func evalAuthenticationSettings() ac.Evaluator { + return ac.EvalAny(ac.EvalAll( + ac.EvalPermission(ac.ActionSettingsWrite, ac.ScopeSettingsSAML), + ac.EvalPermission(ac.ActionSettingsRead, ac.ScopeSettingsSAML), + ), ac.EvalPermission(ac.ActionLDAPStatusRead)) +} diff --git a/pkg/services/navtree/navtreeimpl/admin.go b/pkg/services/navtree/navtreeimpl/admin.go index 3dc024e4364..8e93bdf3ced 100644 --- a/pkg/services/navtree/navtreeimpl/admin.go +++ b/pkg/services/navtree/navtreeimpl/admin.go @@ -121,12 +121,6 @@ func (s *ServiceImpl) getAdminNode(c *contextmodel.ReqContext) (*navtree.NavLink }) } - if s.cfg.LDAPAuthEnabled && hasAccess(ac.EvalPermission(ac.ActionLDAPStatusRead)) { - configNodes = append(configNodes, &navtree.NavLink{ - Text: "LDAP", Id: "ldap", Url: s.cfg.AppSubURL + "/admin/ldap", Icon: "book", - }) - } - if hasAccess(ac.EvalPermission(ac.ActionSettingsRead, ac.ScopeSettingsAll)) && s.features.IsEnabled(featuremgmt.FlagStorage) { storage := &navtree.NavLink{ Text: "Storage", @@ -157,8 +151,8 @@ func enableServiceAccount(s *ServiceImpl, c *contextmodel.ReqContext) bool { } func evalAuthenticationSettings() ac.Evaluator { - return ac.EvalAll( + return ac.EvalAny(ac.EvalAll( ac.EvalPermission(ac.ActionSettingsWrite, ac.ScopeSettingsSAML), ac.EvalPermission(ac.ActionSettingsRead, ac.ScopeSettingsSAML), - ) + ), ac.EvalPermission(ac.ActionLDAPStatusRead)) } diff --git a/public/app/features/admin/UserLdapSyncInfo.tsx b/public/app/features/admin/UserLdapSyncInfo.tsx index 7605ef90873..0ff189bb5d6 100644 --- a/public/app/features/admin/UserLdapSyncInfo.tsx +++ b/public/app/features/admin/UserLdapSyncInfo.tsx @@ -14,7 +14,7 @@ interface Props { interface State {} const format = 'dddd YYYY-MM-DD HH:mm zz'; -const debugLDAPMappingBaseURL = '/admin/ldap'; +const debugLDAPMappingBaseURL = '/admin/authentication/ldap'; export class UserLdapSyncInfo extends PureComponent { onUserSync = () => { diff --git a/public/app/features/admin/ldap/LdapPage.tsx b/public/app/features/admin/ldap/LdapPage.tsx index f0959e6f70e..5a0e68fc1b7 100644 --- a/public/app/features/admin/ldap/LdapPage.tsx +++ b/public/app/features/admin/ldap/LdapPage.tsx @@ -1,14 +1,13 @@ import React, { PureComponent } from 'react'; import { connect, ConnectedProps } from 'react-redux'; -import { NavModel } from '@grafana/data'; +import { NavModelItem } from '@grafana/data'; import { featureEnabled } from '@grafana/runtime'; import { Alert, Button, LegacyForms } from '@grafana/ui'; const { FormField } = LegacyForms; import { Page } from 'app/core/components/Page/Page'; import { contextSrv } from 'app/core/core'; import { GrafanaRouteComponentProps } from 'app/core/navigation/types'; -import { getNavModel } from 'app/core/selectors/navModel'; import { AppNotificationSeverity, LdapError, @@ -32,7 +31,6 @@ import { LdapSyncInfo } from './LdapSyncInfo'; import { LdapUserInfo } from './LdapUserInfo'; interface OwnProps extends GrafanaRouteComponentProps<{}, { username?: string }> { - navModel: NavModel; ldapConnectionInfo: LdapConnectionInfo; ldapUser?: LdapUser; ldapSyncInfo?: SyncInfo; @@ -44,6 +42,13 @@ interface State { isLoading: boolean; } +const pageNav: NavModelItem = { + text: 'LDAP', + subTitle: `Verify your LDAP and user mapping configuration.`, + icon: 'book', + id: 'LDAP', +}; + export class LdapPage extends PureComponent { state = { isLoading: true, @@ -84,12 +89,12 @@ export class LdapPage extends PureComponent { }; render() { - const { ldapUser, userError, ldapError, ldapSyncInfo, ldapConnectionInfo, navModel, queryParams } = this.props; + const { ldapUser, userError, ldapError, ldapSyncInfo, ldapConnectionInfo, queryParams } = this.props; const { isLoading } = this.state; const canReadLDAPUser = contextSrv.hasPermission(AccessControlAction.LDAPUsersRead); return ( - + <> {ldapError && ldapError.title && ( @@ -143,7 +148,6 @@ export class LdapPage extends PureComponent { } const mapStateToProps = (state: StoreState) => ({ - navModel: getNavModel(state.navIndex, 'ldap'), ldapConnectionInfo: state.ldap.connectionInfo, ldapUser: state.ldap.user, ldapSyncInfo: state.ldap.syncInfo, diff --git a/public/app/routes/routes.tsx b/public/app/routes/routes.tsx index 8aef7aadca0..5f727daa716 100644 --- a/public/app/routes/routes.tsx +++ b/public/app/routes/routes.tsx @@ -377,7 +377,7 @@ export function getAppRoutes(): RouteDescriptor[] { ), }, { - path: '/admin/ldap', + path: '/admin/authentication/ldap', component: LdapPage, }, // LOGIN / SIGNUP