Bugzilla – Attachment 129024 Details for
Bug 29543
Self-checkout allows returning everybody's loans
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 29543: Add JWT token handling
Bug-29543-Add-JWT-token-handling.patch (text/plain), 5.57 KB, created by
Jonathan Druart
on 2022-01-05 14:13:26 UTC
(
hide
)
Description:
Bug 29543: Add JWT token handling
Filename:
MIME Type:
Creator:
Jonathan Druart
Created:
2022-01-05 14:13:26 UTC
Size:
5.57 KB
patch
obsolete
>From 1960ac0d2c0f3bb3e67f51c135512fd4c9cab102 Mon Sep 17 00:00:00 2001 >From: Jonathan Druart <jonathan.druart@bugs.koha-community.org> >Date: Wed, 5 Jan 2022 12:20:28 +0100 >Subject: [PATCH] Bug 29543: Add JWT token handling > >Mojo::JWT is installed already, it's not a new dependency. >We need a way to send the patron a token when it's correctly logged in, >and not assumed it's logged in only if patronid is passed >--- > Koha/Token.pm | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++- > t/Token.t | 18 ++++++++++- > 2 files changed, 104 insertions(+), 2 deletions(-) > >diff --git a/Koha/Token.pm b/Koha/Token.pm >index 3f016be86d5..87dc835e1e6 100644 >--- a/Koha/Token.pm >+++ b/Koha/Token.pm >@@ -1,6 +1,6 @@ > package Koha::Token; > >-# Created as wrapper for CSRF tokens, but designed for more general use >+# Created as wrapper for CSRF and JWT tokens, but designed for more general use > > # Copyright 2016 Rijksmuseum > # >@@ -52,6 +52,7 @@ use Modern::Perl; > use Bytes::Random::Secure; > use String::Random; > use WWW::CSRF; >+use Mojo::JWT; > use Digest::MD5 qw( md5_base64 ); > use Encode; > use Koha::Exceptions::Token; >@@ -78,6 +79,9 @@ sub new { > my $csrf_token = $tokenizer->generate({ > type => 'CSRF', id => $id, secret => $secret, > }); >+ my $jwt = $tokenizer->generate({ >+ type => 'JWT, id => $id, secret => $secret, >+ }); > > Generate several types of tokens. Now includes CSRF. > For non-CSRF tokens an optional pattern parameter overrides length. >@@ -101,6 +105,8 @@ sub generate { > my ( $self, $params ) = @_; > if( $params->{type} && $params->{type} eq 'CSRF' ) { > $self->{lasttoken} = _gen_csrf( $params ); >+ } elsif( $params->{type} && $params->{type} eq 'JWT' ) { >+ $self->{lasttoken} = _gen_jwt( $params ); > } else { > $self->{lasttoken} = _gen_rand( $params ); > } >@@ -122,6 +128,21 @@ sub generate_csrf { > return $self->generate({ %$params, type => 'CSRF' }); > } > >+=head2 generate_jwt >+ >+ Like: generate({ type => 'JWT', ... }) >+ Note that JWT is designed to encode a structure but here we are actually only allowing a value >+ that will be store in the key 'id'. >+ >+=cut >+ >+sub generate_jwt { >+ my ( $self, $params ) = @_; >+ return if !$params->{id}; >+ $params = _add_default_jwt_params( $params ); >+ return $self->generate({ %$params, type => 'JWT' }); >+} >+ > =head2 check > > my $result = $tokenizer->check({ >@@ -138,6 +159,9 @@ sub check { > if( $params->{type} && $params->{type} eq 'CSRF' ) { > return _chk_csrf( $params ); > } >+ elsif( $params->{type} && $params->{type} eq 'JWT' ) { >+ return _chk_jwt( $params ); >+ } > return; > } > >@@ -156,6 +180,33 @@ sub check_csrf { > return $self->check({ %$params, type => 'CSRF' }); > } > >+=head2 check_jwt >+ >+ Like: check({ type => 'JWT', id => $id, token => $token }) >+ >+ Will return true if the token contains the passed id >+ >+=cut >+ >+sub check_jwt { >+ my ( $self, $params ) = @_; >+ $params = _add_default_jwt_params( $params ); >+ return $self->check({ %$params, type => 'JWT' }); >+} >+ >+=head2 decode_jwt >+ >+ $tokenizer->decode_jwt({ type => 'JWT', token => $token }) >+ >+ Will return the value of the id stored in the token. >+ >+=cut >+sub decode_jwt { >+ my ( $self, $params ) = @_; >+ $params = _add_default_jwt_params( $params ); >+ return _decode_jwt( $params ); >+} >+ > # --- Internal routines --- > > sub _add_default_csrf_params { >@@ -220,6 +271,41 @@ sub _gen_rand { > return $token; > } > >+sub _add_default_jwt_params { >+ my ( $params ) = @_; >+ my $pw = C4::Context->config('pass'); >+ $params->{secret} //= md5_base64( Encode::encode( 'UTF-8', $pw ) ), >+ return $params; >+} >+ >+sub _gen_jwt { >+ my ( $params ) = @_; >+ return if !$params->{id} || !$params->{secret}; >+ >+ return Mojo::JWT->new( >+ claims => { id => $params->{id} }, >+ secret => $params->{secret} >+ )->encode; >+} >+ >+sub _chk_jwt { >+ my ( $params ) = @_; >+ return if !$params->{id} || !$params->{secret} || !$params->{token}; >+ >+ my $claims = Mojo::JWT->new(secret => $params->{secret})->decode($params->{token}); >+ >+ return 1 if exists $claims->{id} && $claims->{id} == $params->{id}; >+} >+ >+sub _decode_jwt { >+ my ( $params ) = @_; >+ return if !$params->{token} || !$params->{secret}; >+ >+ my $claims = Mojo::JWT->new(secret => $params->{secret})->decode($params->{token}); >+ >+ return $claims->{id}; >+} >+ > =head1 AUTHOR > > Marcel de Rooy, Rijksmuseum Amsterdam, The Netherlands >diff --git a/t/Token.t b/t/Token.t >index 89154a39fd6..d7de3113cf5 100755 >--- a/t/Token.t >+++ b/t/Token.t >@@ -20,7 +20,7 @@ > # along with Koha; if not, see <http://www.gnu.org/licenses>. > > use Modern::Perl; >-use Test::More tests => 11; >+use Test::More tests => 12; > use Test::Exception; > use Time::HiRes qw|usleep|; > use C4::Context; >@@ -101,3 +101,19 @@ subtest 'Pattern parameter' => sub { > ok( $id !~ /[^A-Z]/, 'Only uppercase letters' ); > throws_ok( sub { $tokenizer->generate({ pattern => 'abc{d,e}', }) }, 'Koha::Exceptions::Token::BadPattern', 'Exception should be thrown when wrong pattern is used'); > }; >+ >+subtest 'JWT' => sub { >+ plan tests => 3; >+ >+ my $id = 42; >+ my $jwt = $tokenizer->generate_jwt({ id => $id }); >+ >+ my $is_valid = $tokenizer->check_jwt({ id => $id, token => $jwt }); >+ is( $is_valid, 1, 'valid token should return 1' ); >+ >+ $is_valid = $tokenizer->check_jwt({ id => 24, token => $jwt }); >+ isnt( $is_valid, 1, 'invalid token should not return 1' ); >+ >+ my $retrieved_id = $tokenizer->decode_jwt({ token => $jwt }); >+ is( $retrieved_id, $id, 'id stored in jwt should be correct' ); >+}; >-- >2.25.1
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 29543
:
129022
|
129023
|
129024
|
129025
|
129026
|
129031
|
129032
|
129033
|
129034
|
129035
|
129036
|
129037
|
129039
|
129133
|
129210
|
129211
|
129212
|
129213
|
129214
|
129215
|
129216
|
129217
|
129679