Skip to content

Commit

Permalink
Clean up CanBeSysAdmin construct.
Browse files Browse the repository at this point in the history
We move the logic to ctx where it belongs as it is the context
that determines if one is sysadmin not the user.

This resolves a clash when trying to update users's sysadmin bits
and just is more logical in the first place.
  • Loading branch information
massar committed Feb 16, 2017
1 parent 29dd820 commit 46db7e7
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 74 deletions.
2 changes: 1 addition & 1 deletion doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ The core permission code is located in lib/ctx.go with CheckPerm and lib/struct.
Permissions in pfget/pfset tag can be specified separated by commas to specify multiple permissions that would be acceptible to satisfy the permission check.
Perm's FromString function in lib/ctx handles this conversion from textual edition of a permission to the binary Perm that is used throughout.
## Sysadmin Privilege
## SysAdmin Privilege
The sysadmin privilege is gained by having the sysadmin flag set in the user's table. This can be toggled using the CLI by executing 'user set <username> sysadmin true|false' or using the user configuration UI. Of course it requires sysadmin privileges to toggle.
Expand Down
50 changes: 21 additions & 29 deletions lib/ctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ type PfCtx interface {
GroupHasWiki() bool
GroupHasFile() bool
GroupHasCalendar() bool
CanBeSysAdmin() bool
SwapSysAdmin() bool
IsSysAdmin() bool
CheckPerms(what string, perms Perm) (ok bool, err error)
Expand Down Expand Up @@ -176,6 +175,7 @@ type PfCtxS struct {
output string /* Output buffer */
mode_buffered bool /* Buffering of output in effect */
user PfUser /* Authenticated User */
is_sysadmin bool /* Whether the user's sysadmin priveleges are enabled */
token string /* The authentication token */
token_claims SessionClaims /* Parsed Token Claims */
remote string /* The address of the client, including X-Forwarded-For */
Expand Down Expand Up @@ -663,7 +663,7 @@ func (ctx *PfCtxS) NewToken() (err error) {

// Set some claims
ctx.token_claims.UserDesc = theuser.GetFullName()
ctx.token_claims.IsSysAdmin = theuser.IsSysAdmin()
ctx.token_claims.IsSysAdmin = ctx.is_sysadmin

username := theuser.GetUserName()

Expand All @@ -687,22 +687,25 @@ func (ctx *PfCtxS) NewToken() (err error) {
// (and thus indicating that a new token should be sent out to the user)
// and/or an error to indicate failure.
func (ctx *PfCtxS) LoginToken(tok string) (expsoon bool, err error) {
/* No valid token */
// No valid token
ctx.token = ""

/* Parse the provided token */
// Not a SysAdmin
ctx.is_sysadmin = false

// Parse the provided token
expsoon, err = Token_Parse(tok, "websession", &ctx.token_claims)
if err != nil {
return expsoon, err
}

/* Who they claim they are */
// Who they claim they are
user := ctx.NewUser()
user.SetUserName(ctx.token_claims.Subject)
user.SetFullName(ctx.token_claims.UserDesc)
user.SetSysAdmin(ctx.token_claims.IsSysAdmin)
ctx.is_sysadmin = ctx.token_claims.IsSysAdmin

/* Fetch the details */
// Fetch the details
err = user.Refresh(ctx)
if err == ErrNoRows {
ctx.Dbgf("No such user %q", ctx.token_claims.Subject)
Expand All @@ -712,10 +715,10 @@ func (ctx *PfCtxS) LoginToken(tok string) (expsoon bool, err error) {
return false, err
}

/* Looking good, become the user */
// Looking good, become the user
ctx.Become(user)

/* Valid Token */
// Valid Token
ctx.token = tok

return expsoon, nil
Expand All @@ -726,6 +729,7 @@ func (ctx *PfCtxS) LoginToken(tok string) (expsoon bool, err error) {
//
// A userevent is logged when this function was succesful.
func (ctx *PfCtxS) Login(username string, password string, twofactor string) (err error) {
// The new user */
user := ctx.NewUser()

err = user.CheckAuth(ctx, username, password, twofactor)
Expand All @@ -738,9 +742,12 @@ func (ctx *PfCtxS) Login(username string, password string, twofactor string) (er
return
}

/* Force generation of a new token */
// Force generation of a new token
ctx.token = ""

// Not a sysadmin till they swapadmin
ctx.is_sysadmin = false

ctx.Become(user)

userevent(ctx, "login")
Expand Down Expand Up @@ -868,21 +875,6 @@ func (ctx *PfCtxS) GroupHasCalendar() bool {
return ctx.sel_group.HasCalendar()
}

// CanBeSysAdmin returns whether the loggedin user can become a sysadmin.
func (ctx *PfCtxS) CanBeSysAdmin() bool {
if !ctx.IsLoggedIn() {
return false
}

/* Can we be or not? */
if !ctx.user.CanBeSysAdmin() {
return false
}

/* Could be, if the user wanted */
return true
}

// SwapSysAdmin swaps a user's privilege between normal user and sysadmin.
func (ctx *PfCtxS) SwapSysAdmin() bool {
/* Not logged, can't be SysAdmin */
Expand All @@ -891,12 +883,12 @@ func (ctx *PfCtxS) SwapSysAdmin() bool {
}

/* If they cannot be one, then do not toggle either */
if !ctx.user.CanBeSysAdmin() {
if !ctx.TheUser().CanBeSysAdmin() {
return false
}

/* Toggle state: SysAdmin <> Regular */
ctx.user.SetSysAdmin(!ctx.user.IsSysAdmin())
ctx.is_sysadmin = !ctx.is_sysadmin

/* Force generation of a new token */
ctx.token = ""
Expand All @@ -917,7 +909,7 @@ func (ctx *PfCtxS) IsSysAdmin() bool {
}

/* Not a SysAdmin, easy */
if !ctx.user.IsSysAdmin() {
if !ctx.is_sysadmin {
return false
}

Expand Down Expand Up @@ -1303,7 +1295,7 @@ func (ctx *PfCtxS) CheckPerms(what string, perms Perm) (ok bool, err error) {
if perms.IsSet(PERM_SYS_ADMIN_CAN) {
if ctx.IsLoggedIn() {
ctx.PDbgf(what, perms, "Sys Admin Can - Logged In")
if ctx.CanBeSysAdmin() {
if ctx.TheUser().CanBeSysAdmin() {
ctx.PDbgf(what, perms, "Sys Admin Can")
/* Passed the test */
return true, nil
Expand Down
18 changes: 12 additions & 6 deletions lib/menu.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func (ctx *PfCtxS) Menu(args []string, menu PfMenu) (err error) {
}

if arg == "help" {
/* Walk only, thus don't show help */
// Walk only, thus don't show help
if ctx.menu_walkonly {
err = errors.New("help not allowed during menuwalk")
return
Expand All @@ -128,20 +128,26 @@ func (ctx *PfCtxS) Menu(args []string, menu PfMenu) (err error) {
ctx.OutLn(AppName + " Help for: \"" + ctx.loc + "\"")
}

// Give a bit of detail about the user at the top
if ctx.IsLoggedIn() {
ss := ""
if ctx.TheUser().IsSysAdmin() {

// User is a sysadmin
if ctx.IsSysAdmin() {
ss = " [sysadmin]"
} else if ctx.TheUser().CanBeSysAdmin() {
// User can be a sysadmin, but is not
ss = " [NOT sysadmin]"
}

ctx.OutLn("User: %s%s", ctx.TheUser().GetUserName(), ss)
} else {
// User is not authenticated at all
ctx.OutLn("User: [Not authenticated]")
}
ctx.OutLn("")

/* Special introdoctcuary header at the top menu */
// Special introductuary header at the top menu
if ctx.loc == "" {
ctx.Out("" +
"Welcome to the " + AppName + " menu system which is command line interface (CLI) based.\n" +
Expand All @@ -155,7 +161,7 @@ func (ctx *PfCtxS) Menu(args []string, menu PfMenu) (err error) {
for _, m := range menu.M {
opts := ""

/* Skip menu items that are not allowed */
// Skip menu items that are not allowed
ok, _ = ctx.CheckPerms("Menu("+m.Cmd+")/help", m.Perms)
if !ok {
continue
Expand Down Expand Up @@ -202,7 +208,7 @@ func (ctx *PfCtxS) Menu(args []string, menu PfMenu) (err error) {
return
}

/* Walk Only & command & return the menu? */
// Walk Only & command & return the menu?
if m.Args != nil && ctx.menu_walkonly {
ctx.menu_menu = &m
return
Expand All @@ -220,7 +226,7 @@ func (ctx *PfCtxS) Menu(args []string, menu PfMenu) (err error) {
}
}

/* Execute the menu */
// Execute the menu
err = m.Fun(ctx, nargs)
return
}
Expand Down
2 changes: 1 addition & 1 deletion lib/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ type PfSys struct {
Welcome string `label:"Welcome Text" pftype:"text" pfset:"sysadmin" pfcol:"welcome_text" hint:"Welcome message shown on login page"`
AdminName string `label:"Name of the Administrator(s)" pfset:"sysadmin" hint:"Name of the Administrator, shown at bottom of the page"`
AdminEmail string `label:"Administrator email address" pfset:"sysadmin" hint:"Email address of the Administrator, linked at the bottom of the page"`
AdminEmailPublic bool `label:"Show Sysadmin E-mail to non-members" pfset:"sysadmin" hint:"Show SysAdmin email address in the footer of public/not-logged-in pages"`
AdminEmailPublic bool `label:"Show SysAdmin E-mail to non-members" pfset:"sysadmin" hint:"Show SysAdmin email address in the footer of public/not-logged-in pages"`
CopyYears string `label:"Copyright Years" pfset:"sysadmin" hint:"Years that copyright ownership is claimed"`
EmailDomain string `label:"Email Domain" pfset:"sysadmin" pfcol:"email_domain" hint:"The domain where emails are sourced from"`
PublicURL string `label:"Public URL" pfset:"sysadmin" pfcol:"url_public" hint:"The full URL where the system is exposed to the public, used for redirects and OAuth2 (Example: https://example.net)"`
Expand Down
38 changes: 6 additions & 32 deletions lib/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,7 @@ type PfUser interface {
GetFirstName() string
SetLastName(name string)
GetLastName() string
SetSysAdmin(isone bool)
CanBeSysAdmin() bool
IsSysAdmin() bool
GetLoginAttempts() int
GetUuid() string
GetAffiliation() string
Expand Down Expand Up @@ -101,8 +99,7 @@ type PfUserS struct {
Telephone string `label:"Telephone" pftype:"tel" pfset:"self" pfget:"user_view" pfcol:"tel_info" hint:"The phone number where to contact the user using voice messages"`
Airport string `label:"Airport" min:"3" max:"3" pfset:"self" pfget:"user_view" hint:"Closest airport for this user"`
Biography string `label:"Biography" pftype:"text" pfset:"self" pfget:"user_view" pfcol:"bio_info" hint:"Biography for this user"`
IsSysadmin bool `label:"System Administrator" pfset:"sysadmin" pfget:"group_admin" pfskipfailperm:"yes" pfcol:"sysadmin" hint:"Whether the user is a System Administrator"`
CanBeSysadmin bool `label:"Can Be System Administrator" pfset:"nobody" pfget:"nobody" pfskipfailperm:"yes" pfcol:"sysadmin" hint:"If the user can toggle between Regular and SysAdmin usermode"`
IsSysAdmin bool `label:"System Administrator" pfset:"sysadmin" pfget:"group_admin" pfskipfailperm:"yes" pfcol:"sysadmin" hint:"Whether the user is a System Administrator"`
LoginAttempts int `label:"Number of failed Login Attempts" pfset:"self,group_admin" pfget:"group_admin" pfskipfailperm:"yes" pfcol:"login_attempts" hint:"How many failed login attempts have been registered"`
No_email bool `label:"Email Disabled" pfset:"sysadmin" pfget:"self,group_admin" pfskipfailperm:"yes" hint:"Email address is disabled due to SMTP errors"`
Hide_email bool `label:"Hide email address" pfset:"self" pfget:"self" pfskipfailperm:"yes" hint:"Hide my domain name when forwarding group emails, helpful for DMARC and SPF"`
Expand Down Expand Up @@ -165,16 +162,9 @@ func (user *PfUserS) GetLastName() string {
return user.LastName
}

func (user *PfUserS) SetSysAdmin(isone bool) {
user.IsSysadmin = isone
}

// Whether the user can be a sysadmin when they swap to it
func (user *PfUserS) CanBeSysAdmin() bool {
return user.CanBeSysadmin
}

func (user *PfUserS) IsSysAdmin() bool {
return user.IsSysadmin
return user.IsSysAdmin
}

func (user *PfUserS) GetLoginAttempts() int {
Expand Down Expand Up @@ -271,9 +261,6 @@ func (user *PfUserS) GetList(ctx PfCtx, search string, offset int, max int, exac
}

func (user *PfUserS) fetch(ctx PfCtx, username string) (err error) {
/* Retain SysAdmin bit */
sysadminbit := user.IsSysadmin

/* Force lower case username */
username = strings.ToLower(username)

Expand All @@ -296,19 +283,6 @@ func (user *PfUserS) fetch(ctx PfCtx, username string) (err error) {
err = user.f_postfetch(ctx, user, username, err)
}

/* Do not retain the bit when the fetch failed */
if err == nil {
/* Can be a SysAdmin? */
user.CanBeSysadmin = user.IsSysadmin

/* Retain SysAdmin bit */
user.IsSysadmin = sysadminbit
} else {
/* No sysadmin for this user */
user.CanBeSysadmin = false
user.IsSysadmin = false
}

return
}

Expand Down Expand Up @@ -1095,8 +1069,8 @@ func user_pw_set(ctx PfCtx, args []string) (err error) {

user := ctx.SelectedUser()

/* Sysadmins don't need a password */
if !ctx.TheUser().IsSysAdmin() {
/* SysAdmins don't need a password */
if !ctx.IsSysAdmin() {
curpass := args[3]
/* Check that the current password is correct */
err = user.Verify_Password(ctx, curpass)
Expand All @@ -1115,7 +1089,7 @@ func user_pw_set(ctx PfCtx, args []string) (err error) {
ctx.SelectUser("", PERM_NONE)

/* If we're doing this as a sysadmin, don't logout */
if !ctx.TheUser().IsSysAdmin() {
if !ctx.IsSysAdmin() {
/* Require users to re-authenticate after password changes */
if user == ctx.TheUser() {
ctx.Logout()
Expand Down
8 changes: 4 additions & 4 deletions lib/user_2fa.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ func user_2fa_add(ctx PfCtx, args []string) (err error) {
user := ctx.SelectedUser()

/* SysAdmins can bypass the password check */
if !ctx.TheUser().IsSysAdmin() {
if !ctx.IsSysAdmin() {
err = user.Verify_Password(ctx, pw)
if err != nil {
return
Expand Down Expand Up @@ -475,7 +475,7 @@ func user_2fa_active_mod(ctx PfCtx, id string, curpassword string, active bool,
user := ctx.SelectedUser()

/* SysAdmins can bypass the password check */
if !ctx.TheUser().IsSysAdmin() {
if !ctx.IsSysAdmin() {
err = user.Verify_Password(ctx, curpassword)
if err != nil {
return
Expand All @@ -492,7 +492,7 @@ func user_2fa_active_mod(ctx PfCtx, id string, curpassword string, active bool,
return
}

if !ctx.TheUser().IsSysAdmin() && user.GetUserName() != member {
if !ctx.IsSysAdmin() && user.GetUserName() != member {
ctx.Log("User " + user.GetUserName() + " attempted to access token " + id + " of user " + member)
err = errors.New("No such token")
return
Expand Down Expand Up @@ -582,7 +582,7 @@ func user_2fa_remove(ctx PfCtx, args []string) (err error) {
pw := args[2]

/* SysAdmins can bypass the password check */
if !ctx.TheUser().IsSysAdmin() {
if !ctx.IsSysAdmin() {
err = user.Verify_Password(ctx, pw)
if err != nil {
return
Expand Down
2 changes: 1 addition & 1 deletion share/templates/inc/header_notitle.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
{{ if .Version }}<li>Trident {{ .Version }}</li>
{{ end }}{{ if .TheUser }}<li>{{ csrf_form_param .UI "/search/" "id=\"searchbox\"" }}<input type="text" name="q" autocomplete="off" placeholder="Search..." /></form></li>
<li>{{ user_home_link .UI .TheUser.GetUserName .TheUser.GetFullName }}</li>
{{ if .TheUser.CanBeSysAdmin }}<li>UserMode: <a href="?xtra=swapadmin" title="Swap between SysAdmin and a Regular user">{{ if .TheUser.IsSysAdmin }}<b>SysAdmin</b>{{ else }}Regular{{ end }}</a></li>{{ end }}
{{ if .TheUser.CanBeSysAdmin }}<li>UserMode: <a href="?xtra=swapadmin" title="Swap between SysAdmin and a Regular user">{{ if .UI.IsSysAdmin }}<b>SysAdmin</b>{{ else }}Regular{{ end }}</a></li>{{ end }}
<li><a href="/logout/">Logout</a></li>{{ end }}
</ul></div>{{ end }}
<div class="content">
Expand Down

0 comments on commit 46db7e7

Please sign in to comment.