예제 #1
0
    def test_dictionary_setnone_deletekey(self):
        '''This test case ensures that None values set on non immutable objects trigger a delete of the specified key.'''

        desc = {"attr1": "test", "attr2": "value"}

        obj = DictionaryObject(desc, immutable=False)

        obj.attr1 = None

        self.assertFalse("attr1" in desc)
    def test_hash_nocontext(self):
        '''This test case ensures an exception is raised if no hash context is given or if the context does not contain salt
        entry.'''

        for hash_ctx in [None, {}, {"unknown_attr": "sample value"}]:
            passwd = self._hasher.hash_password("123",
                                                DictionaryObject(hash_ctx))
            self.assertEqual(
                passwd,
                self._hasher.hash_password("123",
                                           DictionaryObject({"salt": 9999})))
예제 #3
0
    def test_dictionary_setnone_deletekey(self):
        '''This test case ensures that None values set on non immutable objects trigger a delete of the specified key.'''

        desc = {"attr1": "test",
                "attr2": "value"}

        obj = DictionaryObject(desc, immutable=False)

        obj.attr1 = None

        self.assertFalse("attr1" in desc)
예제 #4
0
    def test_format_resource_none_ok(self):
        '''This test case ensures validation works correctly even when resource does not contain keys.'''

        desc = {}
        resource = DictionaryObject(desc, immutable=False)

        self._validator.format_resource(resource, None)

        self.assertEqual(desc, {})
    def test_hash_none(self):
        '''This test case ensures that a hash is generated for empty or null passwords.'''

        hash_ctx = DictionaryObject({"salt": 123})
        expected_result = "M2M5OTA5YWZlYzI1MzU0ZDU1MWRhZTIxNTkwYmIyNmUzOGQ1M2YyMTczYjhkM2RjM2VlZTRjMDQ3ZTdhYjFjMWViOGI4NTEwM2UzYmU3YmE2MTNiMzFiYjVjOWMzNjIxNGRjOWYxNGE0MmZkN2EyZmRiODQ4NTZiY2E1YzQ0YzI="

        for plain_passwd in [None, "", "     "]:
            result = self._hasher.hash_password(plain_passwd, hash_ctx)

            self.assertEqual(expected_result, result)
    def test_hash_ok(self):
        '''This test case ensures a base64 encoded hash is return correctly by password hasher.'''

        plain_passwd = "abc123test"
        hash_ctx = DictionaryObject({"salt": 123})
        expected_result = "MzYxZTA5NTk2ZmVjNzZlMzc0MGZiY2I1YTc3NGM2YjM4OTBkMDFlNDEwYzQ5ZDdkNzAwM2IyNWJkZTUxOWE4MTAyMDM5Mzg1YTI4NDA0MmUxODNlN2JhMmNlZmM3NzU0NDQ2MTk5ZjhkYjQzZWEwMDE3MzhmODJmNDBmZWExM2M="

        result = self._hasher.hash_password(plain_passwd, hash_ctx)

        self.assertEqual(expected_result, result)
예제 #7
0
    def test_dictionary_notimmutable(self):
        '''This test case ensures a dictionary object can be built so that his attributes and underlining dictionaries can be
        changed at runtime.'''

        new_attr2 = "abc_altered"

        desc = {"attr1": "abcd", "attr2": "abc"}

        obj = DictionaryObject(desc, immutable=False)

        self.assertEqual(desc["attr1"], obj.attr1)
        self.assertEqual(desc["attr2"], obj.attr2)

        obj.attr2 = new_attr2
        obj.new_attr2 = new_attr2

        self.assertEqual(new_attr2, desc["attr2"])
        self.assertEqual(new_attr2, obj.attr2)
        self.assertEqual(new_attr2, obj.new_attr2)
