Handle users with no roles as "user role"

-for backwards compatibility
This commit is contained in:
Christoph Kluge 2023-06-12 11:35:16 +02:00
parent 21ec2bb51d
commit 0d2e20e9e4
4 changed files with 36 additions and 30 deletions

View File

@ -204,7 +204,10 @@ func (r *JobRepository) CountJobs(
func SecurityCheck(ctx context.Context, query sq.SelectBuilder) (queryOut sq.SelectBuilder, err error) { func SecurityCheck(ctx context.Context, query sq.SelectBuilder) (queryOut sq.SelectBuilder, err error) {
user := auth.GetUser(ctx) user := auth.GetUser(ctx)
if user == nil || user.HasAnyRole([]auth.Role{auth.RoleAdmin, auth.RoleSupport, auth.RoleApi}) { // Admin & Co. : All jobs if user == nil {
var qnil sq.SelectBuilder
return qnil, fmt.Errorf("user context is nil!")
} else if user.HasAnyRole([]auth.Role{auth.RoleAdmin, auth.RoleSupport}) { // Admin & Co. : All jobs
return query, nil return query, nil
} else if user.HasRole(auth.RoleManager) { // Manager : Add filter for managed projects' jobs only + personal jobs } else if user.HasRole(auth.RoleManager) { // Manager : Add filter for managed projects' jobs only + personal jobs
if len(user.Projects) != 0 { if len(user.Projects) != 0 {
@ -215,9 +218,12 @@ func SecurityCheck(ctx context.Context, query sq.SelectBuilder) (queryOut sq.Sel
} }
} else if user.HasRole(auth.RoleUser) { // User : Only personal jobs } else if user.HasRole(auth.RoleUser) { // User : Only personal jobs
return query.Where("job.user = ?", user.Username), nil return query.Where("job.user = ?", user.Username), nil
} else { // Unauthorized : Error } else {
var qnil sq.SelectBuilder // Shortterm compatibility: Return User-Query if no roles:
return qnil, fmt.Errorf("user '%s' with unknown roles [%#v]", user.Username, user.Roles) return query.Where("job.user = ?", user.Username), nil
// // On the longterm: Return Error instead of fallback:
// var qnil sq.SelectBuilder
// return qnil, fmt.Errorf("user '%s' with unknown roles [%#v]", user.Username, user.Roles)
} }
} }

View File

@ -88,12 +88,15 @@ func (r *JobRepository) CountTags(user *auth.User) (tags []schema.Tag, counts ma
LeftJoin("jobtag jt ON t.id = jt.tag_id"). LeftJoin("jobtag jt ON t.id = jt.tag_id").
GroupBy("t.tag_name") GroupBy("t.tag_name")
if user != nil && user.HasRole(auth.RoleUser) { // USER: Only count own jobs if user != nil && user.HasAnyRole([]auth.Role{auth.RoleAdmin, auth.RoleSupport}) { // ADMIN || SUPPORT: Count all jobs
q = q.Where("jt.job_id IN (SELECT id FROM job WHERE job.user = ?)", user.Username) log.Info("CountTags: User Admin or Support -> Count all Jobs for Tags")
// Unchanged: Needs to be own case still, due to UserRole/NoRole compatibility handling in else case
} else if user != nil && user.HasRole(auth.RoleManager) { // MANAGER: Count own jobs plus project's jobs } else if user != nil && user.HasRole(auth.RoleManager) { // MANAGER: Count own jobs plus project's jobs
// Build ("project1", "project2", ...) list of variable length directly in SQL string // Build ("project1", "project2", ...) list of variable length directly in SQL string
q = q.Where("jt.job_id IN (SELECT id FROM job WHERE job.user = ? OR job.project IN (\""+strings.Join(user.Projects, "\",\"")+"\"))", user.Username) q = q.Where("jt.job_id IN (SELECT id FROM job WHERE job.user = ? OR job.project IN (\""+strings.Join(user.Projects, "\",\"")+"\"))", user.Username)
} // else: ADMIN || SUPPORT: Count all jobs } else { // USER OR NO ROLE (Compatibility): Only count own jobs
q = q.Where("jt.job_id IN (SELECT id FROM job WHERE job.user = ?)", user.Username)
}
rows, err := q.RunWith(r.stmtCache).Query() rows, err := q.RunWith(r.stmtCache).Query()
if err != nil { if err != nil {

View File

@ -65,12 +65,10 @@
{#each managerviews as item} {#each managerviews as item}
<NavLink href={item.href} active={window.location.pathname == item.href}><Icon name={item.icon}/> {item.title}</NavLink> <NavLink href={item.href} active={window.location.pathname == item.href}><Icon name={item.icon}/> {item.title}</NavLink>
{/each} {/each}
{:else if authlevel == roles.user} {:else} <!-- Compatibility: Handle "user role" or "no role" as identical-->
{#each userviews as item} {#each userviews as item}
<NavLink href={item.href} active={window.location.pathname == item.href}><Icon name={item.icon}/> {item.title}</NavLink> <NavLink href={item.href} active={window.location.pathname == item.href}><Icon name={item.icon}/> {item.title}</NavLink>
{/each} {/each}
{:else}
<p>API User or Unauthorized!</p>
{/if} {/if}
{#each viewsPerCluster.filter(item => item.requiredRole <= authlevel) as item} {#each viewsPerCluster.filter(item => item.requiredRole <= authlevel) as item}
<NavItem> <NavItem>

View File

@ -23,19 +23,9 @@
} }
let timeoutId = null let timeoutId = null
// Compatibility: Handle "user role" and "no role" identically
function termChanged(sleep = throttle) { function termChanged(sleep = throttle) {
if (authlevel == roles.user) { if (authlevel >= roles.manager) {
project = term
if (timeoutId != null)
clearTimeout(timeoutId)
timeoutId = setTimeout(() => {
dispatch('update', {
project
})
}, sleep)
} else if (authlevel >= roles.manager) {
if (mode == 'user') if (mode == 'user')
user = term user = term
else else
@ -50,17 +40,21 @@
project project
}) })
}, sleep) }, sleep)
} else {
project = term
if (timeoutId != null)
clearTimeout(timeoutId)
timeoutId = setTimeout(() => {
dispatch('update', {
project
})
}, sleep)
} }
} }
</script> </script>
{#if authlevel == roles.user} {#if authlevel >= roles.manager}
<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 >= roles.manager}
<InputGroup> <InputGroup>
<select style="max-width: 175px;" class="form-select" <select style="max-width: 175px;" class="form-select"
bind:value={mode} on:change={modeChanged}> bind:value={mode} on:change={modeChanged}>
@ -72,5 +66,10 @@
placeholder={mode == 'user' ? 'filter username...' : 'filter project...'} /> placeholder={mode == 'user' ? 'filter username...' : 'filter project...'} />
</InputGroup> </InputGroup>
{:else} {:else}
Unauthorized <!-- Compatibility: Handle "user role" and "no role" identically-->
<InputGroup>
<Input
type="text" bind:value={term} on:change={() => termChanged()} on:keyup={(event) => termChanged(event.key == 'Enter' ? 0 : throttle)} placeholder='filter project...'
/>
</InputGroup>
{/if} {/if}