diff --git a/integration-tests/configs/policy-all-false/config.yaml b/integration-tests/configs/policy-all-false/config.yaml new file mode 100644 index 0000000..3fd7c86 --- /dev/null +++ b/integration-tests/configs/policy-all-false/config.yaml @@ -0,0 +1,14 @@ +# Integration Test Config: Policy All False +# + +logLevel: "DEBUG" +checkForUpdates: false + +defaultPolicy: + showDiagnostics: false + showLogList: false + +actions: +- title: sleep 2 seconds + shell: sleep 2 + icon: "🥱" diff --git a/integration-tests/test/general.mjs b/integration-tests/test/general.mjs index c3895f0..36cb37b 100644 --- a/integration-tests/test/general.mjs +++ b/integration-tests/test/general.mjs @@ -37,6 +37,15 @@ describe('config: general', function () { */ }) + it('navbar contains default policy links', async function () { + await getRootAndWait() + + const logListLink = await webdriver.findElements(By.css('[href="/logs"]')) + expect(logListLink).to.not.be.empty + + const diagnosticsLink = await webdriver.findElements(By.css('[href="/diagnostics"]')) + expect(diagnosticsLink).to.not.be.empty + }) it('Footer contains promo', async function () { const ftr = await webdriver.findElement(By.tagName('footer')).getText() diff --git a/integration-tests/test/policy-all-false.mjs b/integration-tests/test/policy-all-false.mjs new file mode 100644 index 0000000..10d42b5 --- /dev/null +++ b/integration-tests/test/policy-all-false.mjs @@ -0,0 +1,32 @@ +import { + getRootAndWait, + takeScreenshotOnFailure, +} from '../lib/elements.js' + +import { By } from 'selenium-webdriver' +import { expect } from 'chai' + +describe('config: policy-all-false', function () { + before(async function () { + await runner.start('policy-all-false') + }); + + after(async () => { + await runner.stop() + }); + + afterEach(function () { + takeScreenshotOnFailure(this.currentTest, webdriver); + }); + + + it('navbar should not contain default policy links', async function () { + await getRootAndWait() + + const logListLink = await webdriver.findElements(By.css('[href="/logs"]')) + expect(logListLink).to.be.empty + + const diagnosticsLink = await webdriver.findElements(By.css('[href="/diagnostics"]')) + expect(diagnosticsLink).to.be.empty + }) +}) diff --git a/proto/olivetin/api/v1/olivetin.proto b/proto/olivetin/api/v1/olivetin.proto index 8660450..e28c2d7 100644 --- a/proto/olivetin/api/v1/olivetin.proto +++ b/proto/olivetin/api/v1/olivetin.proto @@ -49,6 +49,19 @@ message GetDashboardComponentsResponse { string authenticated_user = 5; string authenticated_user_provider = 6; + + EffectivePolicy effective_policy = 7; + Diagnostics diagnostics = 8; +} + +message Diagnostics { + string SshFoundKey = 1; + string SshFoundConfig = 2; +} + +message EffectivePolicy { + bool show_diagnostics = 1; + bool show_log_list = 2; } message GetDashboardComponentsRequest {} diff --git a/service/internal/acl/acl.go b/service/internal/acl/acl.go index f1fa32c..e91b9f8 100644 --- a/service/internal/acl/acl.go +++ b/service/internal/acl/acl.go @@ -32,6 +32,8 @@ type AuthenticatedUser struct { SID string Acls []string + + EffectivePolicy *config.ConfigurationPolicy } func (u *AuthenticatedUser) IsGuest() bool { @@ -43,15 +45,22 @@ func logAclNotMatched(cfg *config.Config, aclFunction string, user *Authenticate log.WithFields(log.Fields{ "User": user.Username, "Action": action.Title, - }).Debugf("%v - No ACLs Matched", aclFunction) + "ACL": acl.Name, + }).Debugf("%v - ACL Not Matched", aclFunction) } } func logAclMatched(cfg *config.Config, aclFunction string, user *AuthenticatedUser, action *config.Action, acl *config.AccessControlList) { + actionTitle := "N/A" + + if action != nil { + actionTitle = action.Title + } + if cfg.LogDebugOptions.AclMatched { log.WithFields(log.Fields{ "User": user.Username, - "Action": action.Title, + "Action": actionTitle, "ACL": acl.Name, }).Debugf("%v - Matched ACL", aclFunction) } @@ -209,6 +218,8 @@ func buildUserAcls(cfg *config.Config, user *AuthenticatedUser) { continue } } + + user.EffectivePolicy = getEffectivePolicy(cfg, user) } func hasGroupsMatch(matchUsergroups []string, usergroup string) bool { @@ -249,3 +260,32 @@ func getRelevantAcls(cfg *config.Config, actionAcls []string, user *Authenticate return ret } + +func getEffectivePolicy(cfg *config.Config, user *AuthenticatedUser) *config.ConfigurationPolicy { + ret := &config.ConfigurationPolicy{ + ShowDiagnostics: cfg.DefaultPolicy.ShowDiagnostics, + ShowLogList: cfg.DefaultPolicy.ShowLogList, + } + + for _, acl := range cfg.AccessControlLists { + if slices.Contains(user.Acls, acl.Name) { + logAclMatched(cfg, "GetEffectivePolicy", user, nil, acl) + + ret = buildConfigurationPolicy(ret, acl.Policy) + } + } + + return ret +} + +func buildConfigurationPolicy(ret *config.ConfigurationPolicy, policy config.ConfigurationPolicy) *config.ConfigurationPolicy { + if policy.ShowDiagnostics { + ret.ShowDiagnostics = policy.ShowDiagnostics + } + + if policy.ShowLogList { + ret.ShowLogList = policy.ShowLogList + } + + return ret +} diff --git a/service/internal/config/config.go b/service/internal/config/config.go index fca1ea0..ad1c818 100644 --- a/service/internal/config/config.go +++ b/service/internal/config/config.go @@ -76,6 +76,13 @@ type AccessControlList struct { MatchUsergroups []string MatchUsernames []string Permissions PermissionsList + Policy ConfigurationPolicy +} + +// ConfigurationPolicy defines global settings which are overridden with an ACL. +type ConfigurationPolicy struct { + ShowDiagnostics bool + ShowLogList bool } type PrometheusConfig struct { @@ -123,6 +130,7 @@ type Config struct { AuthOAuth2RedirectURL string AuthOAuth2Providers map[string]*OAuth2Provider DefaultPermissions PermissionsList + DefaultPolicy ConfigurationPolicy AccessControlLists []*AccessControlList WebUIDir string CronSupportForSeconds bool @@ -243,5 +251,8 @@ func DefaultConfigWithBasePort(basePort int) *Config { config.ListenAddressWebUI = fmt.Sprintf("localhost:%d", basePort+3) config.ListenAddressPrometheus = fmt.Sprintf("localhost:%d", basePort+4) + config.DefaultPolicy.ShowDiagnostics = true + config.DefaultPolicy.ShowLogList = true + return &config } diff --git a/service/internal/grpcapi/grpcApiActions.go b/service/internal/grpcapi/grpcApiActions.go index 3e77463..6f4898c 100644 --- a/service/internal/grpcapi/grpcApiActions.go +++ b/service/internal/grpcapi/grpcApiActions.go @@ -5,6 +5,7 @@ import ( acl "github.com/OliveTin/OliveTin/internal/acl" config "github.com/OliveTin/OliveTin/internal/config" executor "github.com/OliveTin/OliveTin/internal/executor" + installationinfo "github.com/OliveTin/OliveTin/internal/installationinfo" sv "github.com/OliveTin/OliveTin/internal/stringvariables" "sort" ) @@ -35,9 +36,32 @@ func buildDashboardResponse(ex *executor.Executor, cfg *config.Config, user *acl } }) + res.EffectivePolicy = buildEffectivePolicy(user.EffectivePolicy) + res.Diagnostics = buildDiagnostics(res.EffectivePolicy.ShowDiagnostics) + return res } +func buildEffectivePolicy(policy *config.ConfigurationPolicy) *apiv1.EffectivePolicy { + ret := &apiv1.EffectivePolicy{ + ShowDiagnostics: policy.ShowDiagnostics, + ShowLogList: policy.ShowLogList, + } + + return ret +} + +func buildDiagnostics(showDiagnostics bool) *apiv1.Diagnostics { + ret := &apiv1.Diagnostics{} + + if showDiagnostics { + ret.SshFoundKey = installationinfo.Runtime.SshFoundKey + ret.SshFoundConfig = installationinfo.Runtime.SshFoundConfig + } + + return ret +} + func buildAction(actionId string, actionBinding *executor.ActionBinding, user *acl.AuthenticatedUser) *apiv1.Action { action := actionBinding.Action diff --git a/service/internal/httpservers/webuiServer.go b/service/internal/httpservers/webuiServer.go index 53c96f3..3beb423 100644 --- a/service/internal/httpservers/webuiServer.go +++ b/service/internal/httpservers/webuiServer.go @@ -29,8 +29,6 @@ type webUISettings struct { PageTitle string SectionNavigationStyle string DefaultIconForBack string - SshFoundKey string - SshFoundConfig string EnableCustomJs bool AuthLoginUrl string AuthLocalLogin bool @@ -138,8 +136,6 @@ func generateWebUISettings(w http.ResponseWriter, r *http.Request) { PageTitle: cfg.PageTitle, SectionNavigationStyle: cfg.SectionNavigationStyle, DefaultIconForBack: cfg.DefaultIconForBack, - SshFoundKey: installationinfo.Runtime.SshFoundKey, - SshFoundConfig: installationinfo.Runtime.SshFoundConfig, EnableCustomJs: cfg.EnableCustomJs, AuthLoginUrl: cfg.AuthLoginUrl, AuthLocalLogin: cfg.AuthLocalUsers.Enabled, diff --git a/webui.dev/index.html b/webui.dev/index.html index d8c4245..b9a4647 100644 --- a/webui.dev/index.html +++ b/webui.dev/index.html @@ -35,12 +35,6 @@