示例#1
0
    def test_login_required_decorator_with_valid_token(self):
        """Tests the login required decorator called with valid token"""
        type_definitions = ariadne.gql("""
            type Query {
                test: String!
            }
        """)

        query_type = ariadne.QueryType()

        def resolve_test(_, info):
            request = info.context
            self.assertTrue(hasattr(request, "user"))
            self.assertEqual(request.user, self.user)

            return "Test!"

        resolve_test = Mock(wraps=resolve_test)
        decorated_resolve_test = Mock(wraps=login_required(resolve_test))
        query_type.set_field("test", decorated_resolve_test)

        schema = ariadne.make_executable_schema([type_definitions],
                                                [query_type])

        middleware = [JSONWebTokenMiddleware()]

        token = JSONWebTokenBackend().create(self.user)

        request = HttpRequest()
        request.META[HTTP_AUTHORIZATION_HEADER] = f"Token {token}"

        settings = {
            "AUTHENTICATION_BACKENDS": (
                "django_ariadne_jwt.backends.JSONWebTokenBackend",
                "django.contrib.auth.backends.ModelBackend",
            )
        }

        with self.settings(**settings):
            ariadne.graphql_sync(
                schema,
                {
                    "query":
                    """
                    query {
                        test
                    }
                    """
                },
                context_value=request,
                middleware=middleware,
            )

            self.assertTrue(resolve_test.called)