예제 #8
0
    def test_format_resource_ok(self):
        '''This test case ensures format_resource works correctly for an expected resource.'''

        desc = {"username": "******", "password": "******"}
        resource = DictionaryObject(desc, immutable=False)

        self._validator.format_resource(resource, None)

        self.assertEqual(desc["username"], resource.username)
        self.assertTrue("password" not in desc)
예제 #9
0
    def test_dictionary_notimmutable(self):
        '''This test case ensures a dictionary object can be built so that his attributes and underlining dictionaries can be
        changed at runtime.'''

        new_attr2 = "abc_altered"

        desc = {"attr1": "abcd",
                "attr2": "abc"}

        obj = DictionaryObject(desc, immutable=False)

        self.assertEqual(desc["attr1"], obj.attr1)
        self.assertEqual(desc["attr2"], obj.attr2)

        obj.attr2 = new_attr2
        obj.new_attr2 = new_attr2

        self.assertEqual(new_attr2, desc["attr2"])
        self.assertEqual(new_attr2, obj.attr2)
        self.assertEqual(new_attr2, obj.new_attr2)
예제 #10
0
    def format_collection(self, resources, request):  # pylint: disable=W0613
        '''This method must be overriden by each subclass in order to provide custom logic which must be executed after
        a collection is fetched from database. By default, this method simply iterates over the list of available resources and
        invoke format_resource.

        Usually you will want to override this method in order to suppress sensitive data to be sent to clients.'''

        resources = resources or []

        for resource in resources:
            self.format_resource(DictionaryObject(resource, immutable=False),
                                 request)
    def hash_password(self, plain_passwd, hash_ctx=None):
        '''This method provides the sha512 with salt algorithm for a given plain password. In addition, the hash is base64
        encoded.'''

        if not hash_ctx or not hash_ctx.dictionary.get("salt"):
            hash_ctx = DictionaryObject({"salt": self._DEFAULT_SALT})

        plain_passwd = (plain_passwd or "").strip()

        salt = hash_ctx.salt

        text = (plain_passwd + str(salt)).encode()

        hashed_text = hashlib.sha512(text).hexdigest()

        return base64.b64encode(hashed_text.encode()).decode()
예제 #12
0
    def _test_authenticate_ok(self, return_url, expected_url):
        '''This method provides a template test case for ensuring authenticate succeeds for various return_url values.'''

        user = User(username="******",
                    password="******",
                    person_id=1)
        user.user_id = 123

        creation_time, expiration_time = self._mock_creationexpiration_time()

        token = Token({
            "client_id": self._IDP_CLIENTID,
            "type": "login",
            "user_id": user.user_id,
            "creation_time": creation_time,
            "expiration_time": expiration_time
        })

        request, user_repo_cls, user_repo, tokens_service_cls, \
            tokens_service, clienturl_facade = self._mock_authenticate_dependencies(token, user, return_url)

        response = self._idp_controller.authenticate(
            request,
            tokens_service_cls=tokens_service_cls,
            user_repo_cls=user_repo_cls)

        self.assertIsNotNone(response)
        self.assertEqual(302, response.status_code)

        location = response.headers.get("Location")

        self.assertEqual(expected_url, location)

        user_repo.load_by_username.assert_called_once_with(user.username)
        self._hasher.hash_password.assert_called_once_with(
            user.password, DictionaryObject({"salt": user.user_id}))

        tokens_service_cls.assert_called_once_with(clienturl_facade.session)
        tokens_service.generate.assert_called_once_with(
            {
                "client_id": self._IDP_CLIENTID,
                "user_id": user.user_id,
                "expires_in": self._EXPIRES_IN
            }, TokenGeneratorFactory.LOGIN_TOKEN)
        tokens_service.encrypt.assert_called_once_with(token, token.client_id)
