2022-09-23 04:04:48 +08:00
package navtreeimpl
import (
2025-04-30 15:06:44 +08:00
"github.com/grafana/grafana/pkg/apimachinery/identity"
2024-03-25 17:54:45 +08:00
"github.com/grafana/grafana/pkg/login/social"
2022-09-23 04:04:48 +08:00
ac "github.com/grafana/grafana/pkg/services/accesscontrol"
2024-01-25 18:13:24 +08:00
"github.com/grafana/grafana/pkg/services/accesscontrol/ssoutils"
2025-01-09 12:03:42 +08:00
"github.com/grafana/grafana/pkg/services/cloudmigration"
2023-01-27 15:50:36 +08:00
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
2022-09-23 04:04:48 +08:00
"github.com/grafana/grafana/pkg/services/correlations"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/navtree"
2023-03-27 17:15:37 +08:00
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginaccesscontrol"
2022-09-23 04:04:48 +08:00
"github.com/grafana/grafana/pkg/services/serviceaccounts"
2024-10-10 14:27:57 +08:00
"github.com/grafana/grafana/pkg/setting"
2022-09-23 04:04:48 +08:00
)
2024-10-10 14:27:57 +08:00
// nolint: gocyclo
2023-04-20 18:10:12 +08:00
func ( s * ServiceImpl ) getAdminNode ( c * contextmodel . ReqContext ) ( * navtree . NavLink , error ) {
2022-09-23 04:04:48 +08:00
var configNodes [ ] * navtree . NavLink
2023-11-15 04:50:27 +08:00
ctx := c . Req . Context ( )
2022-09-23 04:04:48 +08:00
hasAccess := ac . HasAccess ( s . accessControl , c )
2024-04-10 18:42:13 +08:00
hasGlobalAccess := ac . HasGlobalAccess ( s . accessControl , s . authnService , c )
2023-04-20 18:10:12 +08:00
orgsAccessEvaluator := ac . EvalPermission ( ac . ActionOrgsRead )
2024-03-25 17:54:45 +08:00
authConfigUIAvailable := s . license . FeatureEnabled ( social . SAMLProviderName ) || s . cfg . LDAPAuthEnabled
2023-04-20 18:10:12 +08:00
2024-06-12 23:45:13 +08:00
generalNodeLinks := [ ] * navtree . NavLink { }
if hasAccess ( ac . OrgPreferencesAccessEvaluator ) {
generalNodeLinks = append ( generalNodeLinks , & navtree . NavLink {
Text : "Default preferences" ,
Id : "org-settings" ,
SubTitle : "Manage preferences across an organization" ,
Icon : "sliders-v-alt" ,
Url : s . cfg . AppSubURL + "/org" ,
} )
}
if hasAccess ( ac . EvalPermission ( ac . ActionSettingsRead , ac . ScopeSettingsAll ) ) {
generalNodeLinks = append ( generalNodeLinks , & navtree . NavLink {
Text : "Settings" , SubTitle : "View the settings defined in your Grafana config" , Id : "server-settings" , Url : s . cfg . AppSubURL + "/admin/settings" , Icon : "sliders-v-alt" ,
} )
}
if hasGlobalAccess ( orgsAccessEvaluator ) {
generalNodeLinks = append ( generalNodeLinks , & navtree . NavLink {
Text : "Organizations" , SubTitle : "Isolated instances of Grafana running on the same server" , Id : "global-orgs" , Url : s . cfg . AppSubURL + "/admin/orgs" , Icon : "building" ,
} )
}
if s . features . IsEnabled ( ctx , featuremgmt . FlagFeatureToggleAdminPage ) && hasAccess ( ac . EvalPermission ( ac . ActionFeatureManagementRead ) ) {
generalNodeLinks = append ( generalNodeLinks , & navtree . NavLink {
2024-06-17 18:22:11 +08:00
Text : "Feature toggles" ,
2024-06-12 23:45:13 +08:00
SubTitle : "View and edit feature toggles" ,
Id : "feature-toggles" ,
Url : s . cfg . AppSubURL + "/admin/featuretoggles" ,
Icon : "toggle-on" ,
} )
}
2025-01-09 12:03:42 +08:00
if hasAccess ( cloudmigration . MigrationAssistantAccess ) && s . features . IsEnabled ( ctx , featuremgmt . FlagOnPremToCloudMigrations ) {
2024-06-12 23:45:13 +08:00
generalNodeLinks = append ( generalNodeLinks , & navtree . NavLink {
Text : "Migrate to Grafana Cloud" ,
Id : "migrate-to-cloud" ,
2025-04-10 20:50:37 +08:00
SubTitle : "Copy resources from your self-managed installation to a cloud stack" ,
2024-06-12 23:45:13 +08:00
Url : s . cfg . AppSubURL + "/admin/migrate-to-cloud" ,
} )
}
2025-04-30 15:06:44 +08:00
if c . HasRole ( identity . RoleAdmin ) &&
( s . cfg . StackID == "" || // show OnPrem even when provisioning is disabled
s . features . IsEnabledGlobally ( featuremgmt . FlagProvisioning ) ) {
configNodes = append ( configNodes , & navtree . NavLink {
2025-04-04 18:08:58 +08:00
Text : "Provisioning" ,
2025-03-18 20:55:22 +08:00
Id : "provisioning" ,
2025-04-04 18:08:58 +08:00
SubTitle : "View and manage your provisioning connections" ,
2025-03-18 20:55:22 +08:00
Url : s . cfg . AppSubURL + "/admin/provisioning" ,
2025-04-30 15:06:44 +08:00
} )
2025-03-18 20:55:22 +08:00
}
2024-06-12 23:45:13 +08:00
generalNode := & navtree . NavLink {
Text : "General" ,
SubTitle : "Manage default preferences and settings across Grafana" ,
Id : navtree . NavIDCfgGeneral ,
Url : "/admin/general" ,
Icon : "shield" ,
Children : generalNodeLinks ,
}
if len ( generalNode . Children ) > 0 {
configNodes = append ( configNodes , generalNode )
}
pluginsNodeLinks := [ ] * navtree . NavLink { }
2023-10-12 16:46:43 +08:00
// FIXME: If plugin admin is disabled or externally managed, server admins still need to access the page, this is why
// while we don't have a permissions for listing plugins the legacy check has to stay as a default
2023-05-30 21:39:09 +08:00
if pluginaccesscontrol . ReqCanAdminPlugins ( s . cfg ) ( c ) || hasAccess ( pluginaccesscontrol . AdminAccessEvaluator ) {
2024-06-12 23:45:13 +08:00
pluginsNodeLinks = append ( pluginsNodeLinks , & navtree . NavLink {
2023-04-20 18:10:12 +08:00
Text : "Plugins" ,
Id : "plugins" ,
SubTitle : "Extend the Grafana experience with plugins" ,
Icon : "plug" ,
Url : s . cfg . AppSubURL + "/plugins" ,
} )
}
2024-06-12 23:45:13 +08:00
if s . features . IsEnabled ( ctx , featuremgmt . FlagCorrelations ) && hasAccess ( correlations . ConfigurationPageAccess ) {
pluginsNodeLinks = append ( pluginsNodeLinks , & navtree . NavLink {
Text : "Correlations" ,
Icon : "gf-glue" ,
SubTitle : "Add and configure correlations" ,
Id : "correlations" ,
Url : s . cfg . AppSubURL + "/datasources/correlations" ,
} )
}
2023-04-20 18:10:12 +08:00
2024-11-05 23:55:10 +08:00
if ( s . cfg . Env == setting . Dev ) || s . features . IsEnabled ( ctx , featuremgmt . FlagEnableExtensionsAdminPage ) && hasAccess ( pluginaccesscontrol . AdminAccessEvaluator ) {
2024-10-10 14:27:57 +08:00
pluginsNodeLinks = append ( pluginsNodeLinks , & navtree . NavLink {
Text : "Extensions" ,
Icon : "plug" ,
SubTitle : "Extend the UI of plugins and Grafana" ,
Id : "extensions" ,
Url : s . cfg . AppSubURL + "/admin/extensions" ,
} )
}
2024-06-12 23:45:13 +08:00
pluginsNode := & navtree . NavLink {
Text : "Plugins and data" ,
SubTitle : "Install plugins and define the relationships between data" ,
Id : navtree . NavIDCfgPlugins ,
Url : "/admin/plugins" ,
Icon : "shield" ,
Children : pluginsNodeLinks ,
}
if len ( pluginsNode . Children ) > 0 {
configNodes = append ( configNodes , pluginsNode )
}
accessNodeLinks := [ ] * navtree . NavLink { }
2023-05-30 21:39:09 +08:00
if hasAccess ( ac . EvalAny ( ac . EvalPermission ( ac . ActionOrgUsersRead ) , ac . EvalPermission ( ac . ActionUsersRead , ac . ScopeGlobalUsersAll ) ) ) {
2024-06-12 23:45:13 +08:00
accessNodeLinks = append ( accessNodeLinks , & navtree . NavLink {
2023-04-20 18:10:12 +08:00
Text : "Users" , SubTitle : "Manage users in Grafana" , Id : "global-users" , Url : s . cfg . AppSubURL + "/admin/users" , Icon : "user" ,
2022-09-23 04:04:48 +08:00
} )
}
2023-05-30 21:39:09 +08:00
if hasAccess ( ac . TeamsAccessEvaluator ) {
2024-06-12 23:45:13 +08:00
accessNodeLinks = append ( accessNodeLinks , & navtree . NavLink {
2022-10-03 17:09:32 +08:00
Text : "Teams" ,
Id : "teams" ,
SubTitle : "Groups of users that have common dashboard and permission needs" ,
Icon : "users-alt" ,
Url : s . cfg . AppSubURL + "/org/teams" ,
2022-09-23 04:04:48 +08:00
} )
}
2023-04-20 18:10:12 +08:00
if enableServiceAccount ( s , c ) {
2024-06-12 23:45:13 +08:00
accessNodeLinks = append ( accessNodeLinks , & navtree . NavLink {
2023-04-20 18:10:12 +08:00
Text : "Service accounts" ,
Id : "serviceaccounts" ,
SubTitle : "Use service accounts to run automated workloads in Grafana" ,
Icon : "gf-service-account" ,
Url : s . cfg . AppSubURL + "/org/serviceaccounts" ,
2022-09-23 04:04:48 +08:00
} )
}
2024-09-20 03:58:11 +08:00
if s . license . FeatureEnabled ( "groupsync" ) &&
s . features . IsEnabled ( ctx , featuremgmt . FlagGroupAttributeSync ) &&
hasAccess ( ac . EvalAny (
ac . EvalPermission ( "groupsync.mappings:read" ) ,
ac . EvalPermission ( "groupsync.mappings:write" ) ,
) ) {
accessNodeLinks = append ( accessNodeLinks , & navtree . NavLink {
Text : "External group sync" ,
Id : "groupsync" ,
SubTitle : "Manage mappings of Identity Provider groups to Grafana Roles" ,
Icon : "" ,
Url : s . cfg . AppSubURL + "/admin/access/groupsync" ,
} )
}
2024-06-12 23:45:13 +08:00
usersNode := & navtree . NavLink {
Text : "Users and access" ,
SubTitle : "Configure access for individual users, teams, and service accounts" ,
Id : navtree . NavIDCfgAccess ,
Url : "/admin/access" ,
Icon : "shield" ,
Children : accessNodeLinks ,
2023-04-20 18:10:12 +08:00
}
2024-07-24 21:10:19 +08:00
// Always append admin access as it's injected by grafana-auth-app.
configNodes = append ( configNodes , usersNode )
2023-08-04 02:17:00 +08:00
2024-06-12 23:45:13 +08:00
if authConfigUIAvailable && hasAccess ( ssoutils . EvalAuthenticationSettings ( s . cfg ) ) ||
2025-07-03 16:53:33 +08:00
hasAccess ( ssoutils . OauthSettingsEvaluator ( s . cfg ) ) {
2023-04-20 18:10:12 +08:00
configNodes = append ( configNodes , & navtree . NavLink {
2024-06-12 23:45:13 +08:00
Text : "Authentication" ,
Id : "authentication" ,
SubTitle : "Manage your auth settings and configure single sign-on" ,
Icon : "signin" ,
IsSection : true ,
Url : s . cfg . AppSubURL + "/admin/authentication" ,
2023-04-20 18:10:12 +08:00
} )
}
configNode := & navtree . NavLink {
Id : navtree . NavIDCfg ,
Text : "Administration" ,
2025-04-10 20:42:23 +08:00
SubTitle : "Organization: " + c . GetOrgName ( ) ,
2023-04-20 18:10:12 +08:00
Icon : "cog" ,
SortWeight : navtree . WeightConfig ,
Children : configNodes ,
Url : "/admin" ,
2022-09-28 14:29:35 +08:00
}
2023-04-20 18:10:12 +08:00
return configNode , nil
2022-09-23 04:04:48 +08:00
}
2023-01-27 15:50:36 +08:00
func enableServiceAccount ( s * ServiceImpl , c * contextmodel . ReqContext ) bool {
2022-09-23 04:04:48 +08:00
hasAccess := ac . HasAccess ( s . accessControl , c )
2023-05-30 21:39:09 +08:00
return hasAccess ( serviceaccounts . AccessEvaluator )
2022-09-23 04:04:48 +08:00
}