reating a database schema means creating an interface for applications to use to manage their data. But how do you know how well that interface works until you’ve tried it?
Well, by trying it before you create it.
This talk introduces the concept of test-driven development to database administrators. We’ll use pgTAP to work through a real-world example creating a database design with an intuitive, useful interface for managing application data. Derive more intuitive table structures! Keep an eye to the beauty of your views! Let your procedures make your application more productive! Feel younger and more clever, all through the power of TDDD!
4. David E. Wheeler
OSCON 2010
Portland OR USA
License: Attribution-Noncommercial-Share Alike 3.0 United
States: http://creativecommons.org/licenses/by-nc-sa/3.0/us/
5. Build My VC-Funded App
✔
for Me for Free
David E. Wheeler
CEO, Data Manager
FASN Enterprises, Inc.
OSCON 2010
Portland OR USA
License: Attribution-Noncommercial-Share Alike 3.0 United
States: http://creativecommons.org/licenses/by-nc-sa/3.0/us/
16. How it Works
Microblogging platform
antisocial network
17. How it Works
Microblogging platform
Everyone follows you
antisocial network
18. How it Works
Microblogging platform
Everyone follows you
New users follow everyone
antisocial network
19. How it Works
Microblogging platform
Everyone follows you
New users follow everyone
Goal: Alienate your followers
antisocial network
20. How it Works
Microblogging platform
Everyone follows you
New users follow everyone
Goal: Alienate your followers
Get them to unfollow you
antisocial network
21. How it Works
Microblogging platform
Everyone follows you
New users follow everyone
Goal: Alienate your followers
Get them to unfollow you
Leaderboard: Those with fewest followers
antisocial network
46. Install PostgreSQL
http:/
/www.postgresql.org/download/
Distribution package
Mac/BSD Ports http://roadie.show.local/oscon/
Need postgresql-dev too!
http:/ 10.16.2/oscon/
/10.
antisocial network
47. Install PostgreSQL
http:/
/www.postgresql.org/download/
Distribution package
Mac/BSD Ports http://roadie.show.local/oscon/
Need postgresql-dev too!
Source: http:/ 10.16.2/oscon/
/10.
antisocial network
48. Install PostgreSQL
http:/
/www.postgresql.org/download/
Distribution package
Mac/BSD Ports http://roadie.show.local/oscon/
Need postgresql-dev too!
Source: http:/ 10.16.2/oscon/
/10.
./configure && make && make install
antisocial network
49. Install PostgreSQL
http:/
/www.postgresql.org/download/
Distribution package
Mac/BSD Ports http://roadie.show.local/oscon/
Need postgresql-dev too!
Source: http:/ 10.16.2/oscon/
/10.
./configure && make && make install
cd contrib && make && make install
antisocial network
50. Install PostgreSQL
http:/
/www.postgresql.org/download/
Distribution package
Mac/BSD Ports http://roadie.show.local/oscon/
Need postgresql-dev too!
Source: http:/ 10.16.2/oscon/
/10.
./configure && make && make install
cd contrib && make && make install
initdb -D /usr/local/pgsql/data
antisocial network
56. Install Test::Harness
% cpan Test::Harness
Or…
% wget http://bit.ly/test-harness-321
% tar zxf Test-Harness-3.21.tar.gz
% cd Test-Harness-3.21
57. Install Test::Harness
% cpan Test::Harness
Or…
% wget http://bit.ly/test-harness-321
% tar zxf Test-Harness-3.21.tar.gz
% cd Test-Harness-3.21
% perl Makefile.PL
58. Install Test::Harness
% cpan Test::Harness
Or…
% wget http://bit.ly/test-harness-321
% tar zxf Test-Harness-3.21.tar.gz
% cd Test-Harness-3.21
% perl Makefile.PL
% make
59. Install Test::Harness
% cpan Test::Harness
Or…
% wget http://bit.ly/test-harness-321
% tar zxf Test-Harness-3.21.tar.gz
% cd Test-Harness-3.21
% perl Makefile.PL
% make
% make test
60. Install Test::Harness
% cpan Test::Harness
Or…
% wget http://bit.ly/test-harness-321
% tar zxf Test-Harness-3.21.tar.gz
% cd Test-Harness-3.21
% perl Makefile.PL
% make
% make test
% sudo make install
64. Install pgTAP
% tar jxf pgtap-0.24.tar.bz2
% cd pgtap-0.24
% make TAPSCHEMA=tap Separate
schema
65. Install pgTAP
% tar jxf pgtap-0.24.tar.bz2
% cd pgtap-0.24
% make TAPSCHEMA=tap
% sudo make install
66. Install pgTAP
% tar jxf pgtap-0.24.tar.bz2
% cd pgtap-0.24
% make TAPSCHEMA=tap
% sudo make install
% make installcheck
67. Install pgTAP
% tar jxf pgtap-0.24.tar.bz2
% cd pgtap-0.24
% make TAPSCHEMA=tap
% sudo make install
% make installcheck
% createdb -U postgres flipr
68. Install pgTAP
% tar jxf pgtap-0.24.tar.bz2
% cd pgtap-0.24
% make TAPSCHEMA=tap
% sudo make install
% make installcheck
% createdb -U postgres flipr
% createlang -U postgres -d flipr plpgsql
69. Install pgTAP
% tar jxf pgtap-0.24.tar.bz2
% cd pgtap-0.24
% make TAPSCHEMA=tap
% sudo make install
% make installcheck
% createdb -U postgres flipr
% createlang -U postgres -d flipr plpgsql
% psql -U postgres -d flipr -f pgtap.sql
81. Run the Test
% pg_prove -vd flipr tests/001-schema.pg
tests/001-schema.pg .. 1/1
not ok 1 - Table users should exist
# Failed test 1: "Table users should exist"
# Looks like you failed 1 test of 1
tests/001-schema.pg .. Failed 1/1 subtests
Test Summary Report
-------------------
tests/001-schema.pg (Tests: 1 Failed: 1)
Failed test: 1
Files=1, Tests=1, 0 wallclock secs
Result: FAIL
82. Run the Test
% pg_prove -vd flipr tests/001-schema.pg
tests/001-schema.pg .. 1/1
not ok 1 - Table users should exist
# Failed test 1: "Table users should exist"
# Looks like you failed 1 test of 1
tests/001-schema.pg .. Failed 1/1 subtests
Test Summary Report
-------------------
tests/001-schema.pg (Tests: 1 Failed: 1)
Failed test: 1
Files=1, Tests=1, 0 wallclock secs
Result: FAIL
83. Run the Test
% pg_prove -vd flipr tests/001-schema.pg
tests/001-schema.pg .. 1/1
not ok 1 - Table users should exist
# Failed test 1: "Table users should exist"
# Looks like you failed 1 test of 1
tests/001-schema.pg .. Failed 1/1 subtests
Test Summary Report
-------------------
tests/001-schema.pg (Tests: 1 Failed: 1)
Failed test: 1
Files=1, Tests=1, 0 wallclock secs
Result: FAIL
84. Run the Test
% pg_prove -vd flipr tests/001-schema.pg
tests/001-schema.pg .. 1/1
not ok 1 - Table users should exist
# Failed test 1: "Table users should exist"
# Looks like you failed 1 test of 1
tests/001-schema.pg .. Failed 1/1 subtests
Test Summary Report
-------------------
tests/001-schema.pg (Tests: 1 Failed: 1)
Failed test: 1
Files=1, Tests=1, 0 wallclock secs
Result: FAIL
106. Run ’Em
% pg_prove -vd flipr tests/002-schema.pg
tests/002-schema.pg ..
1..5
ok 1 - Schema public should have the correct tables
ok 2 - Table users should exist
not ok 3 - Column users.nickname should exist
# Failed test 3: "Column users.nickname should exist"
not ok 4 - Column users.password should exist
# Failed test 4: "Column users.password should exist"
not ok 5 - Column users."timestamp" should exist
# Failed test 5: "Column users."timestamp" should exist"
# Looks like you failed 3 tests of 5
tests/002-schema.pg .. Failed 3/5 subtests
Test Summary Report
-------------------
tests/002-schema.pg (Tests: 5 Failed: 2)
Failed tests: 3-5
Files=1, Tests=5, 0 wallclock secs
Result: FAIL
107. Run ’Em
% pg_prove -vd flipr tests/002-schema.pg
tests/002-schema.pg ..
1..5
ok 1 - Schema public should have the correct tables
ok 2 - Table users should exist
not ok 3 - Column users.nickname should exist
# Failed test 3: "Column users.nickname should exist"
not ok 4 - Column users.password should exist
# Failed test 4: "Column users.password should exist"
not ok 5 - Column users."timestamp" should exist
# Failed test 5: "Column users."timestamp" should exist"
# Looks like you failed 3 tests of 5
As
tests/002-schema.pg .. Failed 3/5 subtests
Test Summary Report
-------------------
tests/002-schema.pg (Tests: 5 Failed: 2)
Expected
Failed tests: 3-5
Files=1, Tests=5, 0 wallclock secs
Result: FAIL
109. Add the Columns
DROP TABLE IF EXISTS users;
CREATE TABLE users (
nickname TEXT PRIMARY KEY,
password TEXT NOT NULL,
timestamp TIMESTAMPTZ NOT NULL DEFAULT
NOW()
);
002-users.sql
110. Add the Columns
DROP TABLE IF EXISTS users;
CREATE TABLE users (
nickname TEXT PRIMARY KEY,
password TEXT NOT NULL,
timestamp TIMESTAMPTZ NOT NULL DEFAULT
NOW()
);
002-users.sql
Simple.
112. Run Again
% psql -d flipr -f sql/002-users.sql
% pg_prove -vd flipr tests/002-schema.pg
tests/002-schema.pg ..
1..5
ok 1 - Schema public should have the correct tables
ok 2 - Table users should exist
ok 3 - Column users.nickname should exist
ok 4 - Column users.password should exist
ok 5 - Column users."timestamp" should exist
ok
All tests successful.
Files=1, Tests=5, 0 wallclock secs
Result: PASS
113. Run Again
% psql -d flipr -f sql/002-users.sql
% pg_prove -vd flipr tests/002-schema.pg
tests/002-schema.pg ..
1..5
ok 1 - Schema public should have the correct tables
ok 2 - Table users should exist
ok 3 - Column users.nickname should exist
ok 4 - Column users.password should exist
ok 5 - Column users."timestamp" should exist
ok
All tests successful.
Files=1, Tests=5, 0 wallclock secs
Result: PASS
Rockin.
145. Data Inconsistencies
flipr=# select nickname, password from users;
nickname | password
-----------
+----------------------------------
agliodbs | 72b302bf297a228a75730123efef7c41
anna | May 13, 2005
strongrrl | 008c5926ca861023c1d2a36653fd88e2
theory | 008c5926ca861023c1d2a36653fd88e2
(4 rows)
146. Data Inconsistencies
flipr=# select nickname, password from users;
nickname | password
-----------
+----------------------------------
agliodbs | 72b302bf297a228a75730123efef7c41
anna | May 13, 2005
strongrrl | 008c5926ca861023c1d2a36653fd88e2
theory | 008c5926ca861023c1d2a36653fd88e2
(4 rows)
147. Data Inconsistencies
flipr=# select nickname, password from users;
nickname | password
-----------
+----------------------------------
agliodbs | 72b302bf297a228a75730123efef7c41
✔
anna | May 13, 2005
strongrrl | 008c5926ca861023c1d2a36653fd88e2
theory | 008c5926ca861023c1d2a36653fd88e2
(4 rows)
148. Data Inconsistencies
flipr=# select nickname, password from users;
nickname | password
-----------
+----------------------------------
agliodbs | 72b302bf297a228a75730123efef7c41
✔
anna | May 13, 2005
strongrrl | 008c5926ca861023c1d2a36653fd88e2
theory | 008c5926ca861023c1d2a36653fd88e2
(4 rows)
149. Data Inconsistencies
flipr=# select nickname, password from users;
nickname | password
-----------
+----------------------------------
✘✘✘✘✘✘✘✘ Bad!
agliodbs | 72b302bf297a228a75730123efef7c41
✔
anna | May 13, 2005
strongrrl | 008c5926ca861023c1d2a36653fd88e2
theory | 008c5926ca861023c1d2a36653fd88e2
(4 rows)
150. Data Inconsistencies
flipr=# select nickname, password from users;
nickname | password
-----------
+----------------------------------
✘✘✘✘✘✘✘✘ Bad!
agliodbs | 72b302bf297a228a75730123efef7c41
✔
anna | May 13, 2005
strongrrl | 008c5926ca861023c1d2a36653fd88e2
theory | 008c5926ca861023c1d2a36653fd88e2
(4 rows)
151. Data Inconsistencies
flipr=# select nickname, password from users;
nickname | password
-----------
+----------------------------------
✘✘✘✘✘✘✘✘ Bad!
agliodbs | 72b302bf297a228a75730123efef7c41
✔
anna
〷〷〷〷〷〷〷〷〷
| May 13, 2005
strongrrl | 008c5926ca861023c1d2a36653fd88e2
theory | 008c5926ca861023c1d2a36653fd88e2
We can do better!
(4 rows)
154. What Encryption?
Multiple interfaces
Data must be consistent
antisocial network
155. What Encryption?
Multiple interfaces
Data must be consistent
Encrypt passwords
antisocial network
156. What Encryption?
Multiple interfaces
Data must be consistent
Encrypt passwords
Obscure password duplication
antisocial network
157. What Encryption?
Multiple interfaces
Data must be consistent
Encrypt passwords
Obscure password duplication
Solution: Database functions
antisocial network
164. Run ’Em
% pg_prove -d flipr tests/004-userfunc.pg
tests/004-userfunc.pg .. 1/?
not ok 1 - Function ins_user() should exist
# Failed test 1: "Function ins_user() should exist"
not ok 2 - Function ins_user(text, text) should exist
# Failed test 2: "Function ins_user(text, text) should exist"
not ok 3 - Function ins_user() should return void
# Failed test 3: "Function ins_user() should return void"
# Function ins_user() does not exist
# Looks like you failed 3 tests of 3
tests/004-userfunc.pg .. Failed 3/3 subtests
Test Summary Report
-------------------
tests/004-userfunc.pg (Wstat: 0 Tests: 3 Failed: 3)
Failed tests: 1-3
Files=1, Tests=3, 0 wallclock secs
Result: FAIL
165. Run ’Em
% pg_prove -d flipr tests/004-userfunc.pg
tests/004-userfunc.pg .. 1/?
not ok 1 - Function ins_user() should exist
# Failed test 1: "Function ins_user() should exist"
not ok 2 - Function ins_user(text, text) should exist
# Failed test 2: "Function ins_user(text, text) should exist"
not ok 3 - Function ins_user() should return void
# Failed test 3: "Function ins_user() should return void"
# Function ins_user() does not exist
# Looks like you failed 3 tests of 3
tests/004-userfunc.pg .. Failed 3/3 subtests
Test Summary Report
-------------------
tests/004-userfunc.pg (Wstat: 0 Tests: 3 Failed: 3)
Failed tests: 1-3
Files=1, Tests=3, 0 wallclock secs
Result: FAIL
170. …To make ’em pass
% psql -d flipr -f sql/004-userfunc.sql
CREATE FUNCTION
%
171. …To make ’em pass
% psql -d flipr -f sql/004-userfunc.sql
CREATE FUNCTION
% pg_prove -d flipr tests/004-userfunc.pg
tests/004-userfunc.pg .. ok
All tests successful.
Files=1, Tests=3, 0 wallclock secs
Result: PASS
172. …To make ’em pass
% psql -d flipr -f sql/004-userfunc.sql
CREATE FUNCTION
% pg_prove -d flipr tests/004-userfunc.pg
tests/004-userfunc.pg .. ok
All tests successful.
Files=1, Tests=3, 0 wallclock secs
Result: PASS
Yay!
173. Make sure it does
something.
SELECT has_function('ins_user');
SELECT has_function('ins_user', ARRAY['text', 'text']);
SELECT function_returns('ins_user', 'void');
005-userfunc.pg
174. Make sure it does
something.
SELECT has_function('ins_user');
SELECT has_function('ins_user', ARRAY['text', 'text']);
SELECT function_returns('ins_user', 'void');
SELECT is(COUNT(*)::int, 0, 'Should have no users')
FROM users;
SELECT lives_ok(
$$ SELECT ins_user('theory', 'wet blanket') $$,
'Execution of ins_user() should not die'
);
SELECT is(COUNT(*)::int, 1, 'Should now have one user')
FROM users;
005-userfunc.pg
175. Make sure it does
something.
SELECT has_function('ins_user');
SELECT has_function('ins_user', ARRAY['text', 'text']);
SELECT function_returns('ins_user', 'void');
SELECT is(COUNT(*)::int, 0, 'Should have no users')
FROM users;
SELECT lives_ok(
$$ SELECT ins_user('theory', 'wet blanket') $$,
'Execution of ins_user() should not die'
);
SELECT is(COUNT(*)::int, 1, 'Should now have one user')
FROM users;
005-userfunc.pg
176. Make sure it does
something.
SELECT has_function('ins_user');
SELECT has_function('ins_user', ARRAY['text', 'text']);
SELECT function_returns('ins_user', 'void');
SELECT is(COUNT(*)::int, 0, 'Should have no users')
FROM users;
SELECT lives_ok(
$$ SELECT ins_user('theory', 'wet blanket') $$,
'Execution of ins_user() should not die'
);
SELECT is(COUNT(*)::int, 1, 'Should now have one user')
FROM users;
005-userfunc.pg
177. Make sure it does
something.
SELECT has_function('ins_user');
SELECT has_function('ins_user', ARRAY['text', 'text']);
SELECT function_returns('ins_user', 'void');
SELECT is(COUNT(*)::int, 0, 'Should have no users')
FROM users;
SELECT lives_ok(
$$ SELECT ins_user('theory', 'wet blanket') $$,
'Execution of ins_user() should not die'
);
SELECT is(COUNT(*)::int, 1, 'Should now have one user')
FROM users;
005-userfunc.pg
178. Make sure it does
something.
SELECT has_function('ins_user');
SELECT has_function('ins_user', ARRAY['text', 'text']);
SELECT function_returns('ins_user', 'void');
SELECT is(COUNT(*)::int, 0, 'Should have no users')
FROM users;
SELECT lives_ok(
$$ SELECT ins_user('theory', 'wet blanket') $$,
'Execution of ins_user() should not die'
);
SELECT is(COUNT(*)::int, 1, 'Should now have one user')
FROM users;
005-userfunc.pg
180. What does that get us?
% pg_prove -d flipr tests/005-userfunc.pg
tests/005-userfunc.pg .. 1/?
not ok 6 - Should now have one user
# Failed test 6: "Should now have one user"
# have: 0
# want: 1
# Looks like you failed 1 test of 6
tests/005-userfunc.pg .. Failed 1/6 subtests
Test Summary Report
-------------------
tests/005-userfunc.pg (Wstat: 0 Tests: 6 Failed: 1)
Failed test: 6
Files=1, Tests=6, 1 wallclock secs
Result: FAIL
181. What does that get us?
% pg_prove -d flipr tests/005-userfunc.pg
tests/005-userfunc.pg .. 1/?
not ok 6 - Should now have one user
# Failed test 6: "Should now have one user"
# have: 0
# want: 1
# Looks like you failed 1 test of 6
tests/005-userfunc.pg .. Failed 1/6 subtests
Test Summary Report
-------------------
tests/005-userfunc.pg (Wstat: 0 Tests: 6 Failed: 1)
Failed test: 6
Files=1, Tests=6, 1 wallclock secs
Result: FAIL
182. Modify for the Test
CREATE OR REPLACE FUNCTION ins_user(
nickname TEXT,
password TEXT
) RETURNS VOID LANGUAGE SQL AS'';
005-userfunc.sql
183. Modify for the Test
CREATE OR REPLACE FUNCTION ins_user(
nickname TEXT,
password TEXT
$$
) RETURNS VOID LANGUAGE SQL AS
INSERT INTO users values($1, $2);
$$;
005-userfunc.sql
184. Modify for the Test
CREATE OR REPLACE FUNCTION ins_user(
nickname TEXT,
password TEXT
$$
) RETURNS VOID LANGUAGE SQL AS
INSERT INTO users values($1, $2);
$$;
Bare minimum
005-userfunc.sql
186. …To make ’em pass
% psql -d flipr -f sql/005-userfunc.sql
CREATE FUNCTION
%
187. …To make ’em pass
% psql -d flipr -f sql/005-userfunc.sql
CREATE FUNCTION
% pg_prove -d flipr tests/005-userfunc.pg
tests/005-userfunc.pg .. ok
All tests successful.
Files=1, Tests=6, 0 wallclock secs
Result: PASS
188. …To make ’em pass
% psql -d flipr -f sql/005-userfunc.sql
CREATE FUNCTION
% pg_prove -d flipr tests/005-userfunc.pg
tests/005-userfunc.pg .. ok
All tests successful.
Files=1, Tests=6, 0 wallclock secs
Result: PASS
Great!
189. Add More Assertions
SELECT lives_ok(
$$ SELECT ins_user('theory', 'wet blanket') $$,
'Execution of ins_user() should not die'
);
SELECT is(COUNT(*)::int, 1, 'Should now have one user')
FROM users;
006-userfunc.pg
190. Add More Assertions
SELECT lives_ok(
$$ SELECT ins_user('theory', 'wet blanket') $$,
'Execution of ins_user() should not die'
);
SELECT is(COUNT(*)::int, 1, 'Should now have one user')
FROM users;
SELECT isnt(
password, 'wet blanket',
'Password should not be clear text'
) FROM users WHERE nickname = 'theory';
006-userfunc.pg
191. Add More Assertions
SELECT lives_ok(
$$ SELECT ins_user('theory', 'wet blanket') $$,
'Execution of ins_user() should not die'
);
SELECT is(COUNT(*)::int, 1, 'Should now have one user')
FROM users;
SELECT isnt(
password, 'wet blanket',
'Password should not be clear text'
) FROM users WHERE nickname = 'theory';
006-userfunc.pg
192. Add More Assertions
SELECT lives_ok(
$$ SELECT ins_user('theory', 'wet blanket') $$,
'Execution of ins_user() should not die'
);
SELECT is(COUNT(*)::int, 1, 'Should now have one user')
FROM users;
SELECT isnt(
password, 'wet blanket',
'Password should not be clear text'
) FROM users WHERE nickname = 'theory';
006-userfunc.pg
194. Run ’Em
% pg_prove -d flipr tests/006-userfunc.pg
tests/006-userfunc.pg .. 1/?
not ok 7 - Password should not be clear text
# Failed test 7: "Password should not be clear text"
# have: wet blanket
# want: anything else
# Looks like you failed 1 test of 7
tests/006-userfunc.pg .. Failed 1/7 subtests
Test Summary Report
-------------------
tests/006-userfunc.pg (Wstat: 0 Tests: 7 Failed: 1)
Failed test: 7
Files=1, Tests=7, 0 wallclock secs
Result: FAIL
195. Run ’Em
% pg_prove -d flipr tests/006-userfunc.pg
tests/006-userfunc.pg .. 1/?
not ok 7 - Password should not be clear text
# Failed test 7: "Password should not be clear text"
# have: wet blanket
# want: anything else
# Looks like you failed 1 test of 7
tests/006-userfunc.pg .. Failed 1/7 subtests
Test Summary Report
-------------------
tests/006-userfunc.pg (Wstat: 0 Tests: 7 Failed: 1)
Failed test: 7
Files=1, Tests=7, 0 wallclock secs
Result: FAIL
196. Modify for the Test
CREATE OR REPLACE FUNCTION ins_user(
nickname TEXT,
password TEXT
) RETURNS VOID LANGUAGE SQL AS $$
INSERT INTO users values($1, $ ); 2
$$;
006-userfunc.sql
197. Modify for the Test
CREATE OR REPLACE FUNCTION ins_user(
nickname TEXT,
password TEXT
) RETURNS VOID LANGUAGE SQL AS $$
INSERT INTO users values($1, $ ); 1
$$;
006-userfunc.sql
198. Modify for the Test
CREATE OR REPLACE FUNCTION ins_user(
nickname TEXT,
password TEXT
) RETURNS VOID LANGUAGE SQL AS $$
INSERT INTO users values($1, $ ); 1
$$;
I’m not kidding
006-userfunc.sql
200. …To make ’em pass
% psql -d flipr -f sql/006-userfunc.sql
CREATE FUNCTION
% pg_prove -d flipr tests/006-userfunc.pg
tests/006-userfunc.pg .. ok
All tests successful.
Files=1, Tests=7, 1 wallclock secs
Result: PASS
201. …To make ’em pass
% psql -d flipr -f sql/006-userfunc.sql
CREATE FUNCTION
% pg_prove -d flipr tests/006-userfunc.pg
tests/006-userfunc.pg .. ok
All tests successful.
Files=1, Tests=7, 1 wallclock secs
Result: PASS
So what?
202. Sanity Check
SELECT isnt(
password, 'wet blanket',
'Password should not be clear text'
) FROM users WHERE nickname = 'theory';
007-userfunc.pg
203. Sanity Check
SELECT isnt(
password, 'wet blanket',
'Password should not be clear text'
) FROM users WHERE nickname = 'theory';
SELECT isnt(
password, 'theory',
'Password should not be nickname'
) FROM users WHERE nickname = 'theory';
007-userfunc.pg
204. Sanity Check
SELECT isnt(
password, 'wet blanket',
'Password should not be clear text'
) FROM users WHERE nickname = 'theory';
SELECT isnt(
password, 'theory',
'Password should not be nickname'
) FROM users WHERE nickname = 'theory';
007-userfunc.pg
205. Sanity Check
SELECT isnt(
password, 'wet blanket',
'Password should not be clear text'
) FROM users WHERE nickname = 'theory';
SELECT isnt(
password, 'theory',
'Password should not be nickname'
) FROM users WHERE nickname = 'theory';
007-userfunc.pg
207. Are We Insane?
pg_prove -d flipr tests/007-userfunc.pg
tests/007-userfunc.pg .. 1/?
not ok 8 - Password should not be nickname
# Failed test 8: "Password should not be nickname"
# have: theory
# want: anything else
# Looks like you failed 1 test of 8
tests/007-userfunc.pg .. Failed 1/8 subtests
Test Summary Report
-------------------
tests/007-userfunc.pg (Wstat: 0 Tests: 8 Failed: 1)
Failed test: 8
Files=1, Tests=8, 0 wallclock secs
Result: FAIL
208. Are We Insane?
pg_prove -d flipr tests/007-userfunc.pg
tests/007-userfunc.pg .. 1/?
not ok 8 - Password should not be nickname
# Failed test 8: "Password should not be nickname"
# have: theory
# want: anything else
# Looks like you failed 1 test of 8
tests/007-userfunc.pg .. Failed 1/8 subtests
Test Summary Report
-------------------
tests/007-userfunc.pg (Wstat: 0 Tests: 8 Failed: 1)
Failed test: 8
Files=1, Tests=8, 0 wallclock secs
Result: FAIL
209. Change for the Test
CREATE OR REPLACE FUNCTION ins_user(
nickname TEXT,
password TEXT
) RETURNS VOID LANGUAGE SQL AS $$
INSERT INTO users values($1, $1);
$$;
007-userfunc.sql
210. Change for the Test
CREATE OR REPLACE FUNCTION ins_user(
nickname TEXT,
password TEXT
) RETURNS VOID LANGUAGE SQL AS $$
INSERT INTO users values($1, 'whatever');
$$;
007-userfunc.sql
211. Change for the Test
CREATE OR REPLACE FUNCTION ins_user(
nickname TEXT,
password TEXT
) RETURNS VOID LANGUAGE SQL AS $$
INSERT INTO users values($1, 'whatever');
$$;
That’ll do it.
007-userfunc.sql
213. See ’em Pass
% psql -d flipr -f sql/007-userfunc.sql
CREATE FUNCTION
% pg_prove -d flipr tests/007-userfunc.pg
tests/007-userfunc.pg .. ok
All tests successful.
Files=1, Tests=8, 0 wallclock secs
Result: PASS
214. See ’em Pass
% psql -d flipr -f sql/007-userfunc.sql
CREATE FUNCTION
% pg_prove -d flipr tests/007-userfunc.pg
tests/007-userfunc.pg .. ok
All tests successful.
Files=1, Tests=8, 0 wallclock secs
Result: PASS
Exciting, no?
215. Add Another User…
SELECT isnt(
password, 'theory',
'Password should not be nickname'
) FROM users WHERE nickname = 'theory';
008-userfunc.pg
216. Add Another User…
SELECT isnt(
password, 'theory',
'Password should not be nickname'
) FROM users WHERE nickname = 'theory';
SELECT lives_ok(
$$ SELECT ins_user('strongrrl', 'wet blanket') $$,
'Insert user "strongrrl"'
);
SELECT is(COUNT(*)::int, 2, 'Should now have two users')
FROM users;
SELECT isnt(
(SELECT password FROM users WHERE nickname = 'strongrrl'),
(SELECT password FROM users WHERE nickname = 'theory'),
'Same password should not match'
);
008-userfunc.pg
217. Add Another User…
SELECT isnt(
password, 'theory',
'Password should not be nickname'
) FROM users WHERE nickname = 'theory';
SELECT lives_ok(
$$ SELECT ins_user('strongrrl', 'wet blanket') $$,
'Insert user "strongrrl"'
);
SELECT is(COUNT(*)::int, 2, 'Should now have two users')
FROM users;
SELECT isnt(
(SELECT password FROM users WHERE nickname = 'strongrrl'),
(SELECT password FROM users WHERE nickname = 'theory'),
'Same password should not match'
);
008-userfunc.pg
218. Add Another User…
SELECT isnt(
password, 'theory',
'Password should not be nickname'
) FROM users WHERE nickname = 'theory';
SELECT lives_ok(
$$ SELECT ins_user('strongrrl', 'wet blanket') $$,
'Insert user "strongrrl"'
);
SELECT is(COUNT(*)::int, 2, 'Should now have two users')
FROM users;
SELECT isnt(
(SELECT password FROM users WHERE nickname = 'strongrrl'),
(SELECT password FROM users WHERE nickname = 'theory'),
'Same password should not match'
);
008-userfunc.pg
219. Add Another User…
SELECT isnt(
password, 'theory',
'Password should not be nickname'
) FROM users WHERE nickname = 'theory';
SELECT lives_ok(
$$ SELECT ins_user('strongrrl', 'wet blanket') $$,
'Insert user "strongrrl"'
);
SELECT is(COUNT(*)::int, 2, 'Should now have two users')
FROM users;
SELECT isnt(
(SELECT password FROM users WHERE nickname = 'strongrrl'),
(SELECT password FROM users WHERE nickname = 'theory'),
'Same password should not match'
);
008-userfunc.pg
221. Let Us Be Inconsistent
pg_prove -d flipr tests/008-userfunc.pg
tests/008-userfunc.pg .. 1/?
not ok 11 - Same password should not match
# Failed test 11: "Same password should not match"
# have: whatever
# want: anything else
# Looks like you failed 1 test of 11
tests/008-userfunc.pg .. Failed 1/11 subtests
Test Summary Report
-------------------
tests/008-userfunc.pg (Wstat: 0 Tests: 11 Failed: 1)
Failed test: 11
Files=1, Tests=11, 0 wallclock secs
Result: FAIL
222. Let Us Be Inconsistent
pg_prove -d flipr tests/008-userfunc.pg
tests/008-userfunc.pg .. 1/?
not ok 11 - Same password should not match
# Failed test 11: "Same password should not match"
# have: whatever
# want: anything else
# Looks like you failed 1 test of 11
tests/008-userfunc.pg .. Failed 1/11 subtests
Test Summary Report
-------------------
tests/008-userfunc.pg (Wstat: 0 Tests: 11 Failed: 1)
Failed test: 11
Files=1, Tests=11, 0 wallclock secs
Result: FAIL
223. Cheat Death
CREATE OR REPLACE FUNCTION ins_user(
nickname TEXT,
password TEXT
) RETURNS VOID LANGUAGE SQL AS $$
INSERT INTO users values($1, 'whatever');
$$;
008-userfunc.sql
224. Cheat Death
CREATE OR REPLACE FUNCTION ins_user(
nickname TEXT,
password TEXT
) RETURNS VOID LANGUAGE SQL AS $$
INSERT INTO users values($1, $1 || $2);
$$;
008-userfunc.sql
225. Cheat Death
CREATE OR REPLACE FUNCTION ins_user(
nickname TEXT,
password TEXT
) RETURNS VOID LANGUAGE SQL AS $$
INSERT INTO users values($1, $1 || $2);
$$;
No, seriously.
008-userfunc.sql
227. Take a Pass
% psql -d flipr -f sql/008-userfunc.sql
CREATE FUNCTION
% pg_prove -d flipr tests/008-userfunc.pg
tests/008-userfunc.pg .. ok
All tests successful.
Files=1, Tests=11, 0 wallclock secs
Result: PASS
228. Take a Pass
% psql -d flipr -f sql/008-userfunc.sql
CREATE FUNCTION
% pg_prove -d flipr tests/008-userfunc.pg
tests/008-userfunc.pg .. ok
All tests successful.
Files=1, Tests=11, 0 wallclock secs
Result: PASS
Not unexpected.
229. Let’s Get Serious
SELECT isnt(
(SELECT password FROM users WHERE nickname = 'strongrrl'),
(SELECT password FROM users WHERE nickname = 'theory'),
'Same password should not match'
);
009-userfunc.pg
230. Let’s Get Serious
SELECT isnt(
(SELECT password FROM users WHERE nickname = 'strongrrl'),
(SELECT password FROM users WHERE nickname = 'theory'),
'Same password should not match'
);
SELECT unalike(
password,
'%' || nickname || '%',
'Password should not contain nickname'
) FROM users;
SELECT unalike(
password,
'%wet blanket%',
'Password should not contain clear text'
) FROM users;
009-userfunc.pg
231. Let’s Get Serious
SELECT isnt(
(SELECT password FROM users WHERE nickname = 'strongrrl'),
(SELECT password FROM users WHERE nickname = 'theory'),
'Same password should not match'
);
SELECT unalike(
password,
'%' || nickname || '%',
'Password should not contain nickname'
) FROM users;
SELECT unalike(
password,
'%wet blanket%',
'Password should not contain clear text'
) FROM users;
009-userfunc.pg
232. Let’s Get Serious
SELECT isnt(
(SELECT password FROM users WHERE nickname = 'strongrrl'),
(SELECT password FROM users WHERE nickname = 'theory'),
'Same password should not match'
);
SELECT unalike(
password,
'%' || nickname || '%',
'Password should not contain nickname'
) FROM users;
SELECT unalike(
password,
'%wet blanket%',
'Password should not contain clear text'
) FROM users;
009-userfunc.pg
233. Let’s Get Serious
SELECT isnt(
(SELECT password FROM users WHERE nickname = 'strongrrl'),
(SELECT password FROM users WHERE nickname = 'theory'),
'Same password should not match'
);
SELECT unalike(
password,
'%' || nickname || '%',
'Password should not contain nickname'
) FROM users;
SELECT unalike(
password,
'%wet blanket%',
'Password should not contain clear text'
) FROM users;
009-userfunc.pg
234. Let’s Get Serious
SELECT isnt(
(SELECT password FROM users WHERE nickname = 'strongrrl'),
(SELECT password FROM users WHERE nickname = 'theory'),
'Same password should not match'
);
SELECT unalike(
password,
'%' || nickname || '%',
'Password should not contain nickname'
) FROM users;
SELECT unalike(
password,
'%wet blanket%',
'Password should not contain clear text'
) FROM users;
009-userfunc.pg
235.
236. % pg_prove -d flipr tests/009-userfunc.pg
tests/009-userfunc.pg .. 1/?
not ok 12 - Password should not contain nickname
# Failed test 12: "Password should not contain nickname"
# 'theorywet blanket'
# matches: '%theory%'
not ok 13 - Password should not contain nickname
# Failed test 13: "Password should not contain nickname"
# 'strongrrlwet blanket'
# matches: '%strongrrl%'
not ok 14 - Password should not contain clear text
# Failed test 14: "Password should not contain clear text"
# 'theorywet blanket'
# matches: '%wet blanket%'
not ok 15 - Password should not contain clear text
# Failed test 15: "Password should not contain clear text"
# 'strongrrlwet blanket'
# matches: '%wet blanket%'
# Looks like you failed 4 tests of 15
tests/009-userfunc.pg .. Failed 4/15 subtests
Test Summary Report
-------------------
tests/009-userfunc.pg (Wstat: 0 Tests: 15 Failed: 4)
Failed tests: 12-15
Files=1, Tests=15, 0 wallclock secs
Result: FAIL
237. % pg_prove -d flipr tests/009-userfunc.pg
tests/009-userfunc.pg .. 1/?
not ok 12 - Password should not contain nickname
# Failed test 12: "Password should not contain nickname"
# 'theorywet blanket'
# matches: '%theory%'
not ok 13 - Password should not contain nickname
# Failed test 13: "Password should not contain nickname"
# 'strongrrlwet blanket'
# matches: '%strongrrl%'
not ok 14 - Password should not contain clear text
# Failed test 14: "Password should not contain clear text"
# 'theorywet blanket'
# matches: '%wet blanket%'
not ok 15 - Password should not contain clear text
# Failed test 15: "Password should not contain clear text"
# 'strongrrlwet blanket'
# matches: '%wet blanket%'
# Looks like you failed 4 tests of 15
tests/009-userfunc.pg .. Failed 4/15 subtests
Test Summary Report
-------------------
tests/009-userfunc.pg (Wstat: 0 Tests: 15 Failed: 4)
Failed tests: 12-15
Files=1, Tests=15, 0 wallclock secs
Result: FAIL
238. % pg_prove -d flipr tests/009-userfunc.pg
tests/009-userfunc.pg .. 1/?
not ok 12 - Password should not contain nickname
# Failed test 12: "Password should not contain nickname"
# 'theorywet blanket'
# matches: '%theory%'
not ok 13 - Password should not contain nickname
# Failed test 13: "Password should not contain nickname"
# 'strongrrlwet blanket'
# matches: '%strongrrl%'
not ok 14 - Password should not contain clear text
# Failed test 14: "Password should not contain clear text"
# 'theorywet blanket'
# matches: '%wet blanket%'
not ok 15 - Password should not contain clear text
# Failed test 15: "Password should not contain clear text"
# 'strongrrlwet blanket'
# matches: '%wet blanket%'
# Looks like you failed 4 tests of 15
tests/009-userfunc.pg .. Failed 4/15 subtests
Test Summary Report
-------------------
tests/009-userfunc.pg (Wstat: 0 Tests: 15 Failed: 4)
Failed tests: 12-15
Files=1, Tests=15, 0 wallclock secs
Result: FAIL
239. Try MD5
CREATE OR REPLACE FUNCTION ins_user(
nickname TEXT,
password TEXT
) RETURNS VOID LANGUAGE SQL AS $$
INSERT INTO users values($1, $1 || $2);
$$;
009-userfunc.sql
240. Try MD5
CREATE OR REPLACE FUNCTION ins_user(
nickname TEXT,
password TEXT
) RETURNS VOID LANGUAGE SQL AS $$
INSERT INTO users values($1, md5($2));
$$;
009-userfunc.sql
241. Try MD5
CREATE OR REPLACE FUNCTION ins_user(
nickname TEXT,
password TEXT
) RETURNS VOID LANGUAGE SQL AS $$
INSERT INTO users values($1, md5($2));
$$;
It’s hashish.
009-userfunc.sql
243. Here We Go!
% psql -d flipr sql/009-userfunc.sql
% pg_prove -d flipr tests/009-userfunc.pg
tests/009-userfunc.pg .. 1/?
not ok 11 - Same password should not match
# Failed test 11: "Same password should not match"
# have: 3c908e08d874ad9ec39bffc93b5fb983
# want: anything else
# Looks like you failed 1 test of 15
tests/009-userfunc.pg .. Failed 1/15 subtests
Test Summary Report
-------------------
tests/009-userfunc.pg (Wstat: 0 Tests: 15 Failed: 1)
Failed test: 11
Files=1, Tests=15, 0 wallclock secs
Result: FAIL
244. Here We Go!
% psql -d flipr sql/009-userfunc.sql
% pg_prove -d flipr tests/009-userfunc.pg
tests/009-userfunc.pg .. 1/?
not ok 11 - Same password should not match
# Failed test 11: "Same password should not match"
# have: 3c908e08d874ad9ec39bffc93b5fb983
# want: anything else
# Looks like you failed 1 test of 15
tests/009-userfunc.pg .. Failed 1/15 subtests
Test Summary Report
------------------- Wait, what?
tests/009-userfunc.pg (Wstat: 0 Tests: 15 Failed: 1)
Failed test: 11
Files=1, Tests=15, 0 wallclock secs
Result: FAIL
245. Here We Go!
% psql -d flipr sql/009-userfunc.sql
% pg_prove -d flipr tests/009-userfunc.pg
tests/009-userfunc.pg .. 1/?
not ok 11 - Same password should not match
# Failed test 11: "Same password should not match"
# have: 3c908e08d874ad9ec39bffc93b5fb983
# want: anything else
# Looks like you failed 1 test of 15
tests/009-userfunc.pg .. Failed 1/15 subtests
Test Summary Report
------------------- Wait, what?
tests/009-userfunc.pg (Wstat: 0 Tests: 15 Failed: 1)
Failed test: 11
Files=1, Tests=15, 0 wallclock secs
Result: FAIL
246. Whaaaaa?
SELECT isnt(
(SELECT password FROM users WHERE nickname = 'strongrrl'),
(SELECT password FROM users WHERE nickname = 'theory'),
'Same password should not match'
);
SELECT unalike(
password,
'%' || nickname || '%',
'Password should not contain nickname'
) FROM users;
SELECT unalike(
password,
'%wet blanket%',
'Password should not contain clear text'
) FROM users;
009-userfunc.pg
247. Whaaaaa?
SELECT isnt(
(SELECT password FROM users WHERE nickname = 'strongrrl'),
(SELECT password FROM users WHERE nickname = 'theory'),
'Same password should not match'
);
SELECT unalike(
password,
'%' || nickname || '%',
'Password should not contain nickname'
) FROM users;
SELECT unalike(
password,
'%wet blanket%',
'Password should not contain clear text'
) FROM users;
009-userfunc.pg
248. Whaaaaa?
SELECT isnt(
(SELECT password FROM users WHERE nickname = 'strongrrl'),
(SELECT password FROM users WHERE nickname = 'theory'),
'Same password should not match'
);
SELECT unalike(
password,
'%' || nickname || '%',
'Password should not contain nickname'
Regression!
) FROM users;
SELECT unalike(
password,
'%wet blanket%',
'Password should not contain clear text'
) FROM users;
009-userfunc.pg
249. Whaaaaa?
SELECT isnt(
(SELECT password FROM users WHERE nickname = 'strongrrl'),
(SELECT password FROM users WHERE nickname = 'theory'),
'Same password should not match'
); Must
SELECT unalike(
password,
obscure
'%' || nickname || '%',
'Password should not contain nickname'
dupes.
Regression!
) FROM users;
SELECT unalike(
password,
'%wet blanket%',
'Password should not contain clear text'
) FROM users;
009-userfunc.pg
251. Where Are We?
Function adds user
antisocial network
252. Where Are We?
Function adds user
Nickname not in password
antisocial network
253. Where Are We?
Function adds user
Nickname not in password
No clear text password
antisocial network
254. Where Are We?
Function adds user
Nickname not in password
No clear text password
Must obscure duplicates
antisocial network
255. Where Are We?
Function adds user
Nickname not in password
No clear text password
Must obscure duplicates
How?
antisocial network
256. Where Are We?
Function adds user
Nickname not in password
No clear text password
Must obscure duplicates
How?
Solution: pg_crypto
antisocial network
257. Test for pg_crypto
SELECT col_has_default( 'users', 'timestamp' );
SELECT col_default_is( 'users', 'timestamp', 'now()' );
010-schema.pg
258. Test for pg_crypto
SELECT col_has_default( 'users', 'timestamp' );
SELECT col_default_is( 'users', 'timestamp', 'now()' );
SELECT has_function('crypt');
SELECT has_function('gen_salt');
010-schema.pg
260. See Test Fail
% pg_prove -d flipr tests/010-schema.pg
tests/010-schema.pg .. 1/?
not ok 17 - Function crypt() should exist
# Failed test 17: "Function crypt() should exist"
not ok 18 - Function gen_salt() should exist
# Failed test 18: "Function gen_salt() should exist"
# Looks like you failed 2 tests of 18
tests/010-schema.pg .. Failed 2/18 subtests
Test Summary Report
-------------------
tests/010-schema.pg (Wstat: 0 Tests: 18 Failed: 2)
Failed tests: 17-18
Files=1, Tests=18, 0 wallclock secs
Result: FAIL
266. Use pg_crypt
CREATE OR REPLACE FUNCTION ins_user(
nickname TEXT,
password TEXT
) RETURNS VOID LANGUAGE SQL AS $$
INSERT INTO users values($1, md5($2));
$$;
010-userfunc.sql
267. Use pg_crypt
CREATE OR REPLACE FUNCTION ins_user(
nickname TEXT,
password TEXT
) RETURNS VOID LANGUAGE SQL AS $$
INSERT INTO users values($1, crypt($1, gen_salt('md5')));
$$;
010-userfunc.sql
268. Use pg_crypt
CREATE OR REPLACE FUNCTION ins_user(
nickname TEXT,
password TEXT
) RETURNS VOID LANGUAGE SQL AS $$
INSERT INTO users values($1, crypt($1, gen_salt('md5')));
$$;
Cryptonite!
010-userfunc.sql
277. Are We Sane?
% pg_prove -d flipr tests/011-userfunc.pg
tests/011-userfunc.pg .. 1/?
not ok 16 - Password should match crypted password
# Failed test 16: "Password should match crypted password"
# have: $1$PmBl0CzG$sUwGMzxCKqovvMKaBhyXK.
# want: $1$PmBl0CzG$E/uNgzObrQHl3Wp.C6/TX0
not ok 17 - Password should match crypted password
# Failed test 17: "Password should match crypted password"
# have: $1$KCxoeJAK$APSOlalADk1akGrItOASx.
# want: $1$KCxoeJAK$DrhZ5wT4aUzJE.RydnJLy0
# Looks like you failed 2 tests of 17
tests/011-userfunc.pg .. Failed 2/17 subtests
Test Summary Report
-------------------
tests/011-userfunc.pg (Wstat: 0 Tests: 17 Failed: 2)
Failed tests: 16-17
Files=1, Tests=17, 0 wallclock secs
Result: FAIL
278. Are We Sane?
% pg_prove -d flipr tests/011-userfunc.pg
tests/011-userfunc.pg .. 1/?
not ok 16 - Password should match crypted password
# Failed test 16: "Password should match crypted password"
# have: $1$PmBl0CzG$sUwGMzxCKqovvMKaBhyXK.
# want: $1$PmBl0CzG$E/uNgzObrQHl3Wp.C6/TX0
not ok 17 - Password should match crypted password
# Failed test 17: "Password should match crypted password"
# have: $1$KCxoeJAK$APSOlalADk1akGrItOASx.
# want: $1$KCxoeJAK$DrhZ5wT4aUzJE.RydnJLy0
# Looks like you failed 2 tests of 17
tests/011-userfunc.pg .. Failed 2/17 subtests
Test Summary Report
------------------- Say what?
tests/011-userfunc.pg (Wstat: 0 Tests: 17 Failed: 2)
Failed tests: 16-17
Files=1, Tests=17, 0 wallclock secs
Result: FAIL
279. Are We Sane?
% pg_prove -d flipr tests/011-userfunc.pg
tests/011-userfunc.pg .. 1/?
not ok 16 - Password should match crypted password
# Failed test 16: "Password should match crypted password"
# have: $1$PmBl0CzG$sUwGMzxCKqovvMKaBhyXK.
# want: $1$PmBl0CzG$E/uNgzObrQHl3Wp.C6/TX0
not ok 17 - Password should match crypted password
# Failed test 17: "Password should match crypted password"
# have: $1$KCxoeJAK$APSOlalADk1akGrItOASx.
# want: $1$KCxoeJAK$DrhZ5wT4aUzJE.RydnJLy0
# Looks like you failed 2 tests of 17
tests/011-userfunc.pg .. Failed 2/17 subtests
Test Summary Report
------------------- Say what?
tests/011-userfunc.pg (Wstat: 0 Tests: 17 Failed: 2)
Failed tests: 16-17
Files=1, Tests=17, 0 wallclock secs
Result: FAIL
280. What’d We Do Wrong?
CREATE OR REPLACE FUNCTION ins_user(
nickname TEXT,
password TEXT
) RETURNS VOID LANGUAGE SQL AS $$
1
INSERT INTO users values($1, crypt($ , gen_salt('md5')));
$$;
011-userfunc.sql
281. What’d We Do Wrong?
CREATE OR REPLACE FUNCTION ins_user(
nickname TEXT,
password TEXT
) RETURNS VOID LANGUAGE SQL AS $$
2
INSERT INTO users values($1, crypt($ , gen_salt('md5')));
$$;
011-userfunc.sql
282. What’d We Do Wrong?
CREATE OR REPLACE FUNCTION ins_user(
nickname TEXT,
password TEXT
) RETURNS VOID LANGUAGE SQL AS $$
2
INSERT INTO users values($1, crypt($ , gen_salt('md5')));
$$;
Cryptonite!
011-userfunc.sql
288. Next: upd_pass()
Need password updating
Things to consider:
antisocial network
289. Next: upd_pass()
Need password updating
Things to consider:
Update nonexistent user?
antisocial network
290. Next: upd_pass()
Need password updating
Things to consider:
Update nonexistent user?
Update with invalid password?
antisocial network
291. Next: upd_pass()
Need password updating
Things to consider:
Update nonexistent user?
Update with invalid password?
Was password updated?
antisocial network
307. How’d We Do?
SELECT ok(
upd_pass('theory', 'wet blanket', 'pgtap rulez'),
'upd_pass() should return true for proper args'
);
SELECT is(
password, crypt('pgtap rulez', password),
'Password should now be changed'
) FROM users WHERE nickname = 'theory';
012-userfunc.sql
308. How’d We Do?
SELECT ok(
upd_pass('theory', 'wet blanket', 'pgtap rulez'),
'upd_pass() should return true for proper args'
);
SELECT is(
password, crypt('pgtap rulez', password),
'Password should now be changed'
) FROM users WHERE nickname = 'theory';
012-userfunc.sql
309. How’d We Do?
SELECT ok(
upd_pass('theory', 'wet blanket', 'pgtap rulez'),
'upd_pass() should return true for proper args'
);
SELECT is(
password, crypt('pgtap rulez', password),
'Password should now be changed'
) FROM users WHERE nickname = 'theory';
012-userfunc.sql
311. What Does it Look Like?
CREATE OR REPLACE FUNCTION upd_pass(
nick TEXT,
oldpass TEXT,
newpass TEXT
) RETURNS BOOLEAN LANGUAGE plpgsql AS $$
BEGIN
UPDATE users
SET password = crypt($3, gen_salt('md5'))
WHERE nickname = $1
AND password = crypt($2, password);
RETURN FOUND;
END;
$$;
013-privs.sql
312. What Does it Look Like?
CREATE OR REPLACE FUNCTION upd_pass(
nick TEXT,
oldpass TEXT,
newpass TEXT
) RETURNS BOOLEAN LANGUAGE plpgsql AS $$
BEGIN
UPDATE users
SET password = crypt($3, gen_salt('md5'))
WHERE nickname = $1
AND password = crypt($2, password);
RETURN FOUND;
END;
$$;
013-privs.sql
Good, eh?
316. What About Privileges?
Got solid functions
Apps still using tables
How to prevent that?
antisocial network
317. What About Privileges?
Got solid functions
Apps still using tables
How to prevent that?
Privileges!
antisocial network
318. What About Privileges?
Got solid functions
Apps still using tables
How to prevent that?
Privileges!
Deny access to table
antisocial network
319. What About Privileges?
Got solid functions
Apps still using tables
How to prevent that?
Privileges!
Deny access to table
Allow access to functions
antisocial network
325. Check Privileges
% pg_prove -d flipr tests/013-privs.pg
tests/013-privs.pg .. 1/?
not ok 1 - Role fliprapp should exist
# Failed test 1: "Role fliprapp should exist"
not ok 2 - User fliprapp should not be a super user
# Failed test 2: "User fliprapp should not be a super user"
# User fliprapp does not exist
# Looks like you failed 2 tests of 2
tests/013-privs.pg .. Failed 2/2 subtests
Test Summary Report
-------------------
tests/013-privs.pg (Wstat: 0 Tests: 2 Failed: 2)
Failed tests: 1-2
Files=1, Tests=2, 0 wallclock secs
Result: FAIL
326. Check Privileges
% pg_prove -d flipr tests/013-privs.pg
tests/013-privs.pg .. 1/?
not ok 1 - Role fliprapp should exist
# Failed test 1: "Role fliprapp should exist"
not ok 2 - User fliprapp should not be a super user
# Failed test 2: "User fliprapp should not be a super user"
# User fliprapp does not exist
# Looks like you failed 2 tests of 2
tests/013-privs.pg .. Failed 2/2 subtests
Test Summary Report
-------------------
tests/013-privs.pg (Wstat: 0 Tests: 2 Failed: 2)
Failed tests: 1-2
Files=1, Tests=2, 0 wallclock secs
Result: FAIL
327. Check Privileges
% pg_prove -d flipr tests/013-privs.pg
tests/013-privs.pg .. 1/?
not ok 1 - Role fliprapp should exist
# Failed test 1: "Role fliprapp should exist"
not ok 2 - User fliprapp should not be a super user
# Failed test 2: "User fliprapp should not be a super user"
# User fliprapp does not exist
# Looks like you failed 2 tests of 2
tests/013-privs.pg .. Failed 2/2 subtests
Test Summary Report
-------------------
tests/013-privs.pg (Wstat: 0 Tests: 2 Failed: 2)
Failed tests: 1-2
Files=1, Tests=2, 0 wallclock secs
Result: FAIL