006
Combined tombstoning of uid and login
Lukas Juhrich, Jakob Müller
2023-01-15
Postulated
In the light of data economy, we should not store the login of a User –
which implicitly is a (partial) property of the UnixAccount –
more than necessary.
The only reason to keep the login is to avoid assigning the same mail address to multiple people across time; otherwise, mails might be send to the wrong addressee.
Thus it has been decided (external from the development team) to store the login in form of a hash whenever it stops being required for providing services to a user.
The implementation has to ensure
absence of the login whenever it is not needed (legal requirement)
that no login is doubly assigned (legal / business requirement)
Consequently, we need to track the login hash in some kind of “tombstone”,
such that
it is referenced by a User or a UnixAccount
it exists in all scenarios and is never deleted
Since the login and the uid have the same lifecycle, and both
require tombstoning –
albeit the uid needs to be kept only for technical reasons,
not for legal ones –
it makes sense to let such a tombstone maintain both pieces of data.
In the current model, the relevant entities are related as follows:
User: has a login (nullable) and a unix_account_id (nullable).
UnixAccount: Has the columns uid, gid, home, and login_shell,
but no login.
An ldap account (Derived entity):
If a User has a UnixAccount and the correct permissions,
this causes an LDAP account to be exported by the ldap syncer.
Since user.unix_account is a foreign key constraint,
we have the following possible states (U: User, UA: UnixAccount):
# |
∃U? |
∃U.login? |
∃U.unix_account_id? |
∃UA? |
|---|---|---|---|---|
1 |
✓ |
✗ |
✗ |
✗ |
2 |
✓ |
✗ |
✓ |
✓ |
3 |
✓ |
✓ |
✗ |
✗ |
4 |
✓ |
✓ |
✓ |
✓ |
5 |
✗ |
✗ |
✗ |
✓ |
6 |
✗ |
✗ |
✗ |
✗ |
With regards to tombstoning, the states imply the following requirements:
No requirements.
This is currently allowed, but issues a warning in the ldap syncer. Indeed, without the login the unix account cannot be exported. With tombstones however, we require
\((T_u)\) there shall exist a tombstone with the same uid as the account
\((T_l)\) there shall exist a tombstone with the implied login hash
\((T_u)\) there shall exist a tombstone with the same uid as the account
\((T_l)\) there shall exist a tombstone with the implied login hash
\((E_{ul})\) both tombstones in question should be equal
\((T_u)\) there shall exist a tombstone with the same uid as the account
Nothing exists
There shall be
A new entity unix_tombstone(uid int, login_hash text) satisfying
uid is unique
login_hash is unique
Either column may be null, but not both
uid and login_hash form the primary key
A generated column login_hash on the user relation
(see sqlalchemy.schema.Computed)
\((T_l)\): A foreign key constraint User.login_hash → UnixTombstone.login_hash
\((T_l)\): A foreign key constraint UnixAccount.uid → UnixTombstone.uid
\((E_{ul})\): A constraint checking consistency for users with login and unix account:
In this case, the tombstone induced by the account.uid should agree
with the tombstone induced by the user.login_hash
That the login_hash is optional allows for
unix_accounts which don’t have a unix_login associated to them
to have valid tombstones as well.
However, this implies that were one to couple these accounts to users again,
the tombstone has to be modified to reflect the user’s login (if it exists).
using a combined entity instead of an entity for the login and uid,
respectively, has the advantage that one can identify login tombstones
which never had a respective unix_account.
Database administrators can then decide on whether to keep these entries or not,
since technically these logins have not been used anywhere.
This might not serve any particular purpose but the
In the most frequent use case of creating a user with login and unix account, A tombstone has to be created as well. This is slightly more effort than the current implementation. To avoid this, triggers may be created that take care of this automatically.
Note
This ADR does not take a stance on whether or not to add triggers as it is mainly concerned with ensuring the critical legal and business requirements.
Tests have to be written to ensure that with any state change of the user
or unix_account relations,
the information contained in the tombstone tables is monotonous,
i.e that neither does a tombstone get deleted via a cascade
nor is a field set to null when it has been non-null before.