Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check nbf and exp claims #21

Merged
merged 1 commit into from
Oct 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
EXTENSION = pgjwt
DATA = pgjwt--0.1.1.sql pgjwt--0.1.0--0.1.1.sql
DATA = pgjwt--0.1.1.sql pgjwt--0.1.0--0.1.1.sql pgjwt--0.1.1--0.2.0.sql

# postgres build stuff
PG_CONFIG = pg_config
Expand Down
29 changes: 29 additions & 0 deletions pgjwt--0.1.1--0.2.0.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
CREATE OR REPLACE FUNCTION try_cast_double(inp text)
RETURNS double precision AS $$
BEGIN
BEGIN
RETURN inp::double precision;
EXCEPTION
WHEN OTHERS THEN RETURN NULL;
END;
END;
$$ language plpgsql IMMUTABLE;


CREATE OR REPLACE FUNCTION verify(token text, secret text, algorithm text DEFAULT 'HS256')
RETURNS table(header json, payload json, valid boolean) LANGUAGE sql AS $$
SELECT
jwt.header AS header,
jwt.payload AS payload,
jwt.signature_ok AND tstzrange(
to_timestamp(try_cast_double(jwt.payload->>'nbf')),
to_timestamp(try_cast_double(jwt.payload->>'exp'))
) @> CURRENT_TIMESTAMP AS valid
FROM (
SELECT
convert_from(@[email protected]_decode(r[1]), 'utf8')::json AS header,
convert_from(@[email protected]_decode(r[2]), 'utf8')::json AS payload,
r[3] = @[email protected]_sign(r[1] || '.' || r[2], secret, algorithm) AS signature_ok
FROM regexp_split_to_array(token, '\.') r
) jwt
$$ IMMUTABLE;
2 changes: 1 addition & 1 deletion pgjwt.control
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# pgjwt extension
comment = 'JSON Web Token API for Postgresql'
default_version = '0.1.1'
default_version = '0.2.0'
relocatable = false
requires = pgcrypto
superuser = false
98 changes: 97 additions & 1 deletion test.sql
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ CREATE EXTENSION pgtap;
CREATE EXTENSION pgjwt;

BEGIN;
SELECT plan(14);
SELECT plan(23);

SELECT
is(sign('{"sub":"1234567890","name":"John Doe","admin":true}', 'secret'),
Expand Down Expand Up @@ -131,5 +131,101 @@ SELECT
);


SELECT
results_eq(
$$SELECT header::text, payload::text, valid FROM verify(
E'eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJuYmYiOiJuby1kb3VibGUifQ.6TDHvMKq3Z67KaexRMuhoQ20sYSj9jConcUCO3g2bGyHXACq-FPkJIRAsy1xX90fWKieIAW_tz-4bbFLwwOTPg',
'secret', 'HS512')$$,
$$VALUES ('{"alg":"HS512","typ":"JWT"}', '{"nbf":"no-double"}', true)$$,
'verify() should ignore a nbf claim with a invalid value'
);


SELECT
results_eq(
$$SELECT header::text, payload::text, valid FROM verify(
E'eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOiI3NXoifQ.nfXYiSNNdYNsLrQp5Zry9p0xDCh_CkMSY1dOdqDCLc1YrDxrItwEmZIlTi3BBO8_9OCameSKMyGysYGDCNoaRg',
'secret', 'HS512')$$,
$$VALUES ('{"alg":"HS512","typ":"JWT"}', '{"exp":"75z"}', true)$$,
'verify() should ignore a exp claim with a invalid value'
);


SELECT
results_eq(
$$SELECT valid
FROM verify(sign(json_build_object('nbf', EXTRACT (EPOCH FROM CURRENT_TIMESTAMP) + 1), 'secret', 'HS512'), 'secret', 'HS512')$$,
$$VALUES (false)$$,
'verify() should not verify a jwt checked before its nbf claim'
);


SELECT
results_eq(
$$SELECT valid
FROM verify(sign(json_build_object('nbf', EXTRACT (EPOCH FROM CURRENT_TIMESTAMP) - 1), 'secret', 'HS512'), 'secret', 'HS512')$$,
$$VALUES (true)$$,
'verify() should verify a jwt checked after its nbf claim'
);


SELECT
results_eq(
$$SELECT valid
FROM verify(sign(json_build_object('exp', EXTRACT (EPOCH FROM CURRENT_TIMESTAMP) - 1), 'secret', 'HS512'), 'secret', 'HS512')$$,
$$VALUES (false)$$,
'verify() should not verify a jwt checked after its exp claim'
);


SELECT
results_eq(
$$SELECT valid
FROM verify(sign(json_build_object('exp', EXTRACT (EPOCH FROM CURRENT_TIMESTAMP) + 1), 'secret', 'HS512'), 'secret', 'HS512')$$,
$$VALUES (true)$$,
'verify() should verify a jwt checked before its exp claim'
);



SELECT
results_eq(
$$SELECT valid
FROM verify(sign(json_build_object('exp', EXTRACT (EPOCH FROM CURRENT_TIMESTAMP) + 1), 'secret', 'HS512'), 'secret', 'HS512')$$,
$$VALUES (true)$$,
'verify() should verify a jwt checked before its exp claim'
);

SELECT
results_eq(
$$SELECT valid
FROM verify(sign(
json_build_object(
'nbf', EXTRACT (EPOCH FROM CURRENT_TIMESTAMP) - 3,
'exp', EXTRACT (EPOCH FROM CURRENT_TIMESTAMP) - 1
),
'secret', 'HS512'), 'secret', 'HS512')$$,
$$VALUES (false)$$,
'verify() should not verify a jwt checked outside of its claimed nbf-exp range'
);


SELECT
results_eq(
$$SELECT valid
FROM verify(
sign(
json_build_object(
'nbf', EXTRACT (EPOCH FROM CURRENT_TIMESTAMP) - 3,
'exp', EXTRACT (EPOCH FROM CURRENT_TIMESTAMP) + 3
),
'secret', 'HS512'
),
'secret', 'HS512')$$,
$$VALUES (true)$$,
'verify() should verify a jwt checked within its claimed nbf-exp range'
);


SELECT * FROM finish();
ROLLBACK;