Rework roles as enum, change AuthSource to enum

This commit is contained in:
Christoph Kluge
2023-03-06 11:44:38 +01:00
parent df44bd9621
commit f37e7c26f6
21 changed files with 205 additions and 141 deletions

View File

@@ -10,11 +10,11 @@
const ccconfig = getContext('cc-config')
export let user
export let isAdmin
</script>
{#if user.AuthLevel == 5}
{#if isAdmin == true}
<Card style="margin-bottom: 1.5em;">
<CardHeader>
<CardTitle class="mb-1">Admin Options</CardTitle>

View File

@@ -4,8 +4,9 @@
Dropdown, DropdownToggle, DropdownMenu, DropdownItem, InputGroupText } from 'sveltestrap'
export let username // empty string if auth. is disabled, otherwise the username as string
export let authlevel // integer
export let authlevel // Integer
export let clusters // array of names
export let roles // Role Enum-Like
let isOpen = false
@@ -39,9 +40,9 @@
]
const viewsPerCluster = [
{ title: 'Analysis', authLevel: 4, href: '/monitoring/analysis/', icon: 'graph-up' },
{ title: 'Systems', authLevel: 5, href: '/monitoring/systems/', icon: 'cpu' },
{ title: 'Status', authLevel: 5, href: '/monitoring/status/', icon: 'cpu' },
{ title: 'Analysis', requiredRole: roles.support, href: '/monitoring/analysis/', icon: 'graph-up' },
{ title: 'Systems', requiredRole: roles.admin, href: '/monitoring/systems/', icon: 'cpu' },
{ title: 'Status', requiredRole: roles.admin, href: '/monitoring/status/', icon: 'cpu' },
]
</script>
@@ -52,26 +53,26 @@
<NavbarToggler on:click={() => (isOpen = !isOpen)} />
<Collapse {isOpen} navbar expand="lg" on:update={({ detail }) => (isOpen = detail.isOpen)}>
<Nav pills>
{#if authlevel == 5} <!-- admin -->
{#if authlevel == roles.admin}
{#each adminviews as item}
<NavLink href={item.href} active={window.location.pathname == item.href}><Icon name={item.icon}/> {item.title}</NavLink>
{/each}
{:else if authlevel == 4} <!-- support -->
{:else if authlevel == roles.support}
{#each supportviews as item}
<NavLink href={item.href} active={window.location.pathname == item.href}><Icon name={item.icon}/> {item.title}</NavLink>
{/each}
{:else if authlevel == 3} <!-- manager -->
{:else if authlevel == roles.manager}
{#each managerviews as item}
<NavLink href={item.href} active={window.location.pathname == item.href}><Icon name={item.icon}/> {item.title}</NavLink>
{/each}
{:else if authlevel == 2} <!-- user -->
{:else if authlevel == roles.user}
{#each userviews as item}
<NavLink href={item.href} active={window.location.pathname == item.href}><Icon name={item.icon}/> {item.title}</NavLink>
{/each}
{:else}
<p>API User or Unauthorized!</p>
{/if}
{#each viewsPerCluster.filter(item => item.authLevel <= authlevel) as item}
{#each viewsPerCluster.filter(item => item.requiredRole <= authlevel) as item}
<NavItem>
<Dropdown nav inNavbar>
<DropdownToggle nav caret>
@@ -94,7 +95,7 @@
<InputGroup>
<Input type="text" placeholder="Search 'type:<query>' ..." name="searchId"/>
<Button outline type="submit"><Icon name="search"/></Button>
<InputGroupText style="cursor:help;" title={(authlevel >= 4) ? "Example: 'projectId:a100cd', Types are: jobId | jobName | projectId | username | name" : "Example: 'jobName:myjob', Types are jobId | jobName | projectId"}><Icon name="info-circle"/></InputGroupText>
<InputGroupText style="cursor:help;" title={(authlevel >= roles.support) ? "Example: 'projectId:a100cd', Types are: jobId | jobName | projectId | username | name" : "Example: 'jobName:myjob', Types are jobId | jobName | projectId"}><Icon name="info-circle"/></InputGroupText>
</InputGroup>
</form>
{#if username}

View File

@@ -14,7 +14,8 @@
const ccconfig = getContext('cc-config')
export let filterPresets = {}
export let authLevel
export let authlevel
export let roles
let filters, jobList, matchedJobs = null
let sorting = { field: 'startTime', order: 'DESC' }, isSortingOpen = false, isMetricsSelectionOpen = false
@@ -61,7 +62,7 @@
</Col>
<Col xs="3" style="margin-left: auto;">
<UserOrProject bind:authLevel={authLevel} on:update={({ detail }) => filters.update(detail)}/>
<UserOrProject bind:authlevel={authlevel} bind:roles={roles} on:update={({ detail }) => filters.update(detail)}/>
</Col>
<Col xs="2">
<Refresher on:reload={() => jobList.update()} />

View File

@@ -4,7 +4,7 @@ import Config from './Config.root.svelte'
new Config({
target: document.getElementById('svelte-app'),
props: {
user: user
isAdmin: isAdmin
},
context: new Map([
['cc-config', clusterCockpitConfig]

View File

@@ -6,7 +6,8 @@
export let user = ''
export let project = ''
export let authLevel
export let authlevel
export let roles
let mode = 'user', term = ''
const throttle = 500
@@ -23,7 +24,7 @@
let timeoutId = null
function termChanged(sleep = throttle) {
if (authLevel == 2) {
if (authlevel == roles.user) {
project = term
if (timeoutId != null)
@@ -34,7 +35,7 @@
project
})
}, sleep)
} else if (authLevel >= 3) {
} else if (authlevel >= roles.manager) {
if (mode == 'user')
user = term
else
@@ -53,13 +54,13 @@
}
</script>
{#if authLevel == 2}
{#if authlevel == roles.user}
<InputGroup>
<Input
type="text" bind:value={term} on:change={() => termChanged()} on:keyup={(event) => termChanged(event.key == 'Enter' ? 0 : throttle)} placeholder='filter project...'
/>
</InputGroup>
{:else if authLevel >= 3}
{:else if authlevel >= roles.manager}
<InputGroup>
<select style="max-width: 175px;" class="form-select"
bind:value={mode} on:change={modeChanged}>

View File

@@ -5,7 +5,8 @@ new Jobs({
target: document.getElementById('svelte-app'),
props: {
filterPresets: filterPresets,
authLevel: authLevel
authlevel: authlevel,
roles: roles
},
context: new Map([
['cc-config', clusterCockpitConfig]

View File

@@ -15,9 +15,10 @@
{{end}}
<script>
const header = {
"username": "{{ .User.Username }}",
"authlevel": {{ .User.AuthLevel }},
"clusters": {{ .Clusters }},
"username": "{{ .User.Username }}",
"authlevel": {{ .User.GetAuthLevel }},
"clusters": {{ .Clusters }},
"roles": {{ .Roles }}
};
</script>
</head>

View File

@@ -7,7 +7,7 @@
{{end}}
{{define "javascript"}}
<script>
const user = {{ .User }};
const isAdmin = {{ .User.HasRole .Roles.admin }};
const filterPresets = {{ .FilterPresets }};
const clusterCockpitConfig = {{ .Config }};
</script>

View File

@@ -9,14 +9,14 @@
<th>Running Jobs (short ones not listed)</th>
<th>Total Jobs</th>
<th>Short Jobs in past 24h</th>
{{if ge .User.AuthLevel 4}}
{{if .User.HasRole .Roles.admin}}
<th>System View</th>
<th>Analysis View</th>
{{end}}
</tr>
</thead>
<tbody>
{{if ge .User.AuthLevel 4}}
{{if .User.HasRole .Roles.admin}}
{{range .Infos.clusters}}
<tr>
<td>{{.Name}}</td>

View File

@@ -10,7 +10,8 @@
<script>
const filterPresets = {{ .FilterPresets }};
const clusterCockpitConfig = {{ .Config }};
const authLevel = {{ .User.AuthLevel }};
const authlevel = {{ .User.GetAuthLevel }};
const roles = {{ .Roles }};
</script>
<script src='/build/jobs.js'></script>
{{end}}

View File

@@ -11,6 +11,7 @@ import (
"net/http"
"strings"
"github.com/ClusterCockpit/cc-backend/internal/auth"
"github.com/ClusterCockpit/cc-backend/internal/config"
"github.com/ClusterCockpit/cc-backend/pkg/log"
"github.com/ClusterCockpit/cc-backend/pkg/schema"
@@ -55,11 +56,6 @@ func init() {
_ = base
}
type User struct {
Username string // Username of the currently logged in user
AuthLevel int // Level of authorization
}
type Build struct {
Version string
Hash string
@@ -70,7 +66,8 @@ type Page struct {
Title string // Page title
Error string // For generic use (e.g. the exact error message on /login)
Info string // For generic use (e.g. "Logout successfull" on /login)
User User // Information about the currently logged in user
User auth.User // Information about the currently logged in user (Full User Info)
Roles map[string]auth.Role // Available roles for frontend render checks
Build Build // Latest information about the application
Clusters []schema.ClusterConfig // List of all clusters for use in the Header
FilterPresets map[string]interface{} // For pages with the Filter component, this can be used to set initial filters.