From f54512e3347fa9887ece8b6f2cf5023ebbbd6654 Mon Sep 17 00:00:00 2001 From: Michael Mayer Date: Tue, 14 Feb 2023 20:28:47 +0100 Subject: [PATCH] Auth: Refactor user management commands #98 Signed-off-by: Michael Mayer --- .ldap.cfg | 43 +++++++++++++++++++++++++++++++ docker-compose.yml | 1 + internal/commands/users_legacy.go | 4 +-- internal/commands/users_list.go | 4 +-- internal/entity/auth_user.go | 19 +++++++++----- internal/entity/auth_user_test.go | 24 +++++++++++++++++ 6 files changed, 85 insertions(+), 10 deletions(-) diff --git a/.ldap.cfg b/.ldap.cfg index 0c4212509..e6af759a0 100644 --- a/.ldap.cfg +++ b/.ldap.cfg @@ -16,12 +16,17 @@ debug = true [backend] datastore = "config" baseDN = "dc=localssl,dc=dev" + [[users]] name = "user" givenname = "John" objectClass = "user" displayName = "John Doe" sn = "Doe" + uidnumber = 5003 + primarygroup = 5501 + loginShell = "/bin/sh" + otherGroups = [5505,5506,5507] userPrincipalName = "jdoe@example.com" mail = "jdoe@example.com" passsha256 = "4314c1fe282face45336b1422a3285c5ff31a39c8e24425615fa53a43b718493" # photoprism @@ -32,6 +37,7 @@ debug = true [[users.capabilities]] action = "search" object = "*" + [[users]] name = "bob" givenname = "Bob" @@ -40,6 +46,10 @@ debug = true sn = "Jones" userPrincipalName = "bob@example.com" mail = "bob@example.com" + uidnumber = 5005 + primarygroup = 5502 + loginShell = "/bin/bash" + otherGroups = [5505,5506] passsha256 = "4314c1fe282face45336b1422a3285c5ff31a39c8e24425615fa53a43b718493" # photoprism [[users.customattributes]] photoprismRoleUser = ["true"] @@ -49,6 +59,7 @@ debug = true [[users.capabilities]] action = "search" object = "*" + [[users]] name = "guest" objectClass = "user" @@ -56,9 +67,41 @@ debug = true displayName = "Guest User" userPrincipalName = "guest@example.com" mail = "guest@example.com" + uidnumber = 5006 + primarygroup = 5503 + loginShell = "/bin/sh" + otherGroups = [5505,5507] passsha256 = "4314c1fe282face45336b1422a3285c5ff31a39c8e24425615fa53a43b718493" # photoprism [[users.customattributes]] photoprismRole = ["guest"] [[users.capabilities]] action = "search" object = "*" + +[[groups]] + name = "PhotoPrism-admin" + gidnumber = 5501 + +[[groups]] + name = "PhotoPrism-user" + gidnumber = 5502 + +[[groups]] + name = "PhotoPrism-guest" + gidnumber = 5503 + +[[groups]] + name = "PhotoPrism-visitor" + gidnumber = 5504 + +[[groups]] + name = "gmail" + gidnumber = 5505 + +[[groups]] + name = "email" + gidnumber = 5506 + +[[groups]] + name = "ssh" + gidnumber = 5507 diff --git a/docker-compose.yml b/docker-compose.yml index 243211af1..8ed07bd1b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -51,6 +51,7 @@ services: PHOTOPRISM_LDAP_BIND: "simple" PHOTOPRISM_LDAP_BIND_DN: "cn" PHOTOPRISM_LDAP_BASE_DN: "dc=localssl,dc=dev" + PHOTOPRISM_LDAP_ROLE_DN: "ou=photoprism-*,ou=groups,dc=localssl,dc=dev" PHOTOPRISM_LDAP_SYNC: "true" ## OpenID Connect (pre-configured for local tests): PHOTOPRISM_OIDC_URI: "https://keycloak.localssl.dev/auth/realms/master" diff --git a/internal/commands/users_legacy.go b/internal/commands/users_legacy.go index a293259b8..922657944 100644 --- a/internal/commands/users_legacy.go +++ b/internal/commands/users_legacy.go @@ -23,7 +23,7 @@ var UsersLegacyCommand = cli.Command{ // usersLegacyAction displays legacy user accounts. func usersLegacyAction(ctx *cli.Context) error { return CallWithDependencies(ctx, func(conf *config.Config) error { - cols := []string{"ID", "UID", "User Name", "Display Name", "Email", "Admin", "Created At"} + cols := []string{"ID", "UID", "Name", "User", "Email", "Admin", "Created At"} // Fetch users from database. users := entity.FindLegacyUsers(ctx.Args().First()) @@ -37,8 +37,8 @@ func usersLegacyAction(ctx *cli.Context) error { rows[i] = []string{ fmt.Sprintf("%d", user.ID), user.UserUID, - user.UserName, user.FullName, + user.UserName, user.PrimaryEmail, report.Bool(user.Admin(), report.Yes, report.No), user.CreatedAt.Format("2006-01-02 15:04:05"), diff --git a/internal/commands/users_list.go b/internal/commands/users_list.go index 3568858e6..1012138ad 100644 --- a/internal/commands/users_list.go +++ b/internal/commands/users_list.go @@ -23,7 +23,7 @@ var UsersListCommand = cli.Command{ // usersListAction displays existing user accounts. func usersListAction(ctx *cli.Context) error { return CallWithDependencies(ctx, func(conf *config.Config) error { - cols := []string{"User", "Login", "Full Name", "Email", "Role", "Super Admin", "Web UI", "WebDAV", "Attributes", "Created At"} + cols := []string{"UID", "Name", "User", "Email", "Role", "Super Admin", "Web Login", "WebDAV", "Attributes", "Created At"} // Fetch users from database. users := query.RegisteredUsers() @@ -36,8 +36,8 @@ func usersListAction(ctx *cli.Context) error { for i, user := range users { rows[i] = []string{ user.UID(), - user.Login(), user.FullName(), + user.Login(), user.Email(), user.AclRole().String(), report.Bool(user.SuperAdmin, report.Yes, report.No), diff --git a/internal/entity/auth_user.go b/internal/entity/auth_user.go index 97b8c49e6..9a3723e8e 100644 --- a/internal/entity/auth_user.go +++ b/internal/entity/auth_user.go @@ -879,11 +879,18 @@ func (m *User) SetAvatar(thumb, thumbSrc string) error { return m.Updates(Values{"Thumb": m.Thumb, "ThumbSrc": m.ThumbSrc}) } -// Login returns the login name and provider. +// Login returns the username. func (m *User) Login() string { - if m.AuthProvider == "" || strings.ContainsRune(m.UserName, '@') { - return m.UserName - } else { - return fmt.Sprintf("%s@%s", m.UserName, m.AuthProvider) - } + return m.UserName +} + +// Provider returns the authentication provider name. +func (m *User) Provider() string { + if m.AuthProvider != "" { + return m.AuthProvider + } else if m.UserName != "" && m.ID > 0 { + return "password" + } + + return "" } diff --git a/internal/entity/auth_user_test.go b/internal/entity/auth_user_test.go index 6f8bca592..9d9d217e7 100644 --- a/internal/entity/auth_user_test.go +++ b/internal/entity/auth_user_test.go @@ -814,3 +814,27 @@ func TestUser_SetAvatar(t *testing.T) { assert.Equal(t, SrcManual, m.ThumbSrc) }) } + +func TestUser_Login(t *testing.T) { + t.Run("Visitor", func(t *testing.T) { + assert.Equal(t, "", Visitor.Login()) + }) + t.Run("UnknownUser", func(t *testing.T) { + assert.Equal(t, "", UnknownUser.Login()) + }) + t.Run("Admin", func(t *testing.T) { + assert.Equal(t, "admin", Admin.Login()) + }) +} + +func TestUser_Provider(t *testing.T) { + t.Run("Visitor", func(t *testing.T) { + assert.Equal(t, "", Visitor.Provider()) + }) + t.Run("UnknownUser", func(t *testing.T) { + assert.Equal(t, "", UnknownUser.Provider()) + }) + t.Run("Admin", func(t *testing.T) { + assert.Equal(t, "password", Admin.Provider()) + }) +}