Setup authentication schema and user relation
User authentication is based on PostgREST’s[0]: There is a noninherit
role, authenticator, whose function is only to switch to a different
role according to the application’s session. Accordingly, this role has
no permission for anything.
The roles that this authentication can switch to are guest, invoicer, or
admin. Guest is for anonymous users, when they need to login or
register; invoicers are regular users; and admin are application’s
administrators, that can change other user’s status, when they have to
be removed or have they password changed, for example.
The user relation is actually inaccessible to all roles and can only be
used through a security definer function, login, so that passwords are
not accessible from the application.
I hesitated on what to use as the user’s primary key. The email seemed
a good candiate, because it will be used for login. But something rubs
me the wrong way.
It is not that they can change because, despite what people on the
Internet keeps parroting, they do not need to be “immutable”, PostgreSQL
can cascade updates to foreign keys, and people do **not** change email
addresses that ofter.
What i **do** know is that email addresses should be unique in order to
be used for login and password, hovewer i had to decide what “unique”
means here, because the domain part is case insensitive, but the local
part who knows? I made the arbitrary decision of assuming that the
whole address is case sensitive.
I have the feeling that this will bite me harder in the ass than using
it as the primary key.
[0]: https://postgrest.org/en/stable/auth.html
2023-01-13 00:43:20 +00:00
|
|
|
|
-- Test login
|
|
|
|
|
set client_min_messages to warning;
|
|
|
|
|
create extension if not exists pgtap;
|
|
|
|
|
reset client_min_messages;
|
|
|
|
|
|
|
|
|
|
begin;
|
|
|
|
|
|
Implement login cookie, its verification, and logout
At first i thought that i would need to implement sessions, the ones
that keep small files onto the disk, to know which user is talking to
the server, but then i realized that, for now at least, i only need a
very large number, plus the email address, to be used as a lookup, and
that can be stored in the user table, in a separate schema.
Had to change login to avoid raising exceptions when login failed
because i now keep a record of login attemps, and functions are always
run in a single transaction, thus the exception would prevent me to
insert into login_attempt. Even if i use a separate procedure, i could
not keep the records.
I did not want to add a parameter to the logout function because i was
afraid that it could be called from separate users. I do not know
whether it is possible with the current approach, since the settings
variable is also set by the same applications; time will tell.
2023-01-17 19:48:50 +00:00
|
|
|
|
select plan(20);
|
Setup authentication schema and user relation
User authentication is based on PostgREST’s[0]: There is a noninherit
role, authenticator, whose function is only to switch to a different
role according to the application’s session. Accordingly, this role has
no permission for anything.
The roles that this authentication can switch to are guest, invoicer, or
admin. Guest is for anonymous users, when they need to login or
register; invoicers are regular users; and admin are application’s
administrators, that can change other user’s status, when they have to
be removed or have they password changed, for example.
The user relation is actually inaccessible to all roles and can only be
used through a security definer function, login, so that passwords are
not accessible from the application.
I hesitated on what to use as the user’s primary key. The email seemed
a good candiate, because it will be used for login. But something rubs
me the wrong way.
It is not that they can change because, despite what people on the
Internet keeps parroting, they do not need to be “immutable”, PostgreSQL
can cascade updates to foreign keys, and people do **not** change email
addresses that ofter.
What i **do** know is that email addresses should be unique in order to
be used for login and password, hovewer i had to decide what “unique”
means here, because the domain part is case insensitive, but the local
part who knows? I made the arbitrary decision of assuming that the
whole address is case sensitive.
I have the feeling that this will bite me harder in the ass than using
it as the primary key.
[0]: https://postgrest.org/en/stable/auth.html
2023-01-13 00:43:20 +00:00
|
|
|
|
|
Implement login cookie, its verification, and logout
At first i thought that i would need to implement sessions, the ones
that keep small files onto the disk, to know which user is talking to
the server, but then i realized that, for now at least, i only need a
very large number, plus the email address, to be used as a lookup, and
that can be stored in the user table, in a separate schema.
Had to change login to avoid raising exceptions when login failed
because i now keep a record of login attemps, and functions are always
run in a single transaction, thus the exception would prevent me to
insert into login_attempt. Even if i use a separate procedure, i could
not keep the records.
I did not want to add a parameter to the logout function because i was
afraid that it could be called from separate users. I do not know
whether it is possible with the current approach, since the settings
variable is also set by the same applications; time will tell.
2023-01-17 19:48:50 +00:00
|
|
|
|
set search_path to auth, numerus, public;
|
Setup authentication schema and user relation
User authentication is based on PostgREST’s[0]: There is a noninherit
role, authenticator, whose function is only to switch to a different
role according to the application’s session. Accordingly, this role has
no permission for anything.
The roles that this authentication can switch to are guest, invoicer, or
admin. Guest is for anonymous users, when they need to login or
register; invoicers are regular users; and admin are application’s
administrators, that can change other user’s status, when they have to
be removed or have they password changed, for example.
The user relation is actually inaccessible to all roles and can only be
used through a security definer function, login, so that passwords are
not accessible from the application.
I hesitated on what to use as the user’s primary key. The email seemed
a good candiate, because it will be used for login. But something rubs
me the wrong way.
It is not that they can change because, despite what people on the
Internet keeps parroting, they do not need to be “immutable”, PostgreSQL
can cascade updates to foreign keys, and people do **not** change email
addresses that ofter.
What i **do** know is that email addresses should be unique in order to
be used for login and password, hovewer i had to decide what “unique”
means here, because the domain part is case insensitive, but the local
part who knows? I made the arbitrary decision of assuming that the
whole address is case sensitive.
I have the feeling that this will bite me harder in the ass than using
it as the primary key.
[0]: https://postgrest.org/en/stable/auth.html
2023-01-13 00:43:20 +00:00
|
|
|
|
|
2023-01-18 13:13:58 +00:00
|
|
|
|
select has_function('numerus', 'login', array ['email', 'text', 'inet']);
|
|
|
|
|
select function_lang_is('numerus', 'login', array ['email', 'text', 'inet'], 'plpgsql');
|
|
|
|
|
select function_returns('numerus', 'login', array ['email', 'text', 'inet'], 'text');
|
|
|
|
|
select is_definer('numerus', 'login', array ['email', 'text', 'inet']);
|
|
|
|
|
select volatility_is('numerus', 'login', array ['email', 'text', 'inet'], 'volatile');
|
|
|
|
|
select function_privs_are('numerus', 'login', array ['email', 'text', 'inet'], 'guest', array ['EXECUTE']);
|
|
|
|
|
select function_privs_are('numerus', 'login', array ['email', 'text', 'inet'], 'invoicer', array []::text[]);
|
|
|
|
|
select function_privs_are('numerus', 'login', array ['email', 'text', 'inet'], 'admin', array []::text[]);
|
|
|
|
|
select function_privs_are('numerus', 'login', array ['email', 'text', 'inet'], 'authenticator', array []::text[]);
|
Setup authentication schema and user relation
User authentication is based on PostgREST’s[0]: There is a noninherit
role, authenticator, whose function is only to switch to a different
role according to the application’s session. Accordingly, this role has
no permission for anything.
The roles that this authentication can switch to are guest, invoicer, or
admin. Guest is for anonymous users, when they need to login or
register; invoicers are regular users; and admin are application’s
administrators, that can change other user’s status, when they have to
be removed or have they password changed, for example.
The user relation is actually inaccessible to all roles and can only be
used through a security definer function, login, so that passwords are
not accessible from the application.
I hesitated on what to use as the user’s primary key. The email seemed
a good candiate, because it will be used for login. But something rubs
me the wrong way.
It is not that they can change because, despite what people on the
Internet keeps parroting, they do not need to be “immutable”, PostgreSQL
can cascade updates to foreign keys, and people do **not** change email
addresses that ofter.
What i **do** know is that email addresses should be unique in order to
be used for login and password, hovewer i had to decide what “unique”
means here, because the domain part is case insensitive, but the local
part who knows? I made the arbitrary decision of assuming that the
whole address is case sensitive.
I have the feeling that this will bite me harder in the ass than using
it as the primary key.
[0]: https://postgrest.org/en/stable/auth.html
2023-01-13 00:43:20 +00:00
|
|
|
|
|
|
|
|
|
set client_min_messages to warning;
|
|
|
|
|
truncate auth."user" cascade;
|
Implement login cookie, its verification, and logout
At first i thought that i would need to implement sessions, the ones
that keep small files onto the disk, to know which user is talking to
the server, but then i realized that, for now at least, i only need a
very large number, plus the email address, to be used as a lookup, and
that can be stored in the user table, in a separate schema.
Had to change login to avoid raising exceptions when login failed
because i now keep a record of login attemps, and functions are always
run in a single transaction, thus the exception would prevent me to
insert into login_attempt. Even if i use a separate procedure, i could
not keep the records.
I did not want to add a parameter to the logout function because i was
afraid that it could be called from separate users. I do not know
whether it is possible with the current approach, since the settings
variable is also set by the same applications; time will tell.
2023-01-17 19:48:50 +00:00
|
|
|
|
truncate auth.login_attempt cascade;
|
Setup authentication schema and user relation
User authentication is based on PostgREST’s[0]: There is a noninherit
role, authenticator, whose function is only to switch to a different
role according to the application’s session. Accordingly, this role has
no permission for anything.
The roles that this authentication can switch to are guest, invoicer, or
admin. Guest is for anonymous users, when they need to login or
register; invoicers are regular users; and admin are application’s
administrators, that can change other user’s status, when they have to
be removed or have they password changed, for example.
The user relation is actually inaccessible to all roles and can only be
used through a security definer function, login, so that passwords are
not accessible from the application.
I hesitated on what to use as the user’s primary key. The email seemed
a good candiate, because it will be used for login. But something rubs
me the wrong way.
It is not that they can change because, despite what people on the
Internet keeps parroting, they do not need to be “immutable”, PostgreSQL
can cascade updates to foreign keys, and people do **not** change email
addresses that ofter.
What i **do** know is that email addresses should be unique in order to
be used for login and password, hovewer i had to decide what “unique”
means here, because the domain part is case insensitive, but the local
part who knows? I made the arbitrary decision of assuming that the
whole address is case sensitive.
I have the feeling that this will bite me harder in the ass than using
it as the primary key.
[0]: https://postgrest.org/en/stable/auth.html
2023-01-13 00:43:20 +00:00
|
|
|
|
reset client_min_messages;
|
|
|
|
|
|
|
|
|
|
insert into auth."user" (email, name, password, role)
|
Implement login cookie, its verification, and logout
At first i thought that i would need to implement sessions, the ones
that keep small files onto the disk, to know which user is talking to
the server, but then i realized that, for now at least, i only need a
very large number, plus the email address, to be used as a lookup, and
that can be stored in the user table, in a separate schema.
Had to change login to avoid raising exceptions when login failed
because i now keep a record of login attemps, and functions are always
run in a single transaction, thus the exception would prevent me to
insert into login_attempt. Even if i use a separate procedure, i could
not keep the records.
I did not want to add a parameter to the logout function because i was
afraid that it could be called from separate users. I do not know
whether it is possible with the current approach, since the settings
variable is also set by the same applications; time will tell.
2023-01-17 19:48:50 +00:00
|
|
|
|
values ('info@tandem.blog', 'Tandem', 'test', 'invoicer');
|
Setup authentication schema and user relation
User authentication is based on PostgREST’s[0]: There is a noninherit
role, authenticator, whose function is only to switch to a different
role according to the application’s session. Accordingly, this role has
no permission for anything.
The roles that this authentication can switch to are guest, invoicer, or
admin. Guest is for anonymous users, when they need to login or
register; invoicers are regular users; and admin are application’s
administrators, that can change other user’s status, when they have to
be removed or have they password changed, for example.
The user relation is actually inaccessible to all roles and can only be
used through a security definer function, login, so that passwords are
not accessible from the application.
I hesitated on what to use as the user’s primary key. The email seemed
a good candiate, because it will be used for login. But something rubs
me the wrong way.
It is not that they can change because, despite what people on the
Internet keeps parroting, they do not need to be “immutable”, PostgreSQL
can cascade updates to foreign keys, and people do **not** change email
addresses that ofter.
What i **do** know is that email addresses should be unique in order to
be used for login and password, hovewer i had to decide what “unique”
means here, because the domain part is case insensitive, but the local
part who knows? I made the arbitrary decision of assuming that the
whole address is case sensitive.
I have the feeling that this will bite me harder in the ass than using
it as the primary key.
[0]: https://postgrest.org/en/stable/auth.html
2023-01-13 00:43:20 +00:00
|
|
|
|
|
Implement login cookie, its verification, and logout
At first i thought that i would need to implement sessions, the ones
that keep small files onto the disk, to know which user is talking to
the server, but then i realized that, for now at least, i only need a
very large number, plus the email address, to be used as a lookup, and
that can be stored in the user table, in a separate schema.
Had to change login to avoid raising exceptions when login failed
because i now keep a record of login attemps, and functions are always
run in a single transaction, thus the exception would prevent me to
insert into login_attempt. Even if i use a separate procedure, i could
not keep the records.
I did not want to add a parameter to the logout function because i was
afraid that it could be called from separate users. I do not know
whether it is possible with the current approach, since the settings
variable is also set by the same applications; time will tell.
2023-01-17 19:48:50 +00:00
|
|
|
|
create temp table _login_test (result_num integer, cookie text not null);
|
|
|
|
|
|
|
|
|
|
select lives_ok (
|
|
|
|
|
$$ insert into _login_test select 1, split_part(login('info@tandem.blog', 'test', '::1'::inet), '/', 1) $$,
|
|
|
|
|
'Should login with a correct user and password'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
select isnt_empty (
|
|
|
|
|
$$ select cookie from _login_test join "user" using (cookie) where email = 'info@tandem.blog' $$,
|
|
|
|
|
'Should have returned the cookie that wrote to the user relation.'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
select results_eq (
|
|
|
|
|
$$ select cookie_expires_at > current_timestamp from "user" where email = 'info@tandem.blog' $$,
|
|
|
|
|
$$ values (true) $$,
|
|
|
|
|
'Should have set an expiry date in the future.'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
select isnt_empty (
|
|
|
|
|
$$ select cookie from _login_test where cookie in (select split_part(login('info@tandem.blog', 'test', '192.168.0.1'::inet), '/', 1)) $$,
|
|
|
|
|
'Should return the same cookie if not expired yet.'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
update "user" set cookie_expires_at = current_timestamp - interval '1 hour' where email = 'info@tandem.blog';
|
|
|
|
|
|
|
|
|
|
select lives_ok (
|
|
|
|
|
$$ insert into _login_test select 2, split_part(login('info@tandem.blog', 'test', '::1'::inet), '/', 1) $$,
|
|
|
|
|
'Should login with a correct user and password even with an expired cookie'
|
Setup authentication schema and user relation
User authentication is based on PostgREST’s[0]: There is a noninherit
role, authenticator, whose function is only to switch to a different
role according to the application’s session. Accordingly, this role has
no permission for anything.
The roles that this authentication can switch to are guest, invoicer, or
admin. Guest is for anonymous users, when they need to login or
register; invoicers are regular users; and admin are application’s
administrators, that can change other user’s status, when they have to
be removed or have they password changed, for example.
The user relation is actually inaccessible to all roles and can only be
used through a security definer function, login, so that passwords are
not accessible from the application.
I hesitated on what to use as the user’s primary key. The email seemed
a good candiate, because it will be used for login. But something rubs
me the wrong way.
It is not that they can change because, despite what people on the
Internet keeps parroting, they do not need to be “immutable”, PostgreSQL
can cascade updates to foreign keys, and people do **not** change email
addresses that ofter.
What i **do** know is that email addresses should be unique in order to
be used for login and password, hovewer i had to decide what “unique”
means here, because the domain part is case insensitive, but the local
part who knows? I made the arbitrary decision of assuming that the
whole address is case sensitive.
I have the feeling that this will bite me harder in the ass than using
it as the primary key.
[0]: https://postgrest.org/en/stable/auth.html
2023-01-13 00:43:20 +00:00
|
|
|
|
);
|
|
|
|
|
|
Implement login cookie, its verification, and logout
At first i thought that i would need to implement sessions, the ones
that keep small files onto the disk, to know which user is talking to
the server, but then i realized that, for now at least, i only need a
very large number, plus the email address, to be used as a lookup, and
that can be stored in the user table, in a separate schema.
Had to change login to avoid raising exceptions when login failed
because i now keep a record of login attemps, and functions are always
run in a single transaction, thus the exception would prevent me to
insert into login_attempt. Even if i use a separate procedure, i could
not keep the records.
I did not want to add a parameter to the logout function because i was
afraid that it could be called from separate users. I do not know
whether it is possible with the current approach, since the settings
variable is also set by the same applications; time will tell.
2023-01-17 19:48:50 +00:00
|
|
|
|
|
|
|
|
|
select results_eq(
|
|
|
|
|
$$ select count(distinct cookie)::integer from _login_test $$,
|
|
|
|
|
$$ values (2) $$,
|
|
|
|
|
'Should have returned a new cookie'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
select isnt_empty (
|
|
|
|
|
$$ select cookie from _login_test join "user" using (cookie) where email = 'info@tandem.blog' and result_num = 2 $$,
|
|
|
|
|
'Should have updated the user’s cookie.'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
select results_eq(
|
|
|
|
|
$$ select cookie_expires_at > current_timestamp from "user" where email = 'info@tandem.blog' $$,
|
|
|
|
|
$$ values(true) $$,
|
|
|
|
|
'Should have set an expiry date in the future, again.'
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
select is(
|
|
|
|
|
login('info@tandem.blog'::email, 'mah password', '127.0.0.1'::inet),
|
|
|
|
|
''::text,
|
Setup authentication schema and user relation
User authentication is based on PostgREST’s[0]: There is a noninherit
role, authenticator, whose function is only to switch to a different
role according to the application’s session. Accordingly, this role has
no permission for anything.
The roles that this authentication can switch to are guest, invoicer, or
admin. Guest is for anonymous users, when they need to login or
register; invoicers are regular users; and admin are application’s
administrators, that can change other user’s status, when they have to
be removed or have they password changed, for example.
The user relation is actually inaccessible to all roles and can only be
used through a security definer function, login, so that passwords are
not accessible from the application.
I hesitated on what to use as the user’s primary key. The email seemed
a good candiate, because it will be used for login. But something rubs
me the wrong way.
It is not that they can change because, despite what people on the
Internet keeps parroting, they do not need to be “immutable”, PostgreSQL
can cascade updates to foreign keys, and people do **not** change email
addresses that ofter.
What i **do** know is that email addresses should be unique in order to
be used for login and password, hovewer i had to decide what “unique”
means here, because the domain part is case insensitive, but the local
part who knows? I made the arbitrary decision of assuming that the
whole address is case sensitive.
I have the feeling that this will bite me harder in the ass than using
it as the primary key.
[0]: https://postgrest.org/en/stable/auth.html
2023-01-13 00:43:20 +00:00
|
|
|
|
'Should not find any role with an invalid password'
|
|
|
|
|
);
|
|
|
|
|
|
Implement login cookie, its verification, and logout
At first i thought that i would need to implement sessions, the ones
that keep small files onto the disk, to know which user is talking to
the server, but then i realized that, for now at least, i only need a
very large number, plus the email address, to be used as a lookup, and
that can be stored in the user table, in a separate schema.
Had to change login to avoid raising exceptions when login failed
because i now keep a record of login attemps, and functions are always
run in a single transaction, thus the exception would prevent me to
insert into login_attempt. Even if i use a separate procedure, i could
not keep the records.
I did not want to add a parameter to the logout function because i was
afraid that it could be called from separate users. I do not know
whether it is possible with the current approach, since the settings
variable is also set by the same applications; time will tell.
2023-01-17 19:48:50 +00:00
|
|
|
|
select is(
|
|
|
|
|
login('nope@tandem.blog'::email, 'test'),
|
|
|
|
|
''::text,
|
Setup authentication schema and user relation
User authentication is based on PostgREST’s[0]: There is a noninherit
role, authenticator, whose function is only to switch to a different
role according to the application’s session. Accordingly, this role has
no permission for anything.
The roles that this authentication can switch to are guest, invoicer, or
admin. Guest is for anonymous users, when they need to login or
register; invoicers are regular users; and admin are application’s
administrators, that can change other user’s status, when they have to
be removed or have they password changed, for example.
The user relation is actually inaccessible to all roles and can only be
used through a security definer function, login, so that passwords are
not accessible from the application.
I hesitated on what to use as the user’s primary key. The email seemed
a good candiate, because it will be used for login. But something rubs
me the wrong way.
It is not that they can change because, despite what people on the
Internet keeps parroting, they do not need to be “immutable”, PostgreSQL
can cascade updates to foreign keys, and people do **not** change email
addresses that ofter.
What i **do** know is that email addresses should be unique in order to
be used for login and password, hovewer i had to decide what “unique”
means here, because the domain part is case insensitive, but the local
part who knows? I made the arbitrary decision of assuming that the
whole address is case sensitive.
I have the feeling that this will bite me harder in the ass than using
it as the primary key.
[0]: https://postgrest.org/en/stable/auth.html
2023-01-13 00:43:20 +00:00
|
|
|
|
'Should not find any role with an invalid email'
|
|
|
|
|
);
|
|
|
|
|
|
Implement login cookie, its verification, and logout
At first i thought that i would need to implement sessions, the ones
that keep small files onto the disk, to know which user is talking to
the server, but then i realized that, for now at least, i only need a
very large number, plus the email address, to be used as a lookup, and
that can be stored in the user table, in a separate schema.
Had to change login to avoid raising exceptions when login failed
because i now keep a record of login attemps, and functions are always
run in a single transaction, thus the exception would prevent me to
insert into login_attempt. Even if i use a separate procedure, i could
not keep the records.
I did not want to add a parameter to the logout function because i was
afraid that it could be called from separate users. I do not know
whether it is possible with the current approach, since the settings
variable is also set by the same applications; time will tell.
2023-01-17 19:48:50 +00:00
|
|
|
|
select results_eq(
|
|
|
|
|
'select user_name, ip_address, success, attempted_at from login_attempt order by attempt_id',
|
|
|
|
|
$$ values ('info@tandem.blog', '::1'::inet, true, current_timestamp)
|
|
|
|
|
, ('info@tandem.blog', '192.168.0.1'::inet, true, current_timestamp)
|
|
|
|
|
, ('info@tandem.blog', '::1'::inet, true, current_timestamp)
|
|
|
|
|
, ('info@tandem.blog', '127.0.0.1'::inet, false, current_timestamp)
|
|
|
|
|
, ('nope@tandem.blog', null, false, current_timestamp)
|
|
|
|
|
$$,
|
|
|
|
|
'Should have recorded all login attempts.'
|
|
|
|
|
);
|
|
|
|
|
|
Setup authentication schema and user relation
User authentication is based on PostgREST’s[0]: There is a noninherit
role, authenticator, whose function is only to switch to a different
role according to the application’s session. Accordingly, this role has
no permission for anything.
The roles that this authentication can switch to are guest, invoicer, or
admin. Guest is for anonymous users, when they need to login or
register; invoicers are regular users; and admin are application’s
administrators, that can change other user’s status, when they have to
be removed or have they password changed, for example.
The user relation is actually inaccessible to all roles and can only be
used through a security definer function, login, so that passwords are
not accessible from the application.
I hesitated on what to use as the user’s primary key. The email seemed
a good candiate, because it will be used for login. But something rubs
me the wrong way.
It is not that they can change because, despite what people on the
Internet keeps parroting, they do not need to be “immutable”, PostgreSQL
can cascade updates to foreign keys, and people do **not** change email
addresses that ofter.
What i **do** know is that email addresses should be unique in order to
be used for login and password, hovewer i had to decide what “unique”
means here, because the domain part is case insensitive, but the local
part who knows? I made the arbitrary decision of assuming that the
whole address is case sensitive.
I have the feeling that this will bite me harder in the ass than using
it as the primary key.
[0]: https://postgrest.org/en/stable/auth.html
2023-01-13 00:43:20 +00:00
|
|
|
|
|
|
|
|
|
select *
|
|
|
|
|
from finish();
|
|
|
|
|
|
|
|
|
|
rollback;
|