diff --git a/Makefile b/Makefile index 504a8d6..a53a47d 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,17 @@ -include docker.mk +include test/test.mk PG_DUMP ?= pg_dump PSQL ?= psql +SCHEMA_FILES := \ + schema/sql/schema.sql \ + schema/sql/access.sql \ + schema/sql/api.sql \ + schema/sql/metrics.sql \ + schema/sql/nss.sql \ + schema/sql/reserved.sql \ + schema/sql/stats.sql \ + schema/ext/json-schema/postgres-json-schema--0.1.0.sql \ + out/json-schemas.sql .PHONY: help help: @@ -15,19 +25,9 @@ help: @echo "" @$(MAKE) -s docker-help -out/json-schemas.sql: schema/sql/json-schemas.sql - mkdir -p $(@D) - ./scripts/build schema < "$<" > "$@" - .PHONY: build build: out/json-schemas.sql -schema/ext/json-schema/%: - git submodule update --init --recursive $(@D) - -test/sql/plpgunit/%: - git submodule update --init --recursive $(@D) - .PHONY: fetch fetch: schema/ext/json-schema/ test/sql/plpgunit/ @@ -35,24 +35,10 @@ fetch: schema/ext/json-schema/ test/sql/plpgunit/ fetch-latest: git submodule foreach 'git checkout master && git pull' -SCHEMA_FILES := \ - schema/sql/schema.sql \ - schema/sql/access.sql \ - schema/sql/api.sql \ - schema/sql/metrics.sql \ - schema/sql/nss.sql \ - schema/sql/reserved.sql \ - schema/sql/stats.sql \ - schema/ext/json-schema/postgres-json-schema--0.1.0.sql \ - out/json-schemas.sql - .PHONY: install install: $(SCHEMA_FILES) $(PSQL) -v ON_ERROR_STOP=1 $(foreach file,$(SCHEMA_FILES),-f $(file)); -schema-dump.psql: - $(PG_DUMP) -s > $@ - .PHONY: test test: \ docker-test-build \ @@ -70,3 +56,16 @@ test-shell: \ .PHONY: clean clean: rm -rf out + +out/json-schemas.sql: schema/sql/json-schemas.sql + mkdir -p $(@D) + ./scripts/build schema < "$<" > "$@" + +out/schema-dump.psql: + $(PG_DUMP) -s > $@ + +schema/ext/json-schema/%: + git submodule update --init --recursive $(@D) + +test/sql/plpgunit/%: + git submodule update --init --recursive $(@D) diff --git a/schema/sql/api.sql b/schema/sql/api.sql index 63c4a76..879179c 100755 --- a/schema/sql/api.sql +++ b/schema/sql/api.sql @@ -31,9 +31,17 @@ grant usage on sequence "user_id" to "api-user-create"; grant "api-user-create" to "api"; grant "api-anon" to "api-user-create"; +create role "api-user-manage"; +comment on role "api-user-manage" is + $$Intended for use with user management systems$$; +grant usage on sequence "user_id" to "api-user-manage"; +grant "api-user-manage" to "api"; +grant "api-anon" to "api-user-manage"; + create schema v1; grant create,usage on schema v1 to api; grant usage on schema v1 to "api-anon"; +grant usage on schema v1 to "api-user-manage"; create view v1.hosts as select @@ -73,6 +81,8 @@ comment on column v1.passwd.data is alter view v1."passwd" owner to api; grant select on table v1."passwd" to "api-anon"; grant insert("name","host","data") on table v1."passwd" to "api-user-create"; +grant insert("name","host","data") on table v1."passwd" to "api-user-manage"; +grant update("host","data") on table v1."passwd" to "api-user-manage"; create view v1."group" as select @@ -127,6 +137,7 @@ comment on column v1.ssh_public_key.uid is $$User ID the key is currently linked to$$; alter view v1."ssh_public_key" owner to api; grant select on table v1."ssh_public_key" to "api-anon"; +grant update,delete,insert on table v1."ssh_public_key" to "api-user-manage"; -- PGP Key create view v1.openpgp_public_key as @@ -144,6 +155,7 @@ comment on column v1.openpgp_public_key.ascii_armoured_public_key is comment on column v1.openpgp_public_key.uid is $$User ID the key is currently linked to$$; grant insert("uid", "ascii_armoured_public_key") on table v1."openpgp_public_key" to "api-user-create"; +grant update("uid", "ascii_armoured_public_key") on table v1."openpgp_public_key" to "api-user-manage"; create function insert_pgp_key() returns trigger as $$ begin @@ -216,3 +228,4 @@ create trigger signup alter view v1."signup" owner to api; grant select on table v1."signup" to "api-anon"; grant insert("name", "host", "shell", "keys") on table v1."signup" to "api-user-create"; +grant insert("name", "host", "shell", "keys") on table v1."signup" to "api-user-manage"; diff --git a/test/bats/test.bats b/test/bats/test.bats index bfd28e3..22b32d1 100644 --- a/test/bats/test.bats +++ b/test/bats/test.bats @@ -3,7 +3,7 @@ load test_helper @test "Can connect to userdb PostgreSQL" { sleep 1 - run pg_isready -U postgres -h userdb; + run pg_isready -U postgres -h userdb-postgres; [ "$status" -eq 0 ] echo "$output" | grep "accepting connections" } @@ -74,7 +74,7 @@ load test_helper echo "$output" | grep "testuser42" } -@test "Can create user with a valid host and and SSH key via PostgREST" { +@test "Can create user with the api-user-create JWT token" { run curl http://userdb-postgrest:3000/signup \ -H "Content-Type: application/json" \ @@ -93,3 +93,125 @@ load test_helper run curl http://userdb-postgrest:3000/passwd?name=eq.testuser43 echo "$output" | grep "testuser43" } + +@test "Can create user with the api-user-manage JWT token" { + + run curl http://userdb-postgrest:3000/signup \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $(jwt_token 'api-user-manage')" \ + -X POST \ + --data-binary @- <<-EOF + { + "name": "testuser43", + "host": "test.hashbang.sh", + "shell": "/bin/zsh", + "keys": ["$(cat bats/keys/id_ed25519.pub)"] + } + EOF + [ "$status" -eq 0 ] + + run curl http://userdb-postgrest:3000/passwd?name=eq.testuser43 + echo "$output" | grep "testuser43" +} + +@test "Can update user with a valid update permissioned token" { + + run curl http://userdb-postgrest:3000/signup \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $(jwt_token 'api-user-create')" \ + -X POST \ + --data-binary @- <<-EOF + { + "name": "testuser43", + "host": "test.hashbang.sh", + "shell": "/bin/zsh", + "keys": ["$(cat bats/keys/id_ed25519.pub)"] + } + EOF + [ "$status" -eq 0 ] + + run curl http://userdb-postgrest:3000/passwd?name=eq.testuser43 + echo "$output" | grep "test.hashbang.sh" + + run curl http://userdb-postgrest:3000/passwd?name=eq.testuser43 \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $(jwt_token 'api-user-manage')" \ + -X PATCH \ + --data-binary @- <<-EOF + { + "host": "test2.hashbang.sh" + } + EOF + [ "$status" -eq 0 ] + + run curl http://userdb-postgrest:3000/passwd?name=eq.testuser43 + echo "$output" | grep "test2.hashbang.sh" +} + +@test "Can not update user with a JWT with an invalid role" { + + run curl http://userdb-postgrest:3000/signup \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $(jwt_token 'api-user-create')" \ + -X POST \ + --data-binary @- <<-EOF + { + "name": "testuser43", + "host": "test.hashbang.sh", + "shell": "/bin/zsh", + "keys": ["$(cat bats/keys/id_ed25519.pub)"] + } + EOF + [ "$status" -eq 0 ] + + run curl http://userdb-postgrest:3000/passwd?name=eq.testuser43 + echo "$output" | grep "test.hashbang.sh" + + run curl http://userdb-postgrest:3000/passwd?name=eq.testuser43 \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $(jwt_token 'api-derp')" \ + -X PATCH \ + --data-binary @- <<-EOF + { + "host": "test2.hashbang.sh" + } + EOF + echo "$output" | grep "does not exist" + + run curl http://userdb-postgrest:3000/passwd?name=eq.testuser43 + echo "$output" | grep "test.hashbang.sh" +} + +@test "Can not update user with a JWT with the wrong role" { + + run curl http://userdb-postgrest:3000/signup \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $(jwt_token 'api-user-create')" \ + -X POST \ + --data-binary @- <<-EOF + { + "name": "testuser43", + "host": "test.hashbang.sh", + "shell": "/bin/zsh", + "keys": ["$(cat bats/keys/id_ed25519.pub)"] + } + EOF + [ "$status" -eq 0 ] + + run curl http://userdb-postgrest:3000/passwd?name=eq.testuser43 + echo "$output" | grep "test.hashbang.sh" + + run curl http://userdb-postgrest:3000/passwd?name=eq.testuser43 \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer $(jwt_token 'api-anon')" \ + -X PATCH \ + --data-binary @- <<-EOF + { + "host": "test2.hashbang.sh" + } + EOF + echo "$output" | grep "permission denied" + + run curl http://userdb-postgrest:3000/passwd?name=eq.testuser43 + echo "$output" | grep "test.hashbang.sh" +} diff --git a/test/bats/test_helper.bash b/test/bats/test_helper.bash index 77efce7..b4be3a0 100644 --- a/test/bats/test_helper.bash +++ b/test/bats/test_helper.bash @@ -2,6 +2,7 @@ setup(){ psql -c "insert into hosts (name,maxusers) values ('test.hashbang.sh','500');"; + psql -c "insert into hosts (name,maxusers) values ('test2.hashbang.sh','500');"; } teardown(){ diff --git a/docker.mk b/test/test.mk similarity index 92% rename from docker.mk rename to test/test.mk index f87badb..3f5ec04 100644 --- a/docker.mk +++ b/test/test.mk @@ -1,7 +1,7 @@ NAMESPACE ?= userdb POSTGRES_USER ?= postgres POSTGRES_DB ?= postgres -IMAGE_POSTGRES ?= postgres:latest +IMAGE_POSTGRES ?= postgres@sha256:3657548977d593c9ab6d70d1ffc43ceb3b5164ae07ac0f542d2ea139664eb6b3 IMAGE_POSTGREST ?= postgrest/postgrest:v7.0.1@sha256:2a10713acc388f9a64320443e949eb87a0424ab280e68c4ed4a6d0653c001586 .PHONY: docker-help @@ -21,7 +21,8 @@ docker-start: docker network inspect $(NAMESPACE) \ || docker network create $(NAMESPACE) # Start database - docker run \ + docker inspect -f '{{.State.Running}}' $(NAMESPACE)-postgres 2>/dev/null \ + || docker run \ --detach=true \ --name=$(NAMESPACE)-postgres \ --network=$(NAMESPACE) \ @@ -53,7 +54,8 @@ docker-start: $(IMAGE_POSTGRES) psql" \ install # Start web API - docker run \ + docker inspect -f '{{.State.Running}}' $(NAMESPACE)-postgrest 2>/dev/null \ + || docker run \ --rm \ --detach=true \ --name $(NAMESPACE)-postgrest \