예제 #13
0
    def _validate_user(self, username, password, user_repo):
        '''This method validates the given username and password against the record found in database. If no user is found or
        password does not match an exception is raised.'''

        user = user_repo.load_by_username(username)
        if not user:
            raise OAuth2AuthenticationError("Username or password do not match.")

        password_hash = self._passwords_hasher.hash_password(password, DictionaryObject({"salt": user.user_id}))

        if password_hash != user.password:
            # when the account is created for the first time there is no user_id available so a default salt is used.
            password_hash_default = self._passwords_hasher.hash_password(password)

            if password_hash_default != user.password:
                raise OAuth2AuthenticationError("Username or password do not match.")

        return user
예제 #14
0
    def _test_validate_user_template(self, resource, request):
        '''This method provides a template for validate user test cases.'''

        request.request_id = 9876

        default_person = Person(first_name="-",
                                last_name="-",
                                email_address=resource.username)
        person_id = 1

        plain_passwd = resource.password
        user_id = resource.user_id

        hashed_passwd = "123"

        self._hasher.hash_password = Mock(return_value=hashed_passwd)

        if request.method.lower() == "post":
            self._person_facade.new_model = Mock(return_value=default_person)
            self._person_facade.create = Mock(return_value=[person_id])

        self._validator.validate(resource, request)

        self.assertEqual(hashed_passwd, resource.password)
        self._hasher.hash_password.assert_called_once_with(
            plain_passwd, DictionaryObject({"salt": user_id}))

        if request.method.lower() == "post":
            self.assertEqual(person_id, resource.person_id)

            self._model_facade_cls.assert_called_once_with(
                Person, self._db_conn)
            self._conn_manager.get_connection.assert_called_once_with(
                request.request_id)
            self._person_facade.new_model.assert_called_once_with(
                first_name="-", last_name="-", email_address=resource.username)
            self._person_facade.create.assert_called_once_with(default_person)
예제 #15
0
    def _hash_password(self, resource):
        '''This method hashes the password from the given resource.'''

        hash_ctx = {"salt": resource.user_id}
        resource.password = self._passwd_hasher.hash_password(resource.password, DictionaryObject(hash_ctx))
예제 #16
0
    def get_item(self, request, version, resource_url, resource_id):
        '''This method provides the API for retrieving a single item from a collection. The item is uniquely identified by
        resource_id. Below you can find a success response example:

        .. code-block:: html

            GET - /api/1.0/simple-resources/1 HTTP/1.1

            200 OK
            Content-Type: application/json
            Content-Length: ...

            {
                "id": 1,
                "name": "Test resource",
                "description": "Simple description"
            }

        Of course there are cases when exceptions might occur. Below, you can find a list of error response retrieved from
        get_item API:

            * **10000** - Whenever we try to retrieve a resource with unknown type. (Not registered to ROA).
            * **10030** - Whenever we try to retrieve a resource and an unexpected database exception occurs.
            * **10040** - Whenever we try to retrieve a resource which does not exist.
        '''

        if version != "latest":
            version = float(version)

        fields = request.params.get("fields")

        resource = self._resources_registry.find_by_url(resource_url, version)

        if not resource:
            return self._handle_resource_notfound(version, resource_url)

        self._inject_security_context(request, resource.model)
        access_token = self.validate_security_context(request, "read")

        model_facade = self._model_facade_cls(
            resource.model, self._get_current_connection(request))

        try:
            model = model_facade.find_by_pk(
                {model_facade.model_pk_cols[0]: resource_id})

            if not self._is_model_owned_by(model, access_token, resource):
                model = None
        except FantasticoDbError as dbex:
            return self._handle_resource_dberror(version, resource_url, dbex)

        if not model:
            return self._handle_resource_item_notfound(version, resource_url,
                                                       resource_id)

        json_serializer = self._json_serializer_cls(resource)

        resource_body = json_serializer.serialize(model, fields)

        if resource.validator and model:
            resource.validator().format_resource(
                DictionaryObject(resource_body, immutable=False), request)

        resource_body = json.dumps(resource_body)

        response = Response(body=resource_body.encode(),
                            content_type="application/json",
                            status_code=200)
        self._add_cors_headers(response)

        return response