What is the best way to structure password storing tables in RDBMS? - rdbms

Name of an account and it's password are stored in different tables in order to improve security. Which table should contain a foreign key to another?
I can store passwords like this:
CREATE TABLE account
(
id INT
, name TEXT
)
;
CREATE TABLE password
(
account_id INT
, password_hash TEXT
, CONSTRAINT fk_password_account_id
FOREING KEY (account_id) REFERENCES account (id)
)
;
In that way hacker don't know user's password even if she/he knows account's name.
Another approach is:
CREATE TABLE account
(
id INT
, name TEXT
, password_id INT
, CONSTRAINT fk_account_password_id
FOREIGN KEY (password_id) REFERENCES password (id)
)
;
CREATE TABLE password
(
id INT
, password_hash TEXT
)
;
This way even if hacker knows a password, she/he doesn't know who is the owner.
So, which approach is better, assuming passwords are stored in different databases, or, at least, different schemas? And if passwords and account are stored in the same database?

Related

How do I define the main/primary record of a one-to-many relationship?

I'm making a service with an account table and a profile table. An account can own multiple profiles, but accounts always have a primary profile. This would initially be the first profile created alongside the account upon registration, but the user could add profiles and set one as the primary profile later.
I've tried the following setup:
create table account (
id uuid primary key,
email text unique,
phone text unique,
created_at timestamptz,
primary_profile_id uuid references profile on delete restrict,
);
create table profile (
id uuid primary key,
account_id uuid references account on delete cascade,
username text unique,
about text,
created_at timestamptz
);
This doesn't work because:
You can't even run that to create the tables since they both rely on the other existing beforehand. A workaround would be to create the account table without primary_profile_id and alter the table to add that column after the creation of the profile table, however...
Even if you can create the tables, you can't add records to them because you would need the other to exist first to reference it. It is technically possible if you leave primary_profile_id as NULL and change it after the profile has been created, but the columns aren't supposed to be nullable, so it's not really ideal.
Is there any good solution to this? I've also considered having a primary boolean on the profile table, but then there's nothing on the database side preventing that being true for multiple profiles under a single account.
Thanks for any help :)
Your idea of enforcing your requirement with a foreign key is good.
Creating the tables is no problem; you can simply run
create table account (
id uuid primary key,
email text unique,
phone text unique,
created_at timestamptz,
primary_profile_id uuid,
);
create table profile (
id uuid primary key,
account_id uuid references account on delete cascade,
username text unique,
about text,
created_at timestamptz
);
ALTER TABLE account
ADD FOREIGN KEY (primary_profile_id) REFERENCES profile
DEFERRABLE INITIALLY DEFERRED;
A deferred foreign key constraint like that is not checked right when a row is inserted, but at the end of the transaction. So you can add account first and then the matching profile, as long as you Insert both in the same transaction.
I recommend using NOT NULL in your column definitions wherever possible.

Not able to create a foreign key; Relation " " does not exist

I am trying to create a foreign key called 'user_id' for a 'transactions' table where the user_id references the 'user_accounts' table 'id' column. I keep getting an error when I execute the script that says:
SQL Error [42P01]: ERROR: relation "user_accounts" does not exist
The table clearly exists as I have been populating the user_accounts table with data that can be viewed in dbeaver. I am using Postgres and I am aware that quotes/capitalization can really make things difficult but I have executed my entire script without capitalizing or using quotes on any of the table or column names. Although, I did capitalize some of my column data types and I am wondering if that is the issue here? If so, what direction should I take to get my foreign key to work?
My script:
create table if not exists user_accounts (
id serial primary key,
first_name VARCHAR(30),
last_name VARCHAR(30),
username VARCHAR(20),
password VARCHAR(20),
deposit INT,
creditScore INT
)
create table if not exists transactions (
transaction_id serial primary key,
user_id INT references user_accounts(id) not null,
transaction_type VARCHAR(20),
amount INT
)

PostgreSQL audit table design with Multiple "User types"

