Snippets
Created by
John Frommeyer
last modified
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | #!/usr/bin/env python3
# Will get SSL warnings if python 2 is used. Still works though.
"""Testing web service"""
import sys
from datetime import datetime
import hashlib
import hmac
import base64
import argparse
import getpass
import requests
SCHEME = 'https://'
HOST = 'pennprovenance.net'
BASE_URL = SCHEME + HOST
TOKENS_PATH = '/prov/tokens'
def hash_and_encode(payload):
"""hash and base64 encode the string payload"""
payload_bytes = payload.encode('utf-8')
hasher = hashlib.sha256()
hasher.update(payload_bytes)
hashed_bytes = hasher.digest()
encoded_hashed_bytes = base64.standard_b64encode(hashed_bytes)
encoded_hashed = encoded_hashed_bytes.decode('utf-8')
return encoded_hashed
def sign_string(token, string_to_sign):
"""return base64 encoding of signature for string_to_sign signed by token"""
key_bytes = token.encode('utf-8')
msg_bytes = string_to_sign.encode('utf-8')
signature_bytes = hmac.new(
key_bytes, msg=msg_bytes, digestmod=hashlib.sha256).digest()
encoded_signature_bytes = base64.standard_b64encode(signature_bytes)
encoded_signature = encoded_signature_bytes.decode('utf-8')
return encoded_signature
def get_auth_headers(
session_token,
http_method,
request_path,
query_string,
payload):
"""return authentication headers for the request signed with sessionToken"""
session_key = session_token['key']
now = datetime.now().isoformat()
payload_for_signing = hash_and_encode(payload)
string_to_sign = '\n'.join((
session_key,
http_method,
HOST,
request_path,
query_string,
now,
payload_for_signing))
token = session_token['token']
signature = sign_string(token, string_to_sign)
auth_headers = {'sessionKey': session_key,
'timestamp': now,
'signature': signature}
return auth_headers
def create_token(url, username, password):
"""create token and return sessionToken dict"""
post_payload = {
'credentials': {
'name': username,
'password': password
}
}
post_headers = {'Accept': 'application/json'}
post_response = requests.post(url,
headers=post_headers, json=post_payload)
if post_response.status_code != 200:
sys.exit('POST error:' + post_response.text)
post_response_json = post_response.json()
session_token = post_response_json['sessionToken']
print('successfully created session token: ' + session_token['key'])
return session_token
def delete_token(session_token):
"""delete token"""
session_key = session_token['key']
method = 'DELETE'
query_string = ''
delete_path = TOKENS_PATH + '/' + session_key
payload = ''
delete_headers = get_auth_headers(
session_token,
method,
delete_path,
query_string,
payload)
# Even though we don't expect a body in response add Accept header in case
# we get error back. Otherwise we'd get XML version.
delete_headers['Accept'] = 'application/json'
delete = requests.delete(
BASE_URL + delete_path,
headers=delete_headers)
if delete.status_code != 204:
sys.exit('DELETE error:' + delete.text)
print('successfully deleted session token: ' + session_key)
def main():
"""create and delete a token for signature testing"""
parser = argparse.ArgumentParser(
description='Create and delete token to test request signing')
parser.add_argument(
'--username',
dest='username',
required=True,
help='the user\'s username')
parser.add_argument(
'--password',
dest='password',
help="""The user\'s password.
If not supplied on command line, the user will be prompted for password.""")
args = parser.parse_args()
username = args.username
password = args.password
if password is None:
password = getpass.getpass(
prompt='Enter password for ' + username + ': ')
session_token = create_token(
BASE_URL + TOKENS_PATH,
username,
password)
delete_token(session_token)
if __name__ == '__main__':
main()
|
Comments (0)
You can clone a snippet to your computer for local editing. Learn more.