This is an automated email from the git hooks/post-receive script. New commit to branch bow-v2-go in repository bow. See https://gitlab.nuiton.org/chorem/bow.git commit 68ec100266d7d70c79f77266065523cfc5d09ed5 Author: Benjamin <poussin@codelutin.com> Date: Thu Apr 30 01:37:07 2020 +0200 reprise de la secu de la base pour les alias public les roles sont crees/supprimes par des triggers ajout des actions d'alias --- README.md | 5 ++ migrate/001_init_schema.sql | 106 +++++++++++++++++++++++++++++++---- pkg/http/opensearchResource.go | 16 +++--- pkg/repository/bookmarkRepository.go | 24 ++++++++ pkg/repository/userRepository.go | 10 ---- 5 files changed, 134 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 792aab1..2282293 100644 --- a/README.md +++ b/README.md @@ -10,3 +10,8 @@ go run cmd/bow/main.go cd web yarn serve + + +== TODO +- verifier que les contraintes n'unicitées sont bien respectées (alias public) +- faire une action noop qui charge juste la page demander mais en plus la met dans l'historique des actions faites diff --git a/migrate/001_init_schema.sql b/migrate/001_init_schema.sql index 40500a2..34bf5db 100644 --- a/migrate/001_init_schema.sql +++ b/migrate/001_init_schema.sql @@ -155,24 +155,30 @@ CREATE TRIGGER update_BowUser_updateDate BEFORE INSERT OR UPDATE ON BowUser FOR CREATE TRIGGER update_bowgroup_updateDate BEFORE INSERT OR UPDATE ON bowgroup FOR EACH ROW EXECUTE PROCEDURE update_updateDate_column(); CREATE TRIGGER update_Bookmark_updateDate BEFORE INSERT OR UPDATE ON Bookmark FOR EACH ROW EXECUTE PROCEDURE update_updateDate_column(); +-- -------------- S E C U R I T Y -------------- -- + -- nobody n'herite pas des droits des autres pour le force a faire un "set role" CREATE USER nobody WITH NOINHERIT CREATEROLE LOGIN PASSWORD '{{.nobody_password}}' +CREATE ROLE person; + -- l'utilisateur nobody a le droit d'inserer des users (creation de compte) et c'est lui qui visite les pages GRANT INSERT ON bowUser TO nobody; GRANT INSERT ON pageHistory TO nobody; +-- l'utilisateur nobody a le droit de lire les alias public et l'uri pour permettre la recheche et donc l'utilisation des alias public +GRANT SELECT(uri, publicAlias) ON bookmark TO nobody; -- tout le monde a le droit de faire certaine chose, on restraint les updates au champs qui peuvent varier -GRANT SELECT, DELETE, TRIGGER ON bowUser TO PUBLIC; -GRANT UPDATE (updateDate, password, tokens, emails, unconfirmedEmails, authenticationInfo, autoScreenshot, autoFavicon, maxTagInCloud, maxResult, actions) ON bowUser TO PUBLIC; -GRANT SELECT, INSERT, DELETE, TRIGGER ON bowgroup TO PUBLIC; -GRANT UPDATE(updateDate, description, tokens, admin, writer, reader) ON bowgroup TO PUBLIC; -GRANT SELECT, INSERT, DELETE, TRIGGER ON bookmark TO PUBLIC; -GRANT UPDATE(uri, description, tags, updateDate, privateAlias, publicAlias, authenticationInfo, favicon, screenshot, visit, lang) ON bookmark TO PUBLIC; +GRANT SELECT, DELETE, TRIGGER ON bowUser TO person; +GRANT UPDATE (updateDate, password, tokens, emails, unconfirmedEmails, authenticationInfo, autoScreenshot, autoFavicon, maxTagInCloud, maxResult, actions) ON bowUser TO person; +GRANT SELECT, INSERT, DELETE, TRIGGER ON bowgroup TO person; +GRANT UPDATE(updateDate, description, tokens, admin, writer, reader) ON bowgroup TO person; +GRANT SELECT, INSERT, DELETE, TRIGGER ON bookmark TO person; +GRANT UPDATE(uri, description, tags, updateDate, privateAlias, personAlias, authenticationInfo, favicon, screenshot, visit, lang) ON bookmark TO person; -- on ne peut pas modifier une action, mais on peut la supprimer -GRANT SELECT, INSERT, DELETE, TRIGGER ON actionHistory TO PUBLIC; +GRANT SELECT, INSERT, DELETE, TRIGGER ON actionHistory TO person; -- on ne peut que lire les historiques de pages -GRANT SELECT ON pageHistory TO PUBLIC; +GRANT SELECT ON pageHistory TO person; ALTER TABLE bowUser ENABLE ROW LEVEL SECURITY; ALTER TABLE bowgroup ENABLE ROW LEVEL SECURITY; @@ -199,9 +205,9 @@ CREATE POLICY bowgroup_access_update ON bowgroup FOR UPDATE USING (admin @> ('{' || current_user || '}')::uuid[]); --- tout le monde peut creer des bookmarks, mais a la fin le createur doit etre owner +-- tout le monde peut lire les url et les publicAlias des bookmarks (peut etre faire une table PublicAlias pour les sortir) CREATE POLICY bookmark_access ON bookmark - USING (owner = current_user::uuid); + USING (true); -- si un bookmark a comme tag '@toto' et proprietaire '1234' alors il est visible de toutes les utilisateurs -- appartenant (admin, writer, reader) au groupe 'toto' dont l'utilisateur '1234' est admin ou writer @@ -216,6 +222,7 @@ CREATE POLICY actionHistory_access ON actionHistory -- droit specifique pour nobody -- il peut lire tous les id, login, email, password -- il peut creer de nouveau utilisateur +-- il peut faire des recherches sur les alias publics CREATE POLICY bowUser_nobody_access ON bowUser FOR SELECT TO nobody @@ -226,8 +233,87 @@ CREATE POLICY bowUser_nobody_insert ON bowUser TO nobody WITH CHECK (true); +CREATE POLICY bookmark_nobody_access on bookmark + FOR SELECT + TO nobody + USING (true); + +-- creation automatique des roles lors de la creation d'un compte +CREATE OR REPLACE FUNCTION create_role() +RETURNS TRIGGER AS $$ +DECLARE + id varchar := NEW."id"; +BEGIN + -- creation du role pour l'utilisateur + execute 'CREATE ROLE "' || id || '"'; + -- nobody peut prendre ce role + execute 'GRANT "' || id || '" TO nobody'; + -- les users font parti du role person + execute 'GRANT person TO "' || id || '"'; + + RETURN NEW; +END; +$$ language 'plpgsql'; + +-- suppression automatique des roles lors de la suppression d'un compte +CREATE OR REPLACE FUNCTION delete_role() +RETURNS TRIGGER AS $$ +DECLARE + id varchar := OLD."id"; +BEGIN + execute 'DROP ROLE IF EXISTS "' || id || '"'; + + RETURN OLD; +END; +$$ language 'plpgsql'; + +CREATE TRIGGER create_role AFTER INSERT ON bowUser + FOR EACH ROW EXECUTE PROCEDURE create_role(); + +CREATE TRIGGER delete_role AFTER DELETE ON bowUser + FOR EACH ROW EXECUTE PROCEDURE delete_role(); + + ---- create above / drop below ---- +DROP TRIGGER create_role ON bowUser; +DROP TRIGGER delete_role ON bowUser; + +DROP FUNCTION delete_role; +DROP FUNCTION create_role; + +DROP POLICY bookmark_nobody_access ON bookmark; +DROP POLICY bowUser_nobody_insert ON bowUser; +DROP POLICY bowUser_nobody_access ON bowUser; +DROP POLICY actionHistory_access ON actionHistory; +DROP POLICY bookmark_access_group ON bookmark; +DROP POLICY bookmark_access ON bookmark; +DROP POLICY bowgroup_access_update ON bowgroup; +DROP POLICY bowgroup_access_insert ON bowgroup; +DROP POLICY bowgroup_access_select ON bowgroup; +DROP POLICY bowUser_access ON bowUser; + +ALTER TABLE bowUser DISABLE ROW LEVEL SECURITY; +ALTER TABLE bowgroup DISABLE ROW LEVEL SECURITY; +ALTER TABLE bookmark DISABLE ROW LEVEL SECURITY; +ALTER TABLE actionHistory DISABLE ROW LEVEL SECURITY; + +REVOKE INSERT ON bowUser FROM nobody; +REVOKE INSERT ON pageHistory FROM nobody; +REVOKE SELECT(uri, publicAlias) ON bookmark FROM nobody; + +REVOKE SELECT, DELETE, TRIGGER ON bowUser FROM person; +REVOKE UPDATE (updateDate, password, tokens, emails, unconfirmedEmails, authenticationInfo, autoScreenshot, autoFavicon, maxTagInCloud, maxResult, actions) ON bowUser FROM person; +REVOKE SELECT, INSERT, DELETE, TRIGGER ON bowgroup FROM person; +REVOKE UPDATE(updateDate, description, tokens, admin, writer, reader) ON bowgroup FROM person; +REVOKE SELECT, INSERT, DELETE, TRIGGER ON bookmark FROM person; +REVOKE UPDATE(uri, description, tags, updateDate, privateAlias, publicAlias, authenticationInfo, favicon, screenshot, visit, lang) ON bookmark FROM person; +REVOKE SELECT, INSERT, DELETE, TRIGGER ON actionHistory FROM person; +REVOKE SELECT ON pageHistory FROM person; + +DROP USER nobody; +DROP ROLE person; + DROP TABLE actionHistory; DROP TABLE pageHistory; DROP TABLE bookmark; diff --git a/pkg/http/opensearchResource.go b/pkg/http/opensearchResource.go index ddb1b7c..4d376cb 100644 --- a/pkg/http/opensearchResource.go +++ b/pkg/http/opensearchResource.go @@ -78,13 +78,16 @@ var actions = map[string]func(w http.ResponseWriter, r *http.Request, currentUse publicalias := getOrEmpty(args, 4) lang := getOrEmpty(args, 5) - // FIXME parametrer l'url url := fmt.Sprintf("http://localhost:8080/edit/new?uri=%s&description=%s&tags=%s&privatealias=%s&publicalias=%s&lang=%s", uri, description, tags, privatealias, publicalias, lang) http.Redirect(w, r, url, http.StatusFound) }, constant.RedirectAlias: func(w http.ResponseWriter, r *http.Request, currentUser model.BowUser, prefix string, ask string) { - // TODO recherche dans les alias prives - http.Redirect(w, r, "TODO", http.StatusFound) + uri, err := repository.URIFromAlias(currentUser, ask) + if err != nil { + utils.Throw(w, utils.NewHTTPError500(err, currentUser)) + return + } + http.Redirect(w, r, uri, http.StatusFound) }, constant.SuggestionAlias: func(w http.ResponseWriter, r *http.Request, currentUser model.BowUser, prefix string, ask string) { // renvoyer les couple alias/uri/description? pour l'affichage en suggest @@ -119,11 +122,10 @@ func getAction(currentUser model.BowUser, ask string) model.Action { var result model.Action for _, a := range currentUser.Actions { prefix := a.Prefix - if prefix == "" { - result = a - } else if strings.HasPrefix(ask, prefix) { + log.Printf("getAction %v == %v %v (%v && %v || %v) \n", ask, result, a, strings.HasPrefix(ask, prefix), result.Prefix == "", len(prefix) > len(result.Prefix)) + if strings.HasPrefix(ask, prefix) && (result.Prefix == "" || len(prefix) > len(result.Prefix)) { result = a - break + log.Printf("=====> %v", result) } } return result diff --git a/pkg/repository/bookmarkRepository.go b/pkg/repository/bookmarkRepository.go index 68987a3..b8d1767 100644 --- a/pkg/repository/bookmarkRepository.go +++ b/pkg/repository/bookmarkRepository.go @@ -78,6 +78,30 @@ func TagsJSON(currentUser model.BowUser, filter string, withCount bool) (string, return result, nil } +/* +URIFromAlias retourne l'uri associe a l'alias prive ou public +*/ +func URIFromAlias(currentUser model.BowUser, alias string) (string, error) { + arg := fmt.Sprintf(`{"%s"}`, alias) + // recherche dans les alias prive en 1er + q := &query{sql: `select uri from bookmark where privateAlias && $1::text[];`} + result, err := q.QueryString(currentUser, arg) + if err != nil { + return "", utils.NewHTTPError500(err, currentUser) + } + + if result == "" { + // s'il n'y a pas de resultat recherche dans les alias public + q = &query{asNobody: true, sql: `select uri from bookmark where publicAlias && $1::text[];`} + result, err = q.QueryString(currentUser, arg) + if err != nil { + return "", utils.NewHTTPError500(err, currentUser) + } + } + + return result, nil +} + func AddOneVisit(currentUser model.BowUser, id string) (string, error) { q := &query{sql: `update bookmark SET visit = visit + 1 where id=$1 returning uri;`} uri, err := q.QueryString(currentUser, id) diff --git a/pkg/repository/userRepository.go b/pkg/repository/userRepository.go index fb6a7ec..1283a4a 100644 --- a/pkg/repository/userRepository.go +++ b/pkg/repository/userRepository.go @@ -142,11 +142,6 @@ func CreateUser(login string, password string) (string, error) { log.Println("create user", string(userAsJSON)) q := &query{asNobody: true, sql: `INSERT INTO bowUser AS t SELECT * FROM json_populate_record(NULL::bowUser, $1::json);`} - q.setPostSQL(` - CREATE ROLE "%[1]s"; - GRANT "%[1]s" TO nobody; - `, currentUser.ID) - err = q.execOnOneRow(currentUser, userAsJSON) return currentUser.ID, err @@ -157,11 +152,6 @@ DeleteUser suppression d'un nouveau bookmark */ func DeleteUser(currentUser model.BowUser, id string) error { q := &query{sql: `DELETE FROM bowuser WHERE id=$1;`} - q.setPostSQL(` - RESET ROLE; - DROP ROLE IF EXISTS "%s"; - `, currentUser.ID) - err := q.execOnOneRow(currentUser, id) return err -- To stop receiving notification emails like this one, please contact chorem.org SCM administrator <admin+scm@chorem.org>.