I'm trying to implement an Audit table design in PostgreSQL, where I have different types of user id's that can be audited.
Let's say I have a table named admins (which belong to an organization), and table superadmins (which don't).
CREATE TABLE example.organizations (
id SERIAL UNIQUE,
company_name varchar(50) NOT NULL UNIQUE,
phone varchar(20) NOT NULL check (phone ~ '^[0-9]+$')
);
and an example of a potential admin design
CREATE TABLE example.admins (
id serial primary_key,
admin_type varchar not null,
#... shared data
check constraint admin_type in ("super_admins", "regular_admins")
);
CREATE TABLE example.regular_admins (
id integer primary key,
admin_type varchar not null default "regular_admins"
organization_id integer references example.organizations(id),
#... other regular admin fields
foreign key (id, admin_type) references example.admins (id, admin_type),
check constraint admin_type = "regular_admins"
);
CREATE TABLE example.super_admins (
id integer primary key,
admin_type varchar not null default "super_admins"
#... other super admin fields
foreign key (id, admin_type) references example.admins (id, admin_type),
check constraint admin_type = "super_admins"
);
Now an audit table
CREATE TABLE audit.organizations (
audit_timestamp timestamp not null default now(),
operation text,
admin_id integer primary key,
before jsonb,
after jsonb,
);
This calls for inheritance or polymorphism at some level, but I'm curious about how to design it. I've heard that using PostgreSQL's inheritance functionality is not always a great way to go, although I'm finding it to fit this use case.
I'll need to be able to reference a single admin id in the trigger that updates the audit table, and it would be nice to be able to get the admin information when selecting from the audit table without using multiple queries.
Would it be better to use PostgreSQL inheritance or are there other ideas I haven't considered?
I wouldn't say that it calls for inheritance or polymorphism. Admins and superadmins are both types of user, whose only difference is that the former belong to an organization. You can represent this with a single table and a nullable foreign key. No need to overcomplicate matters. Especially if you're using a serial as your primary key type: bad things happen if you confuse admin #2 for superadmin #2.

Best way to store company and employee data

I want to create an application where shop owner can register their shop and can store their customer details. My question is what will be the best way to store shop and their corresponding customer information.
I can create store and customer table and can have foreign key mapping. But is there any alternative and more secure way of doing this? Here security is primary concern. One shop owner should not be able to see other shop owner details.
You can create a third table with the name of shop_customers where you have both the ids of shop and customer as foreign key mapping.
Create table shops(
shop_id integer,
primary key (shop_id)
);
Create table customers(
customer_id integer,
primary key (customer_id)
);
CREATE TABLE shop_customers(
shop_id integer,
customer_id integer,
Primary Key (shop_id,customer_id),
Foreign Key (shop_id) REFERENCES shops(shop_id),
Foreign Key (customer_id) REFERENCES customers(customer_id)
);

Multiple ID's in a field. Postgresql

So, i'm currently working with a database system where a user can register, login and update his/her details whenever.
The database includes 5 roles:
1. Public
2. Member
3. Moderator
4. Coordinator
5. Admin
I want to be able to assign multiple roles to my users. For example, the Admin can also be a member. Therefore in the database it should show:
User_id | Role_ID
------------------------
user1 | 2, 5
^ is it possible to add multivalued id's in postgresql?
You can use filed of type array to store list of values.
However I think that there is much better way to organize what you want.
Make one table: role_names and another roles, like that:
CREATE TABLE role_names
(
id serial NOT NULL,
name text NOT NULL,
CONSTRAINT role_names_pkey PRIMARY KEY (id),
CONSTRAINT role_names_name_key UNIQUE (name)
);
CREATE TABLE roles
(
user_id bigint NOT NULL,
role_id bigint NOT NULL,
CONSTRAINT roles_pkey PRIMARY KEY (user_id, role_id),
CONSTRAINT roles_role_id_fkey FOREIGN KEY (role_id)
REFERENCES role_names (id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE RESTRICT
);
Now in the table role_names you put all the roles that you want to have.
In the table roles, you can assign or delete any number of roles to any user.
Also you can search in table roles for specific users or specific roles - much neat and faster than searching into arrays I think.
Feel free to add FK constraint for the user_id field too.
Yes, you can use int array to store list of roles.
Here's related question -Junction tables vs foreign key arrays?