s/whitelist/allowlist/

This commit is contained in:
mik2k2 2021-12-23 18:58:03 +01:00
parent dbc0bdbeac
commit 110aca2e8b
5 changed files with 74 additions and 74 deletions

64
auth.go
View File

@ -18,9 +18,9 @@ import (
"golang.org/x/crypto/ssh"
)
// ErrNotWhitelisted Is the error returned when a key is checked that is not whitelisted,
// when whitelisting is enabled.
var ErrNotWhitelisted = errors.New("not whitelisted")
// ErrNotAllowlisted Is the error returned when a key is checked that is not allowlisted,
// when allowlisting is enabled.
var ErrNotAllowlisted = errors.New("not allowlisted")
// ErrBanned is the error returned when a client is banned.
var ErrBanned = errors.New("banned")
@ -50,19 +50,19 @@ func newAuthAddr(addr net.Addr) string {
return host
}
// Auth stores lookups for bans, whitelists, and ops. It implements the sshd.Auth interface.
// If the contained passphrase is not empty, it complements a whitelist.
// Auth stores lookups for bans, allowlists, and ops. It implements the sshd.Auth interface.
// If the contained passphrase is not empty, it complements a allowlist.
type Auth struct {
passphraseHash []byte
whitelistModeMu sync.RWMutex
whitelistMode bool
allowlistModeMu sync.RWMutex
allowlistMode bool
bannedAddr *set.Set
bannedClient *set.Set
banned *set.Set
whitelist *set.Set
allowlist *set.Set
ops *set.Set
opFile string
whitelistFile string
allowlistFile string
}
// NewAuth creates a new empty Auth.
@ -71,21 +71,21 @@ func NewAuth() *Auth {
bannedAddr: set.New(),
bannedClient: set.New(),
banned: set.New(),
whitelist: set.New(),
allowlist: set.New(),
ops: set.New(),
}
}
func (a *Auth) WhitelistMode() bool {
a.whitelistModeMu.RLock()
defer a.whitelistModeMu.RUnlock()
return a.whitelistMode
func (a *Auth) AllowlistMode() bool {
a.allowlistModeMu.RLock()
defer a.allowlistModeMu.RUnlock()
return a.allowlistMode
}
func (a *Auth) SetWhitelistMode(value bool) {
a.whitelistModeMu.Lock()
defer a.whitelistModeMu.Unlock()
a.whitelistMode = value
func (a *Auth) SetAllowlistMode(value bool) {
a.allowlistModeMu.Lock()
defer a.allowlistModeMu.Unlock()
a.allowlistMode = value
}
// SetPassphrase enables passphrase authentication with the given passphrase.
@ -101,7 +101,7 @@ func (a *Auth) SetPassphrase(passphrase string) {
// AllowAnonymous determines if anonymous users are permitted.
func (a *Auth) AllowAnonymous() bool {
return !a.WhitelistMode() && a.passphraseHash == nil
return !a.AllowlistMode() && a.passphraseHash == nil
}
// AcceptPassphrase determines if passphrase authentication is accepted.
@ -134,11 +134,11 @@ func (a *Auth) CheckBans(addr net.Addr, key ssh.PublicKey, clientVersion string)
// CheckPubkey determines if a pubkey fingerprint is permitted.
func (a *Auth) CheckPublicKey(key ssh.PublicKey) error {
authkey := newAuthKey(key)
whitelisted := a.whitelist.In(authkey)
if a.AllowAnonymous() || whitelisted || a.IsOp(key) {
allowlisted := a.allowlist.In(authkey)
if a.AllowAnonymous() || allowlisted || a.IsOp(key) {
return nil
} else {
return ErrNotWhitelisted
return ErrNotAllowlisted
}
}
@ -180,29 +180,29 @@ func (a *Auth) LoadOpsFromFile(path string) error {
return fromFile(path, func(key ssh.PublicKey) { a.Op(key, 0) })
}
// Whitelist will set a public key as a whitelisted user.
func (a *Auth) Whitelist(key ssh.PublicKey, d time.Duration) {
// Allowlist will set a public key as a allowlisted user.
func (a *Auth) Allowlist(key ssh.PublicKey, d time.Duration) {
if key == nil {
return
}
var err error
authItem := newAuthItem(key)
if d != 0 {
err = a.whitelist.Set(set.Expire(authItem, d))
err = a.allowlist.Set(set.Expire(authItem, d))
} else {
err = a.whitelist.Set(authItem)
err = a.allowlist.Set(authItem)
}
if err == nil {
logger.Debugf("Added to whitelist: %q (for %s)", authItem.Key(), d)
logger.Debugf("Added to allowlist: %q (for %s)", authItem.Key(), d)
} else {
logger.Errorf("Error adding %q to whitelist for %s: %s", authItem.Key(), d, err)
logger.Errorf("Error adding %q to allowlist for %s: %s", authItem.Key(), d, err)
}
}
// LoadWhitelistFromFile reads a file in authorized_keys format and whitelists public keys
func (a *Auth) LoadWhitelistFromFile(path string) error {
a.whitelistFile = path
return fromFile(path, func(key ssh.PublicKey) { a.Whitelist(key, 0) })
// LoadAllowlistFromFile reads a file in authorized_keys format and allowlists public keys
func (a *Auth) LoadAllowlistFromFile(path string) error {
a.allowlistFile = path
return fromFile(path, func(key ssh.PublicKey) { a.Allowlist(key, 0) })
}
// Ban will set a public key as banned.

View File

@ -21,7 +21,7 @@ func ClonePublicKey(key ssh.PublicKey) (ssh.PublicKey, error) {
return ssh.ParsePublicKey(key.Marshal())
}
func TestAuthWhitelist(t *testing.T) {
func TestAuthAllowlist(t *testing.T) {
key, err := NewRandomPublicKey(512)
if err != nil {
t.Fatal(err)
@ -33,8 +33,8 @@ func TestAuthWhitelist(t *testing.T) {
t.Error("Failed to permit in default state:", err)
}
auth.Whitelist(key, 0)
auth.SetWhitelistMode(true)
auth.Allowlist(key, 0)
auth.SetAllowlistMode(true)
keyClone, err := ClonePublicKey(key)
if err != nil {
@ -47,7 +47,7 @@ func TestAuthWhitelist(t *testing.T) {
err = auth.CheckPublicKey(keyClone)
if err != nil {
t.Error("Failed to permit whitelisted:", err)
t.Error("Failed to permit allowlisted:", err)
}
key2, err := NewRandomPublicKey(512)
@ -57,7 +57,7 @@ func TestAuthWhitelist(t *testing.T) {
err = auth.CheckPublicKey(key2)
if err == nil {
t.Error("Failed to restrict not whitelisted:", err)
t.Error("Failed to restrict not allowlisted:", err)
}
}

View File

@ -34,8 +34,8 @@ type Options struct {
Pprof int `long:"pprof" description:"Enable pprof http server for profiling."`
Verbose []bool `short:"v" long:"verbose" description:"Show verbose logging."`
Version bool `long:"version" description:"Print version and exit."`
Whitelist string `long:"whitelist" description:"Optional file of public keys who are allowed to connect."`
Passphrase string `long:"unsafe-passphrase" description:"Require an interactive passphrase to connect. Whitelist feature is more secure."`
Allowlist string `long:"allowlist" description:"Optional file of public keys who are allowed to connect."`
Passphrase string `long:"unsafe-passphrase" description:"Require an interactive passphrase to connect. Allowlist feature is more secure."`
}
const extraHelp = `There are hidden options and easter eggs in ssh-chat. The source code is a good
@ -144,11 +144,11 @@ func main() {
fail(5, "Failed to load admins: %v\n", err)
}
err = auth.LoadWhitelistFromFile(options.Whitelist)
err = auth.LoadAllowlistFromFile(options.Allowlist)
if err != nil {
fail(6, "Failed to load whitelist: %v\n", err)
fail(6, "Failed to load allowlist: %v\n", err)
}
auth.SetWhitelistMode(options.Whitelist != "")
auth.SetAllowlistMode(options.Allowlist != "")
if options.Motd != "" {
host.GetMOTD = func() (string, error) {

36
host.go
View File

@ -780,7 +780,7 @@ func (h *Host) InitCommands(c *chat.Commands) {
if pk == nil {
noKeyUsers = append(noKeyUsers, user.Identifier.Name())
} else {
h.auth.Whitelist(pk, 0)
h.auth.Allowlist(pk, 0)
}
}
return nil
@ -796,13 +796,13 @@ func (h *Host) InitCommands(c *chat.Commands) {
return errors.New("must specify whether to keep or flush current entries")
}
if args[0] == "flush" {
h.auth.whitelist.Clear()
h.auth.allowlist.Clear()
}
return h.auth.LoadWhitelistFromFile(h.auth.whitelistFile)
return h.auth.LoadAllowlistFromFile(h.auth.allowlistFile)
}
allowlistReverify := func(room *chat.Room) []string {
if !h.auth.WhitelistMode() {
if !h.auth.AllowlistMode() {
return []string{"allowlist is disabled, so nobody will be kicked"}
}
var kicked []string
@ -820,32 +820,32 @@ func (h *Host) InitCommands(c *chat.Commands) {
}
allowlistStatus := func() (msgs []string) {
if h.auth.WhitelistMode() {
if h.auth.AllowlistMode() {
msgs = []string{"The allowlist is currently enabled."}
} else {
msgs = []string{"The allowlist is currently disabled."}
}
whitelistedUsers := []string{}
whitelistedKeys := []string{}
h.auth.whitelist.Each(func(key string, item set.Item) error {
allowlistedUsers := []string{}
allowlistedKeys := []string{}
h.auth.allowlist.Each(func(key string, item set.Item) error {
keyFP := item.Key()
if forConnectedUsers(func(user *chat.Member, pk ssh.PublicKey) error {
if pk != nil && sshd.Fingerprint(pk) == keyFP {
whitelistedUsers = append(whitelistedUsers, user.Name())
allowlistedUsers = append(allowlistedUsers, user.Name())
return errors.New("not an actual error, but exit early because we found the key")
}
return nil
}) == nil {
// if we land here, the key matches no users
whitelistedKeys = append(whitelistedKeys, keyFP)
allowlistedKeys = append(allowlistedKeys, keyFP)
}
return nil
})
if len(whitelistedUsers) != 0 {
msgs = append(msgs, fmt.Sprintf("The following connected users are on the allowlist: %v", whitelistedUsers))
if len(allowlistedUsers) != 0 {
msgs = append(msgs, fmt.Sprintf("The following connected users are on the allowlist: %v", allowlistedUsers))
}
if len(whitelistedKeys) != 0 {
msgs = append(msgs, fmt.Sprintf("The following keys of not connected users are on the allowlist: %v", whitelistedKeys))
if len(allowlistedKeys) != 0 {
msgs = append(msgs, fmt.Sprintf("The following keys of not connected users are on the allowlist: %v", allowlistedKeys))
}
return
}
@ -872,13 +872,13 @@ func (h *Host) InitCommands(c *chat.Commands) {
case "help":
replyLines = allowlistHelptext
case "on":
h.auth.SetWhitelistMode(true)
h.auth.SetAllowlistMode(true)
case "off":
h.auth.SetWhitelistMode(false)
h.auth.SetAllowlistMode(false)
case "add":
replyLines = forPubkeyUser(args[1:], func(pk ssh.PublicKey) { h.auth.Whitelist(pk, 0) })
replyLines = forPubkeyUser(args[1:], func(pk ssh.PublicKey) { h.auth.Allowlist(pk, 0) })
case "remove":
replyLines = forPubkeyUser(args[1:], func(pk ssh.PublicKey) { h.auth.Whitelist(pk, 1) })
replyLines = forPubkeyUser(args[1:], func(pk ssh.PublicKey) { h.auth.Allowlist(pk, 1) })
case "import":
replyLines, err = allowlistImport(args[1:])
case "reload":

View File

@ -173,7 +173,7 @@ func TestHostNameCollision(t *testing.T) {
}
}
func TestHostWhitelist(t *testing.T) {
func TestHostAllowlist(t *testing.T) {
auth := NewAuth()
s, host := getHost(t, auth)
defer s.Close()
@ -192,12 +192,12 @@ func TestHostWhitelist(t *testing.T) {
}
clientpubkey, _ := ssh.NewPublicKey(clientkey.Public())
auth.Whitelist(clientpubkey, 0)
auth.SetWhitelistMode(true)
auth.Allowlist(clientpubkey, 0)
auth.SetAllowlistMode(true)
err = sshd.ConnectShell(target, "foo", func(r io.Reader, w io.WriteCloser) error { return nil })
if err == nil {
t.Error("Failed to block unwhitelisted connection.")
t.Error("Failed to block unallowlisted connection.")
}
}
@ -268,52 +268,52 @@ func TestHostAllowlistCommand(t *testing.T) {
}
sendCmd("/allowlist on")
if !host.auth.WhitelistMode() {
if !host.auth.AllowlistMode() {
t.Error("allowlist not enabled after /allowlist on")
}
sendCmd("/allowlist off")
if host.auth.WhitelistMode() {
if host.auth.AllowlistMode() {
t.Error("allowlist not disabled after /allowlist off")
}
testKey := "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPUiNw0nQku4pcUCbZcJlIEAIf5bXJYTy/DKI1vh5b+P"
testKeyFP := "SHA256:GJNSl9NUcOS2pZYALn0C5Qgfh5deT+R+FfqNIUvpM9s="
if host.auth.whitelist.Len() != 0 {
if host.auth.allowlist.Len() != 0 {
t.Error("allowlist not empty before adding anyone")
}
sendCmd("/allowlist add ssh-invalid blah ssh-rsa wrongAsWell invalid foo bar %s", testKey)
assertLineEq("users without a public key: [foo]\r")
assertLineEq("invalid users: [invalid]\r")
assertLineEq("invalid keys: [ssh-invalid blah ssh-rsa wrongAsWell]\r")
if !host.auth.whitelist.In(testKeyFP) || !host.auth.whitelist.In(clientKeyFP) {
if !host.auth.allowlist.In(testKeyFP) || !host.auth.allowlist.In(clientKeyFP) {
t.Error("failed to add keys to allowlist")
}
sendCmd("/allowlist remove invalid bar")
assertLineEq("invalid users: [invalid]\r")
if host.auth.whitelist.In(clientKeyFP) {
if host.auth.allowlist.In(clientKeyFP) {
t.Error("failed to remove key from allowlist")
}
if !host.auth.whitelist.In(testKeyFP) {
if !host.auth.allowlist.In(testKeyFP) {
t.Error("removed wrong key")
}
sendCmd("/allowlist import 5h")
if host.auth.whitelist.In(clientKeyFP) {
if host.auth.allowlist.In(clientKeyFP) {
t.Error("imporrted key not seen long enough")
}
sendCmd("/allowlist import")
assertLineEq("users without a public key: [foo]\r")
if !host.auth.whitelist.In(clientKeyFP) {
if !host.auth.allowlist.In(clientKeyFP) {
t.Error("failed to import key")
}
sendCmd("/allowlist reload keep")
if !host.auth.whitelist.In(testKeyFP) {
if !host.auth.allowlist.In(testKeyFP) {
t.Error("cleared allowlist to be kept")
}
sendCmd("/allowlist reload flush")
if host.auth.whitelist.In(testKeyFP) {
if host.auth.allowlist.In(testKeyFP) {
t.Error("kept allowlist to be cleared")
}
sendCmd("/allowlist reload thisIsWrong")