def header(url, method, options=None): """ :param uri: 'http://example.com/resource?a=b' :param method: HTTP verb ('GET', 'POST', etc) :param options: Required Options: credentials (id, key, algorithm) Optional: ext: Application specific data (string) timestamp: A pre-calculated timestamp nonce: '2334f34f': A pre-generated nonce localtimeOffsetMsec: Time offset to sync with server time (ignored if timestamp provided) (Example 400) payload: UTF-8 encoded string for body hash generation (ignored if hash provided) (Example '{"some":"payload"}') contentType: Payload content-type (ignored if hash provided) (Example 'application/json') hash: Pre-calculated payload hash (Example 'U4MKKSmiVxk37JCCrAVIjV=') app: Oz application id ('24s23423f34dx') dlg: Oz delegated-by application id - '234sz34tww3sd' """ result = {'field': '', 'artifacts': {}} if url is None or len(url) == 0: log.info("Bad URL skipping") return result if method is None or len(method) == 0: log.info("Bad method skipping") return result if not isinstance(options, dict): log.info("Bad options skipping") return result if 'credentials' not in options: log.info("Bad credentials skipping") return result cred = options['credentials'] if 'id' not in cred or 'key' not in cred or 'algorithm' not in cred: log.info("Bad credentail elements skipping") return result timestamp = math.floor(time.time()) if 'timestamp' in options: offset = 0 if 'localtimeOffsetMsec' in options: offset = int(options['localtimeOffsetMsec']) timestamp = math.floor(options['timestamp'] + offset) if 'nonce' not in options: options['nonce'] = hcrypto.random_string(6) url_parts = util.parse_normalized_url(url) # TODO use None or '' for these optional artifacts? if 'hash' not in options: options['hash'] = None if 'ext' not in options: options['ext'] = None if 'app' not in options: options['app'] = None if 'dlg' not in options: options['dlg'] = None resource = url_parts['resource'] log.debug('parsed URL parts: %s' % pprint.pformat(url_parts)) artifacts = { 'ts': int(timestamp), 'nonce': options['nonce'], 'method': method, 'resource': resource, 'host': url_parts['hostname'], 'port': url_parts['port'], 'hash': options['hash'], 'ext': options['ext'], 'app': options['app'], 'dlg': options['dlg'] } result['artifacts'] = artifacts if artifacts['hash'] is None and 'payload' in options: if 'contentType' not in options: options['contentType'] = 'text/plain' log.debug('about to hash payload: %s' % options['payload']) log.debug('algorithm=%s, contentType=%s' % (cred['algorithm'], options['contentType'])) artifacts['hash'] = hcrypto.calculate_payload_hash( options['payload'], cred['algorithm'], options['contentType']) log.debug('artifacts=%s' % pprint.pformat(artifacts)) mac = hcrypto.calculate_mac('header', cred, artifacts) _header = ''.join([ 'Hawk id="', cred['id'], '"', ', ts="', str(artifacts['ts']), '"', ', nonce="', artifacts['nonce'], '"', ]) if len(artifacts['hash']) > 0: _header += ', hash="' + artifacts['hash'] + '"' if artifacts['ext'] is not None and len(artifacts['ext']) > 0: util.check_header_attribute(artifacts['ext']) h_ext = artifacts['ext'].replace('\\', '\\\\').replace('\n', '\\n') _header += ', ext="' + h_ext + '"' _header += ', mac="' + mac + '"' if artifacts['app'] is not None: _header += ', app="' + artifacts['app'] + '"' if artifacts['dlg'] is not None: _header += ', dlg="' + artifacts['dlg'] + '"' result['field'] = _header return result
def before_insert_posts(documents): meta_post = current_app.config.get('META_POST') posts_endpoint = meta_post['server']['urls']['posts_feed'] app_type = str(url_for('server_info.types_item', name='app', _external=True)) credentials_type = str(url_for('server_info.types_item', name='credentials', _external=True)) for document in documents: # Create version information, but save app version data if present current_time = time.time() time_seconds = int(current_time) time_millisec = int(current_time * 1000) time_microsec = int(current_time * 1000000) app_version = get_app_version(document) digest = create_version_digest(document) document['version'] = create_version_document(digest, time_millisec, app_version) # Create an ID for the document if document['type'] == credentials_type: # Since credentials posts are created automatically by the server, # we need to specify their IDs in microseconds document['_id'] = str(NewBase60(time_microsec)) else: document['_id'] = str(NewBase60(time_seconds)) # Additional processing for certain post types if document['type'] == app_type: # For app posts, we must create an additional credentials post # and make sure they link to each other hawk_key = str(random_string(64)) hawk_algorithm = 'sha256' credentials_post = { 'entity': str(meta_post['entity']), 'type': credentials_type, 'content': { 'hawk_key': hawk_key, 'hawk_algorithm': hawk_algorithm }, 'links': [ { 'post': str(document['_id']), 'url': str(posts_endpoint + "/" + document['_id']), 'type': app_type } ] } response, _, _, status = post_internal('posts', credentials_post) if not 'links' in document: document['links'] = [] cred_id = str(response['_id']) cred_url = str(posts_endpoint + "/" + cred_id) document['links'].append({ 'post': cred_id, 'url': cred_url, 'type': credentials_type }) # Create a signal to change the POST response envelope g.app_POST = True credentials = { 'id': cred_id, 'key': hawk_key, 'algorithm': hawk_algorithm } g.cred_bewit_url = cred_url + '?bewit=' + hawk_get_bewit(cred_url, {'credentials': credentials, 'ttl_sec': BEWIT_TTL})
def header(url, method, options=None): """ :param uri: 'http://example.com/resource?a=b' :param method: HTTP verb ('GET', 'POST', etc) :param options: Required Options: credentials (id, key, algorithm) Optional: ext: Application specific data (string) timestamp: A pre-calculated timestamp nonce: '2334f34f': A pre-generated nonce localtimeOffsetMsec: Time offset to sync with server time (ignored if timestamp provided) (Example 400) payload: UTF-8 encoded string for body hash generation (ignored if hash provided) (Example '{"some":"payload"}') contentType: Payload content-type (ignored if hash provided) (Example 'application/json') hash: Pre-calculated payload hash (Example 'U4MKKSmiVxk37JCCrAVIjV=') app: Oz application id ('24s23423f34dx') dlg: Oz delegated-by application id - '234sz34tww3sd' """ result = {'field': '', 'artifacts': {}} if url is None or len(url) == 0: print "Bad URL skipping" return result if method is None or len(method) == 0: print "Bad method skipping" return result if not isinstance(options, dict): print "Bad options skipping" return result if 'credentials' not in options: print "Bad credentials skipping" return result cred = options['credentials'] if 'id' not in cred or 'key' not in cred or 'algorithm' not in cred: print "Bad credentail elements skipping" return result timestamp = math.floor(time.time()) if 'timestamp' in options: offset = 0 if 'localtimeOffsetMsec' in options: offset = int(options['localtimeOffsetMsec']) timestamp = math.floor(options['timestamp'] + offset) if 'nonce' not in options: options['nonce'] = hcrypto.random_string(6) url_parts = parse_normalized_url(url) # TODO use None or '' for these optional artifacts? if 'hash' not in options: options['hash'] = None if 'ext' not in options: options['ext'] = None if 'app' not in options: options['app'] = None if 'dlg' not in options: options['dlg'] = None resource = url_parts['path'] if len(url_parts['query']) > 0: resource += '?' + url_parts['query'] artifacts = { 'ts': int(timestamp), 'nonce': options['nonce'], 'method': method, 'resource': resource, 'host': url_parts['hostname'], 'port': url_parts['port'], 'hash': options['hash'], 'ext': options['ext'], 'app': options['app'], 'dlg': options['dlg'] } result['artifacts'] = artifacts if artifacts['hash'] is None and 'payload' in options: if 'contentType' not in options: options['contentType'] = 'text/plain' artifacts['hash'] = hcrypto.calculate_payload_hash( options['payload'], cred['algorithm'], options['contentType']) mac = hcrypto.calculate_mac('header', cred, artifacts) _header = ''.join([ 'Hawk id="', cred['id'], '"', ', ts="', str(artifacts['ts']), '"', ', nonce="', artifacts['nonce'], '"', ]) if len(artifacts['hash']) > 0: _header += ', hash="' + artifacts['hash'] + '"' if artifacts['ext'] is not None and len(artifacts['ext']) > 0: util.check_header_attribute(artifacts['ext']) h_ext = artifacts['ext'].replace('\\', '\\\\').replace('\n', '\\n') _header += ', ext="' + h_ext + '"' _header += ', mac="' + mac + '"' if artifacts['app'] is not None: _header += ', app="' + artifacts['app'] + '"' if artifacts['dlg'] is not None: _header += ', dlg="' + artifacts['dlg'] + '"' result['field'] = _header return result