test_csv2pskc.doctest - tests for the csv2pskc script
Copyright (C) 2018 Arthur de Jong
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
>>> from binascii import a2b_hex
>>> import getpass
>>> import shlex
>>> import sys
>>> import tempfile
>>> from pskc import PSKC
>>> from pskc.scripts.csv2pskc import main
Sadly we cannot test --help and --version properly because argparse calls
exit(0) which doctest does not like.
>>> sys.argv = shlex.split('csv2pskc --help')
>>> main() # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
SystemExit: 0
>>> sys.argv = shlex.split('csv2pskc --version')
>>> main() # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
SystemExit: 0
We can output a PSKC file with some simple data from a CSV file. The columns
in the CSV file refer to names of PSKC properties.
>>> f = tempfile.NamedTemporaryFile('w+t')
>>> x = f.write('''
... serial,secret,algorithm,response_length,time_interval
... 987654321,3132333435363738393031323334353637383930,urn:ietf:params:xml:ns:keyprov:pskc:hotp,8,
... 987654321,31323334,urn:ietf:params:xml:ns:keyprov:pskc:pin,4,
... '''.lstrip())
>>> f.flush()
>>> sys.argv = ['csv2pskc', f.name]
>>> main() #doctest: +REPORT_UDIFF +NORMALIZE_WHITESPACE
987654321
MTIzNDU2Nzg5MDEyMzQ1Njc4OTA=
987654321
MTIzNA==
We can also save the output to a file.
>>> f = tempfile.NamedTemporaryFile('w+t')
>>> x = f.write('''
... serial,secret,algorithm,response_length,time_interval
... 987654321,3132333435363738393031323334353637383930,urn:ietf:params:xml:ns:keyprov:pskc:hotp,8,
... 987654321,31323334,urn:ietf:params:xml:ns:keyprov:pskc:pin,4,
... '''.lstrip())
>>> f2 = tempfile.NamedTemporaryFile()
>>> f.flush()
>>> sys.argv = ['csv2pskc', f.name, '--output', f2.name]
>>> main()
>>> with open(f2.name, 'r') as r:
... x = sys.stdout.write(r.read()) #doctest: +ELLIPSIS +REPORT_UDIFF +NORMALIZE_WHITESPACE
...
MTIzNDU2Nzg5MDEyMzQ1Njc4OTA=
...
MTIzNA==
A bigger example.
>>> f = tempfile.NamedTemporaryFile('w+t')
>>> x = f.write('''
... serial,secret,algorithm,response_length,response_encoding,manufacturer,issuer,policy.start_date,policy.expiry_date,id,counter
... 654321,3132333435363738393031323334353637383930,urn:ietf:params:xml:ns:keyprov:pskc:hotp,8,DECIMAL,TokenVendorAcme,Issuer,2006-05-01 00:00:00+00:00,2006-05-31 00:00:00+00:00,1,2
... 123456,3132333435363738393031323334353637383930,urn:ietf:params:xml:ns:keyprov:pskc:hotp,8,DECIMAL,TokenVendorAcme,Issuer,2006-05-01 00:00:00+00:00,2006-05-31 00:00:00+00:00,2,3
... 9999999,3132333435363738393031323334353637383930,urn:ietf:params:xml:ns:keyprov:pskc:hotp,8,DECIMAL,TokenVendorAcme,Issuer,2006-03-01 00:00:00+00:00,2006-03-31 00:00:00+00:00,3,42
... 9999999,3132333435363738393031323334353637383930,urn:ietf:params:xml:ns:keyprov:pskc:hotp,8,DECIMAL,TokenVendorAcme,Issuer,2006-04-01 00:00:00+00:00,2006-04-30 00:00:00+00:00,4,12
... '''.lstrip())
>>> f.flush()
>>> sys.argv = ['csv2pskc', f.name]
>>> main() #doctest: +REPORT_UDIFF +NORMALIZE_WHITESPACE
TokenVendorAcme
654321
Issuer
MTIzNDU2Nzg5MDEyMzQ1Njc4OTA=
2
2006-05-01T00:00:00Z
2006-05-31T00:00:00Z
TokenVendorAcme
123456
Issuer
MTIzNDU2Nzg5MDEyMzQ1Njc4OTA=
3
2006-05-01T00:00:00Z
2006-05-31T00:00:00Z
TokenVendorAcme
9999999
Issuer
MTIzNDU2Nzg5MDEyMzQ1Njc4OTA=
42
2006-03-01T00:00:00Z
2006-03-31T00:00:00Z
TokenVendorAcme
9999999
Issuer
MTIzNDU2Nzg5MDEyMzQ1Njc4OTA=
12
2006-04-01T00:00:00Z
2006-04-30T00:00:00Z
As long as it is in a file (does not work on stdin) the script should also
automatically pick up tab-separated files.
>>> f = tempfile.NamedTemporaryFile('w+t')
>>> x = f.write('''
... id\tsecret\tcounter
... 654321\t3132333435363738393031323334353637383930\t2
... 123456\t3132333435363738393031323334353637383930\t3
... 9999999\t3132333435363738393031323334353637383930\t42
... 9999999\t3132333435363738393031323334353637383930\t12
... '''.lstrip())
>>> f.flush()
>>> sys.argv = ['csv2pskc', f.name]
>>> main() #doctest: +REPORT_UDIFF +NORMALIZE_WHITESPACE
MTIzNDU2Nzg5MDEyMzQ1Njc4OTA=
2
MTIzNDU2Nzg5MDEyMzQ1Njc4OTA=
3
MTIzNDU2Nzg5MDEyMzQ1Njc4OTA=
42
MTIzNDU2Nzg5MDEyMzQ1Njc4OTA=
12
We can use the --columns option to override using the first row to specify
the key properties.
>>> f = tempfile.NamedTemporaryFile('w+t')
>>> x = f.write('''
... nr,key,start date,info
... 121232,6848464354638468468835346896846846846846,2017-04-01,something
... 213422,9843138168168196616849849634548496832446,2017-02-12,else
... '''.lstrip())
>>> f.flush()
>>> sys.argv = ['csv2pskc', f.name, '--columns', 'id+serial,secret,start_date,-']
>>> main() #doctest: +REPORT_UDIFF +NORMALIZE_WHITESPACE
121232
2017-04-01T00:00:00
aEhGQ1RjhGhGiDU0aJaEaEaEaEY=
213422
2017-02-12T00:00:00
mEMTgWgWgZZhaEmEljRUhJaDJEY=
Alternatively, we can provide a mapping for column names found in the CSV
file to key properties.
>>> f = tempfile.NamedTemporaryFile('w+t')
>>> x = f.write('''
... nr,key,start date,info
... 121232,6848464354638468468835346896846846846846,2017-04-01,something
... 213422,9843138168168196616849849634548496832446,2017-02-12,else
... '''.lstrip())
>>> f.flush()
>>> sys.argv = ['csv2pskc', f.name, '--columns', 'key:secret,nr:id+serial,info:-']
>>> main() #doctest: +REPORT_UDIFF +NORMALIZE_WHITESPACE
121232
2017-04-01T00:00:00
aEhGQ1RjhGhGiDU0aJaEaEaEaEY=
213422
2017-02-12T00:00:00
mEMTgWgWgZZhaEmEljRUhJaDJEY=
We can also set global key properties with the --set option to apply values
to all keys in the PSKC file:
>>> f = tempfile.NamedTemporaryFile('w+t')
>>> x = f.write('''
... id+serial,secret
... 987654321,7c613e9c2194ff7da7f4770ab2ed712111fcbe95
... 987654322,4be618e3459e936137994854bc3d2ebe46f3cce2
... '''.lstrip())
>>> f.flush()
>>> sys.argv = [
... 'csv2pskc', f.name,
... '--set', 'manufacturer=TokenVendor', '--set', 'issuer=TokenIssuer']
>>> main() #doctest: +REPORT_UDIFF +NORMALIZE_WHITESPACE
TokenVendor
987654321
TokenIssuer
fGE+nCGU/32n9HcKsu1xIRH8vpU=
TokenVendor
987654322
TokenIssuer
S+YY40Wek2E3mUhUvD0uvkbzzOI=
The --skip-rows option can be used to either not use the first row to denote
the key properties that are set (in which case the --columns option is
mandatory) or skip more rows at the beginning of the file.
>>> f = tempfile.NamedTemporaryFile('w+t')
>>> x = f.write('''
... 987654321,7c613e9c2194ff7da7f4770ab2ed712111fcbe95
... 987654322,4be618e3459e936137994854bc3d2ebe46f3cce2
... '''.lstrip())
>>> f.flush()
>>> sys.argv = ['csv2pskc', f.name, '--skip-rows=0', '--columns=id+serial,secret']
>>> main() #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE +REPORT_UDIFF
...
...
fGE+nCGU/32n9HcKsu1xIRH8vpU=
...
...
S+YY40Wek2E3mUhUvD0uvkbzzOI=
...
>>> f = tempfile.NamedTemporaryFile('w+t')
>>> x = f.write('''
... id+serial,secret
... IGNORED LINE
... 987654321,7c613e9c2194ff7da7f4770ab2ed712111fcbe95
... 987654322,4be618e3459e936137994854bc3d2ebe46f3cce2
... '''.lstrip())
>>> f.flush()
>>> sys.argv = ['csv2pskc', f.name, '--skip-rows=2']
>>> main() #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE +REPORT_UDIFF
...
...
fGE+nCGU/32n9HcKsu1xIRH8vpU=
...
...
S+YY40Wek2E3mUhUvD0uvkbzzOI=
...
We can encrypt the resulting PSKC file with a passphrase.
>>> f = tempfile.NamedTemporaryFile('w+t')
>>> x = f.write('''
... id,secret
... 987654321,7c613e9c2194ff7da7f4770ab2ed712111fcbe95
... 987654322,4be618e3459e936137994854bc3d2ebe46f3cce2
... '''.lstrip())
>>> f.flush()
>>> sys.argv = ['csv2pskc', f.name, '--passwd', 'supersecure']
>>> main() #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE +REPORT_UDIFF
...
...
16
...
...
...
...
...
...
...
...
...
Alternatively we can switch from passphrase-based encryption to key-based
encryption.
>>> f = tempfile.NamedTemporaryFile('w+t')
>>> x = f.write('''
... id,secret
... 987654321,7c613e9c2194ff7da7f4770ab2ed712111fcbe95
... 987654322,4be618e3459e936137994854bc3d2ebe46f3cce2
... '''.lstrip())
>>> f.flush()
>>> sys.argv = ['csv2pskc', f.name, '--secret', '12345678901234567890123456789012']
>>> main() #doctest: +ELLIPSIS +NORMALIZE_WHITESPACE +REPORT_UDIFF
...
...
...
...
...
...
...
...
...