示例#2
0
    async def dummy_client(self, ):
        """
        Client for a dummy server
        """
        type_defs = ariadne.gql("""
            scalar JSON

            type Query {
                headers: JSON
                hello: String
                value_error_required: String!
                value_error: String
                type_error: String
                unauthenticated_error: String
                unauthorized_error: String
            }

            """)
        query = ariadne.QueryType()

        @query.field("hello")
        def hello(parent: Any, info: GraphQLResolveInfo):
            return "👋"

        @query.field("value_error")
        @query.field("value_error_required")
        def value_error(parent: Any, info: GraphQLResolveInfo):
            raise ValueError("this is a value error")

        @query.field("type_error")
        def type_error(parent: Any, info: GraphQLResolveInfo):
            raise TypeError("this is a type error")

        @query.field("unauthenticated_error")
        def unauthenticated_error(parent: Any, info: GraphQLResolveInfo):
            raise Unauthenticated("this is an unauthenticated error")

        @query.field("unauthorized_error")
        def unauthorized_error(parent: Any, info: GraphQLResolveInfo):
            raise Unauthorized("this is an unauthorized error")

        schema = make_executable_schema(type_defs, query)
        app = Starlette()
        app.mount("/", GraphQL(schema))
        async with httpx.Client(app=app,
                                base_url="http://prefect.io") as dummy_client:
            yield dummy_client
        uuid_input(uuid: UUID): String!
        uuid_output: UUID!
    }

    type Mutation {
        hello_mutation(input: InputType): JSON!
    }

    input InputType {
        u: UUID!
        j: JSON!
    }
    """)

query = ariadne.QueryType()
mutation = ariadne.MutationType()


@query.field("json_input")
def json_input_resolver(parent: Any, info: GraphQLResolveInfo, json):
    return json["x"]


@query.field("json_output")
def json_output_resolver(parent: Any, info: GraphQLResolveInfo):
    return {"x": [1, 2]}


@query.field("datetime_input")
def datetime_input_resolver(parent: Any, info: GraphQLResolveInfo, dt):
示例#4
0
    def test_login_required_decorator_without_valid_token(self):
        """Tests the login required decorator called without valid token"""
        type_definitions = ariadne.gql("""
            type Query {
                me: String!
                mustfail: String!
            }
        """)

        query_type = ariadne.QueryType()

        resolve_me = Mock(return_value="Me!")
        query_type.set_field("me", resolve_me)

        resolve_mustfail = Mock(return_value="FAIL!")
        decorated_resolve_mustfail = Mock(
            wraps=login_required(resolve_mustfail))
        query_type.set_field("mustfail", decorated_resolve_mustfail)

        schema = ariadne.make_executable_schema([type_definitions],
                                                [query_type])

        middleware = [JSONWebTokenMiddleware()]

        request = HttpRequest()

        settings = {
            "AUTHENTICATION_BACKENDS": (
                "django_ariadne_jwt.backends.JSONWebTokenBackend",
                "django.contrib.auth.backends.ModelBackend",
            )
        }

        with self.settings(**settings):
            success, result = ariadne.graphql_sync(
                schema,
                {
                    "query":
                    """
                    query {
                        me
                        mustfail
                    }
                    """
                },
                context_value=request,
                middleware=middleware,
            )

            self.assertTrue(resolve_me.called)
            self.assertFalse(resolve_mustfail.called)

            self.assertIsNotNone(result)
            self.assertIn("errors", result)

            test_field_error_found = False

            for error_data in result["errors"]:
                if "mustfail" in error_data["path"]:
                    test_field_error_found = True

            self.assertTrue(test_field_error_found)
示例#5
0
    def __init__(self):
        """
        The schema generator generates a GraphQL schema.
        The purpose is to provide a schema to which resolvers are then
        attached, which is then given to Ariadne, and for resolvers to
        have information about expected types.

        For RPSL queries and types, this is dynamically generated based on
        the RPSL objects from irrd.rpsl. Other parts are fixed.
        This means that the schema is always the same for a given IRRd
        codebase - there are no runtime or user configurable parts.

        Along with generating the schema, some metadata is saved, e.g.
        self.graphql_types which allows resolvers to learn the GraphQL
        type for a certain field.

        This generator also creates Ariadne object types on self, which
        are used to attach resolvers to them.
        """
        self._set_rpsl_query_fields()
        self._set_rpsl_object_interface_schema()
        self._set_rpsl_contact_schema()
        self._set_rpsl_object_schemas()
        self._set_enums()

        schema = self.enums
        schema += """
            scalar ASN
            scalar IP

            schema {
              query: Query
            }

            type Query {
              rpslObjects(""" + self.rpsl_query_fields + """): [RPSLObject!]
              databaseStatus(sources: [String!]): [DatabaseStatus]
              asnPrefixes(asns: [ASN!]!, ipVersion: Int, sources: [String!]): [ASNPrefixes!]
              asSetPrefixes(setNames: [String!]!, ipVersion: Int, sources: [String!], excludeSets: [String!], sqlTrace: Boolean): [AsSetPrefixes!]
              recursiveSetMembers(setNames: [String!]!, depth: Int, sources: [String!], excludeSets: [String!], sqlTrace: Boolean): [SetMembers!]
            }

            type DatabaseStatus {
                source: String!
                authoritative: Boolean!
                objectClassFilter: [String!]
                rpkiRovFilter: Boolean!
                scopefilterEnabled: Boolean!
                localJournalKept: Boolean!
                serialOldestJournal: Int
                serialNewestJournal: Int
                serialLastExport: Int
                serialNewestMirror: Int
                lastUpdate: String
                synchronisedSerials: Boolean!
            }

            type RPSLJournalEntry {
                rpslPk: String!
                source: String!
                serialNrtm: Int!
                operation: String!
                origin: String
                objectClass: String!
                objectText: String!
                timestamp: String!
            }

            type ASNPrefixes {
                asn: ASN!
                prefixes: [IP!]
            }

            type AsSetPrefixes {
                rpslPk: String!
                prefixes: [IP!]
            }

            type SetMembers {
                rpslPk: String!
                rootSource: String!
                members: [String!]
            }
        """
        schema += self.rpsl_object_interface_schema
        schema += self.rpsl_contact_schema
        schema += ''.join(self.rpsl_object_schemas.values())
        schema += 'union RPSLContactUnion = RPSLPerson | RPSLRole'

        self.type_defs = ariadne.gql(schema)

        self.query_type = ariadne.QueryType()
        self.rpsl_object_type = ariadne.InterfaceType("RPSLObject")
        self.rpsl_contact_union_type = ariadne.UnionType("RPSLContactUnion")
        self.asn_scalar_type = ariadne.ScalarType("ASN")
        self.ip_scalar_type = ariadne.ScalarType("IP")
        self.object_types = [
            self.query_type, self.rpsl_object_type,
            self.rpsl_contact_union_type, self.asn_scalar_type,
            self.ip_scalar_type
        ]

        for name in self.rpsl_object_schemas.keys():
            self.object_types.append(ariadne.ObjectType(name))

        self.object_types.append(ariadne.ObjectType("ASNPrefixes"))
        self.object_types.append(ariadne.ObjectType("AsSetPrefixes"))
        self.object_types.append(ariadne.ObjectType("SetMembers"))
        self.object_types.append(ariadne.EnumType("RPKIStatus", RPKIStatus))
        self.object_types.append(
            ariadne.EnumType("ScopeFilterStatus", ScopeFilterStatus))
    def tests_regular_requests(self):
        # fmt: off
        """Tests that the middleware is being called correctly on """ \
            """regular requests"""
        # fmt: on

        type_definitions = ariadne.gql(
            """
            type Query {
                test: String!
            }
        """
        )

        query_type = ariadne.QueryType()

        def resolve_test(_, info):
            request = info.context
            self.assertTrue(hasattr(request, "user"))
            self.assertEqual(request.user, self.user)

            return "Test!"

        resolve_test = Mock(wraps=resolve_test)
        query_type.set_field("test", resolve_test)

        schema = ariadne.make_executable_schema(
            [type_definitions], [query_type]
        )

        middleware = JSONWebTokenMiddleware()

        token = create_jwt(self.user)

        request = HttpRequest()
        request.META[HTTP_AUTHORIZATION_HEADER] = f"Token {token}"

        settings = {
            "AUTHENTICATION_BACKENDS": (
                "django_ariadne_jwt.backends.JSONWebTokenBackend",
                "django.contrib.auth.backends.ModelBackend",
            )
        }

        with self.settings(**settings):
            # Spies on the JSONWebTokenMiddleware.resolve method
            def spy(*args, **kwargs):
                return JSONWebTokenMiddleware.resolve(
                    middleware, *args, **kwargs
                )

            spy = Mock(wraps=spy)

            with patch.object(middleware, "resolve", new=spy):
                ariadne.graphql_sync(
                    schema,
                    {
                        "query": """
                        query {
                            test
                        }
                        """
                    },
                    context_value=request,
                    middleware=[middleware],
                )

                self.assertTrue(spy.called)
                self.assertTrue(resolve_test.called)