def test_dymo_no_write_when_read_disabled(self): # pylint: disable=no-self-use model = QuestionnaireState(USER_ID, STATE_DATA, VERSION) with mock.patch('app.storage.data_access.is_dynamodb_read_enabled', mock.Mock(return_value=False)), \ mock.patch('app.storage.data_access.models.db.session.add') as merge: data_access.put(model, overwrite=False) merge.assert_called()
def _save_session(self, session_id, user_id, data, legacy=False): raw_data = json.dumps(vars(data)) protected_header = { 'alg': 'dir', 'enc': 'A256GCM', 'kid': '1,1', } if legacy: plaintext = base64url_encode(raw_data) else: plaintext = raw_data jwe_token = jwe.JWE( plaintext=plaintext, protected=protected_header, recipient=self.key ) session_model = EQSession( session_id, user_id, jwe_token.serialize(compact=True) ) data_access.put(session_model)
def use_jti_claim(jti_claim, expires): """ Use a jti claim :param jti_claim: jti claim to mark as used. :param expires: when the jti claim expires. :raises ValueError: when jti_claim is None. :raises TypeError: when jti_claim is not a valid uuid4. :raises JtiTokenUsed: when jti_claim has already been used. """ if jti_claim is None: raise ValueError if not _is_valid(jti_claim): logger.info('jti claim is invalid', jti_claim=jti_claim) raise TypeError try: used_at = datetime.now(tz=tzutc()) # Make claim expire a little later than exp to avoid race conditions with out of sync clocks. expires += timedelta(seconds=60) jti = UsedJtiClaim(jti_claim, used_at, expires) data_access.put(jti, overwrite=False) except ItemAlreadyExistsError as e: logger.error('jti claim has already been used', jti_claim=jti_claim) raise JtiTokenUsed(jti_claim) from e
def test_put(self): model = QuestionnaireState(USER_ID, STATE_DATA, VERSION) with mock.patch('app.storage.dynamodb_api.put') as put: data_access.put(model) self.assertEqual(put.call_args[0][0], model) self.assertTrue(put.call_args[0][1])
def test_put_rds_no_overwrite(self): model = QuestionnaireState(USER_ID, STATE_DATA, VERSION) setattr(model, '_use_dynamo', False) with mock.patch('app.data_model.models.db.session.add', side_effect=IntegrityError('', '', '')) as add, \ self.assertRaises(ItemAlreadyExistsError): data_access.put(model, overwrite=False) self.assertTrue(add.called)
def test_put_propogate_dynamo_exception(self): model = QuestionnaireState(USER_ID, STATE_DATA, VERSION) side_effect = ClientError({'Error': { 'Code': 'RandomError' }}, 'PutItem') with mock.patch('app.storage.dynamo_api.put_item', side_effect=side_effect) as put_item, \ self.assertRaises(ClientError): data_access.put(model, overwrite=False) self.assertFalse(put_item.call_args[1]['overwrite'])
def save(self): """ save session """ if self._eq_session: self._eq_session.session_data = \ StorageEncryption(self.user_id, self.user_ik, self.pepper).encrypt_data(vars(self.session_data)) data_access.put(self._eq_session) return self
def test_put_no_overwrite(self): model = QuestionnaireState(USER_ID, STATE_DATA, VERSION) side_effect = ClientError( {'Error': { 'Code': 'ConditionalCheckFailedException' }}, 'PutItem') with mock.patch('app.storage.dynamo_api.put_item', side_effect=side_effect) as put_item, \ self.assertRaises(ItemAlreadyExistsError): data_access.put(model, overwrite=False) self.assertFalse(put_item.call_args[1]['overwrite'])
def test_put_rds(self): model = QuestionnaireState(USER_ID, STATE_DATA, VERSION) setattr(model, '_use_dynamo', False) with mock.patch('app.data_model.models.db.session.merge') as merge: data_access.put(model) self.assertTrue(merge.called) rds_model = merge.call_args[0][0] self.assertEqual(rds_model.user_id, USER_ID) self.assertEqual(rds_model.state, STATE_DATA) self.assertEqual(rds_model.version, VERSION)
def test_put(self): model = QuestionnaireState(USER_ID, STATE_DATA, VERSION) with mock.patch('app.storage.dynamo_api.put_item') as put_item: data_access.put(model) self.assertEqual(put_item.call_args[0][1], 'user_id') dynamo_item = put_item.call_args[0][2] self.assertEqual(dynamo_item['user_id'], USER_ID) self.assertEqual(dynamo_item['state_data'], STATE_DATA) self.assertEqual(dynamo_item['version'], VERSION) self.assertTrue(put_item.call_args[1]['overwrite'])
def add_or_update(self, data, version): compressed_data = snappy.compress(data) encrypted_data = self.encrypter.encrypt_data(compressed_data) questionnaire_state = self._find_questionnaire_state() if questionnaire_state: logger.debug('updating questionnaire data', user_id=self._user_id) questionnaire_state.state_data = encrypted_data questionnaire_state.version = version else: logger.debug('creating questionnaire data', user_id=self._user_id) questionnaire_state = QuestionnaireState(self._user_id, encrypted_data, version) data_access.put(questionnaire_state)
def add_or_update(self, data, version): encrypted_data = self.encrypter.encrypt_data(data) encrypted_data_json = json.dumps({'data': encrypted_data}) questionnaire_state = self._find_questionnaire_state() if questionnaire_state: logger.debug('updating questionnaire data', user_id=self._user_id) questionnaire_state.state_data = encrypted_data_json questionnaire_state.version = version else: logger.debug('creating questionnaire data', user_id=self._user_id) questionnaire_state = QuestionnaireState(self._user_id, encrypted_data_json, version) data_access.put(questionnaire_state)
def _store_viewable_submission(answers, metadata, submitted_time): pepper = current_app.eq['secret_store'].get_secret_by_name( 'EQ_SERVER_SIDE_STORAGE_ENCRYPTION_USER_PEPPER') encrypter = StorageEncryption(current_user.user_id, current_user.user_ik, pepper) encrypted_data = encrypter.encrypt_data( { 'answers': answers, 'metadata': metadata.copy(), }, ) valid_until = submitted_time + timedelta( seconds=g.schema.json['view_submitted_response']['duration']) item = SubmittedResponse( tx_id=metadata['tx_id'], data=encrypted_data, valid_until=valid_until.replace(tzinfo=tzutc()), ) data_access.put(item)
def _save_legacy_state_data(self, user_id, data): protected_header = { 'alg': 'dir', 'enc': 'A256GCM', 'kid': '1,1', } jwe_token = jwe.JWE( plaintext=base64url_encode(data), protected=protected_header, recipient=self.storage.encrypter.key ) legacy_state_data = json.dumps({'data': jwe_token.serialize(compact=True)}) questionnaire_state = QuestionnaireState( user_id, legacy_state_data, QuestionnaireStore.LATEST_VERSION ) data_access.put(questionnaire_state)