def reencrypt(self, user): container = Container(self.name, self.path, self.type, user.id) container.files = self.files for f in container.files: f.policy = Policy.generate(f.policy_text, user) db.session.add(f) db.session.delete(self) db.session.add(container) db.session.commit() out = container.dict() out['files'] = list() for f in container.files: out['files'].append(f.dict()) aa_param = dict() aa_param['files'] = list() for f in out['files']: aa_param['files'].append({ "path": f['path'], "type": f['type'], "policy": f['policy'] }) aa_param['outfile'] = container.path aa_param['overwriteOutfile'] = True aa_response = AttrAuth.encrypt_container(container, aa_param) if aa_response is None: return None return True
def generate(policy, current_user): # generate a policy based on a user-specified policy dependend on the policy_mode if policy == all_attr: # if policy is the default policy simply use it return policy else: # otherwise ... users = Policy.evaluate( policy, current_user) # compute the authorized set of contacts if policy_mode == 0: if 'NOT' not in policy: # normal ABE only work if no excludes have been used return Policy.convert(policy) # TODO: else case - what to do if exlcuded have been used elif policy_mode == 1: # case: static ciphertext strategy uuid_attr = 'AAAAA' + str(uuid.uuid4()).replace( '-', '') # generate a unique attribute attr = Attribute( uuid_attr, True, current_user.id) # store this attribute permanently db.session.add(attr) db.session.commit() # and assign it to the authorized contacts for user in users: user.attributes.append(attr) db.session.add(user) aa_response = AttrAuth.add_attr( user, attr, current_user) # AA communication if aa_response is None: db.session.rollback() db.session.commit() return uuid_attr elif policy_mode == 2: # case: static secret key strategy return ' OR '.join( [c.identity for c in users] ) # generate disjunction of identity attribute of authorized contacts
def decrypt_container(): # to decrypt a cipher text data = json.JSONDecoder().decode(request.data) print data if 'container' not in data or 'outputDirectory' not in data: return make_response('', 400) # error missing parameters # extract manifest of a container # to receive identity of sender x = open(data['container'], 'rb') x.read(11) len = struct.unpack('>Q', x.read(8))[0] x.read(32) manifest = x.read(len) x = json.JSONDecoder().decode(manifest) # fetch secret key of sender identity generated for user kex_request = requests.get( kex_url + '/keys/' + x['owner']['emails'][0] + '?access_token=' + current_user.kex_access_token) if kex_request.status_code != 200: return make_response('', 500) # KEX error # send repective secret key to AA data['user'] = {'privateKey': kex_request.text} aa_response = AttrAuth.decrypt_container(json.dumps(data)) if aa_response['success'] is False: return make_response(aa_response['msg'], 500) # error during the decryption return make_response('', 200)
def delete_attribute(attr_id): # to delete an attribute # this function will delete an attribute # and tries to delete if from all contacts that had it assigned to attr = models.Attribute.query.filter_by(id=attr_id).first_or_404() if attr not in current_user.attributes: return make_response('', 403) users = models.Contact.query.filter( models.Contact.attributes.contains(attr)).all() delete_errors = list() for user in users: aa_response = AttrAuth.delete_attr(user, attr, current_user) if aa_response is None: delete_errors.append(user.id) if len(delete_errors) == 0: # analogous error handling db.session.delete(attr) db.session.commit() return make_response('', 200) for user in users: if user.id not in delete_errors: user.attributes.remove(attr) db.session.add(user) db.session.commit() return make_response('', 500)
def add_user(): # this adds a new contact for a logged-in user data = json.JSONDecoder().decode(request.data) if 'name' not in data or 'email' not in data: return make_response('', 400) # error missing parameters user = models.Contact(data['name'], data['email'], current_user.id) db.session.add(user) db.session.commit() # otherwise store contact persistently attr_id = models.Attribute(user.identity, False, current_user.id) attr_id.display_name = user.name attr_all = models.Attribute.query.filter_by(name=all_attr).first() db.session.add(attr_id) db.session.add(attr_all) db.session.commit() user.attributes.append(attr_id) # assign identity attribute to contact user.attributes.append(attr_all) # assign all attribtue to contact db.session.add(user) db.session.commit() aa_response = AttrAuth.add_user(user) # inform AA about created user if aa_response is None: db.session.delete(user) # delete user in error case db.session.commit() return make_response('', 500) user.secret_key = aa_response[ 'secretSeed'] # the AA currently responds with the secret seed not the secret key aa_response = AttrAuth.add_attr( user, attr_id, current_user) # inform AA about identity AA if aa_response is None: db.session.delete(attr_id) # delete it in error case db.session.commit() return make_response('', 500) aa_response = AttrAuth.add_attr( user, attr_all, current_user) # inform AA about all attribute if aa_response is None: db.session.delete(attr_all) # delete in error case db.session.commit() return make_response('', 500) return make_response(json.dumps(user.dict()), 201)
def add_container(): data = json.JSONDecoder().decode(request.data) if 'name' not in data or 'files' not in data: return make_response('', 400) # error missing parameter if not data['files']: return make_response('', 400) # error missing parameter if 'output_path' in data: output_path = os.path.join(data['output_path'], data['name'] + cont_ext) # if output_path is specified use it else: output_path = os.path.join(basedir, 'data', str(current_user.id), data['name'] + cont_ext) # otherwise generate it container = models.Container(data['name'], output_path, policy_mode, current_user.id) # create container db.session.add(container) # and store it persistently db.session.commit() for f in data['files']: # iterate through submitted files array if 'path' not in f or 'type' not in f or 'policy' not in f: return make_response('', 400) # error missing file parameter if not os.path.isfile(f['path']): return make_response('', 404) # error file does not exist # TODO: delete created container in error case f['policy'] = f['policy'].replace(', ', ',').replace(': ', ':') # parse submitted policy policy = models.Policy.generate(f['policy'], current_user) # create file db.session.add(models.File(f['path'], f['type'], policy, f['policy'], container.id)) # store in DB db.session.commit() # serialize container for response out = container.dict() out['files'] = list() for f in container.files: out['files'].append(f.dict()) # generate AA parameter aa_param = dict() aa_param['files'] = list() for f in out['files']: aa_param['files'].append({ "path": f['path'], "type": f['type'], "policy": f['policy'] }) aa_param['outfile'] = container.path aa_param['owner'] = {'emails': [current_user.email]} # embed identity of user into container aa_response = AttrAuth.encrypt_container(container, aa_param) # start encryption if aa_response is None: return make_response('', 500) # error AA error return make_response(json.dumps(out), 201) # successful encryption
def delete_user(user_id): # to delete a contact user = models.Contact.query.filter_by(id=user_id).first_or_404() if user not in current_user.contacts: return make_response('', 403) attr_id = models.Attribute.query.filter_by(name=user.identity).first() aa_response = AttrAuth.delete_attr(user, attr_id, current_user) if aa_response is None: return make_response('', 500) aa_response = AttrAuth.delete_user(user) if aa_response is None: return make_response('', 400) db.session.delete(attr_id) db.session.delete(user) db.session.commit() return make_response('', 200)
def get_secret_key(user_id): # to get the secret key in HTTP body user = models.Contact.query.filter_by(id=user_id).first_or_404() if user not in current_user.contacts: return make_response('', 403) aa_response = AttrAuth.get_priv_key(user) if aa_response is None: return make_response('', 400) return make_response(aa_response['privatekey'], 200)
def check_for(contact, user): # check_for() is used to determine ciphertexts that have to be updated after a contact has been modified container = Container.query.filter_by(user_id=user.id) for c in container: # iterate over all container of a user if c.type == 0: # case: no strategy used - do nothing pass elif c.type == 1: # case: static ciphertext strategy used for f in c.files: # iterate over all files - for each file allowed_users = Policy.evaluate( f.policy_text, user) # evaluate the policy of the file uuid = Attribute.query.filter_by(name=f.policy).first() if contact not in allowed_users and uuid in contact.attributes: # if contact is not in set of allowed_users after modification contact.attributes.remove( uuid) # remove uuid attribute from the contact db.session.add(contact) db.session.commit() aa_response = AttrAuth.delete_attr( contact, uuid, user) # inform AA if aa_response is None: db.session.rollback() elif contact in allowed_users and uuid not in contact.attributes: # if contact is in set of allowed_users but has not the corresponding attribute contact.attributes.append( uuid) # assign attribute to the contact db.session.add(contact) db.session.commit() aa_response = AttrAuth.add_attr(contact, uuid, user) # inform AA if aa_response is None: db.session.rollback() elif c.type == 2: # case: static secret key strategy used for f in c.files: # iterate through files again allowed_users = Policy.evaluate( f.policy_text, user) # compute authorized users if contact not in allowed_users and contact.identity in f.policy: # if user is not intented to have access to the resource after modification c.reencrypt(user) # reencrypt if contact in allowed_users and contact.identity not in f.policy: # if user is intended to have access to the resource after the modification c.reencrypt(user) # reencrypt
def download_private_key(user_id): # to download the private key as file user = models.Contact.query.filter_by(id=user_id).first_or_404() if user not in current_user.contacts: return make_response('', 403) aa_response = AttrAuth.get_priv_key(user) if aa_response is None: return make_response('', 400) response = make_response(base64.b64decode(aa_response['privatekey'])) response.headers[ 'Content-Disposition'] = 'attachment; filename=' + user.email + '.private_key' return response
def show_user(user_id): user = models.Contact.query.filter_by(id=user_id).first_or_404() if user not in current_user.contacts: return make_response('', 403) out = user.dict() out['properties'] = [p.dict() for p in user.properties] out['attributes'] = [a.dict() for a in user.attributes if not a.sys] # load the private key from the AA aa_response = AttrAuth.get_priv_key(user) if aa_response is not None: out['private_key'] = aa_response['privatekey'] return make_response(json.dumps(out), 200)
def show_container(container_id): # show status of container # can be used to check status of ongoing encryption processes container = models.Container.query.filter_by(id=container_id).first_or_404() if container not in current_user.container: return make_response('', 403) out = container.dict() out['files'] = list() for f in container.files: out['files'].append(f.dict()) aa_response = AttrAuth.status_container(container) if aa_response['success'] is False: return make_response(aa_response['msg'], 500) else: out['status'] = aa_response['status'] return make_response(json.dumps(out), 200)
def assign_attribute(user_id, attr_id): # to assign an existent attribute to a contact user = models.Contact.query.filter_by(id=user_id).first_or_404() if user not in current_user.contacts: return make_response('', 403) attr = models.Attribute.query.filter_by(id=attr_id).first_or_404() if attr not in current_user.attributes: return make_response('', 403) aa_response = AttrAuth.add_attr(user, attr, current_user) if aa_response is None: return make_response('', 500) user.attributes.append(attr) db.session.add(user) db.session.commit() Policy.check_for(user, current_user) # involves reevaluation return make_response('', 200)
def dissociate_attribute(user_id, attr_id): # to dissociate an attribute from a contact # NOTE: this does not delete the entire attribute user = models.Contact.query.filter_by(id=user_id).first_or_404() if user not in current_user.contacts: return make_response('', 403) attr = models.Attribute.query.filter_by(id=attr_id).first_or_404() if attr not in current_user.attributes: return make_response('', 403) aa_response = AttrAuth.delete_attr(user, attr, current_user) if aa_response is None: return make_response('', 500) user.attributes.remove(attr) db.session.add(user) db.session.commit() Policy.check_for(user, current_user) # involves reevaluation return make_response('', 200)
def assign_new_attribute(user_id): # to assign a new attribute to a contact user = models.Contact.query.filter_by(id=user_id).first_or_404() if user not in current_user.contacts: return make_response('', 403) data = json.JSONDecoder().decode(request.data) if 'name' not in data: return make_response('', 400) attr = models.Attribute(data['name'], False, current_user.id) # instantiate attribute db.session.add(attr) try: db.session.commit() # try to commit except exc.IntegrityError: # in case attribute already exists db.session.rollback() attr = models.Attribute.query.filter_by( display_name=data['name']).first() # use the existent one if attr in user.attributes: # if attribute already assigned - notify user return make_response('', 409) # else ... aa_response = AttrAuth.add_attr(user, attr, current_user) # inform AA if aa_response is None: db.session.delete(attr) # error case - delete attribute db.session.commit() return make_response('', 500) # and inform user user.attributes.append(attr) # otherwise assign it to contact db.session.add(user) db.session.commit() Policy.check_for( user, current_user ) # depending on the enforcement strategy - reevaluate all container return make_response(json.dumps(attr.dict()), 200) # success
def edit_attribute(attr_id): # this tries to modify an attribute # all contacts that have the original attribute assigned are updated # therefore the original attribute is deleted from these # and the new attribute is assigned to these attr = models.Attribute.query.filter_by(id=attr_id).first_or_404() if attr not in current_user.attributes: return make_response('', 403) data = json.JSONDecoder().decode(request.data) if 'name' not in data: return make_response('', 400) attr_new = models.Attribute(data['name'], False, current_user.id) db.session.add(attr_new) try: db.session.commit() except exc.IntegrityError: db.session.rollback() return make_response(json.dumps(attr.dict()), 409) users = models.Contact.query.filter( models.Contact.attributes.contains(attr)).all() delete_errors = list() create_errors = list() for user in users: # iterate through contacts aa_response = AttrAuth.delete_attr(user, attr, current_user) # delete wave if aa_response is None: delete_errors.append( user.id) # in error case remember faulty contacts aa_response = AttrAuth.add_attr(user, data['name'], current_user) # create wave if aa_response is None: create_errors.append( user.id) # in error case remember faulty contacts if len(delete_errors) == 0 and len( create_errors) == 0: # case no errors in wave db.session.delete(attr_new) db.session.commit() attr.name = attr_new.name db.session.add(attr) db.session.commit() return make_response(json.dumps(attr.dict()), 200) # success if len(users) == len( create_errors): # case create wave not successfull for any user db.session.delete(attr_new) # delete the new attribute db.session.commit() # at least state is consistent for user in users: # iterate through users again if user.id not in delete_errors: user.attributes.remove( attr) # delete old attribute for successful contacts if user.id not in create_errors: user.attributes.append( attr_new) # create new attribute for successful contacts db.session.add(user) db.session.commit() # leave the rest as is # yet notify client with status code 500 # to indicate an error occured return make_response('', 500)