Skip to content

Commit 9c64eef

Browse files
Change Graphql Query authz method to QUERY (#72)
* Change Graphql Query auth method to QUERY * Fix tests * Bumpversion to 2.5.0 * Update support to include python 3.14 --------- Co-authored-by: Peter Boers <[email protected]>
1 parent e5d4e8c commit 9c64eef

File tree

7 files changed

+26
-25
lines changed

7 files changed

+26
-25
lines changed

.bumpversion.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[bumpversion]
2-
current_version = 2.4.2
2+
current_version = 2.5.0
33
commit = False
44
tag = False
55
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\-(?P<release>[a-z]+)(?P<build>\d+))?

.github/workflows/test-package.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
runs-on: ubuntu-latest
1313
strategy:
1414
matrix:
15-
python-version: ['3.11', '3.12', '3.13']
15+
python-version: ['3.11', '3.12', '3.13', '3.14']
1616
fail-fast: false
1717
steps:
1818
- uses: actions/checkout@v2

oauth2_lib/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313

1414
"""This is the SURF Oauth2 module that interfaces with the oauth2 setup."""
1515

16-
__version__ = "2.4.2"
16+
__version__ = "2.5.0"

oauth2_lib/fastapi.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ class GraphqlAuthorization(ABC):
260260
"""
261261

262262
@abstractmethod
263-
async def authorize(self, request: RequestPath, user: OIDCUserModel) -> bool | None:
263+
async def authorize(self, request: RequestPath, method: str, user: OIDCUserModel) -> bool | None:
264264
pass
265265

266266

@@ -366,7 +366,7 @@ def __init__(self, opa_url: str, auto_error: bool = False, opa_kwargs: Mapping[s
366366
# By default don't raise HTTP 403 because partial results are preferred
367367
super().__init__(opa_url, auto_error, opa_kwargs)
368368

369-
async def authorize(self, request: RequestPath, user_info: OIDCUserModel) -> bool | None:
369+
async def authorize(self, request: RequestPath, method: str, user_info: OIDCUserModel) -> bool | None:
370370
if not (oauth2lib_settings.OAUTH2_ACTIVE and oauth2lib_settings.OAUTH2_AUTHORIZATION_ACTIVE):
371371
return None
372372

@@ -375,7 +375,7 @@ async def authorize(self, request: RequestPath, user_info: OIDCUserModel) -> boo
375375
**(self.opa_kwargs or {}),
376376
**(user_info or {}),
377377
"resource": request,
378-
"method": "POST",
378+
"method": method,
379379
}
380380
}
381381

oauth2_lib/strawberry.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,14 @@ async def is_authenticated(info: OauthInfo) -> bool:
105105
return current_user is not None
106106

107107

108-
async def is_authorized(info: OauthInfo, path: str) -> bool:
108+
async def is_authorized(info: OauthInfo, path: str, method: str) -> bool:
109109
"""Check that the user is allowed to query/mutate this path."""
110110
context = info.context
111111
current_user = await context.get_current_user
112112
if not current_user:
113113
return False
114114

115-
authorization_decision = await context.auth_manager.graphql_authorization.authorize(path, current_user)
115+
authorization_decision = await context.auth_manager.graphql_authorization.authorize(path, method, current_user)
116116
authorized = bool(authorization_decision)
117117
logger.debug(
118118
"Received graphql authorization decision",
@@ -172,7 +172,7 @@ async def has_permission(self, source: Any, info: OauthInfo, **kwargs) -> bool:
172172
return True
173173

174174
path = get_query_path(info)
175-
if await is_authorized(info, path):
175+
if await is_authorized(info, path, "QUERY"):
176176
return True
177177

178178
self.message = f"User is not authorized to query `{path}`"
@@ -192,7 +192,7 @@ async def has_permission(self, source: Any, info: OauthInfo, **kwargs) -> bool:
192192
return skip_mutation_auth_checks()
193193

194194
path = get_mutation_path(info)
195-
if await is_authorized(info, path):
195+
if await is_authorized(info, path, "POST"):
196196
return True
197197

198198
self.message = f"User is not authorized to execute mutation `{path}`"

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ classifiers = [
2525
"Intended Audience :: Telecommunications Industry",
2626
"License :: OSI Approved :: Apache Software License",
2727
"Programming Language :: Python :: 3 :: Only",
28+
"Programming Language :: Python :: 3.14",
2829
"Programming Language :: Python :: 3.13",
2930
"Programming Language :: Python :: 3.12",
3031
"Programming Language :: Python :: 3.11",
@@ -41,7 +42,7 @@ requires = [
4142
"asyncstdlib",
4243
]
4344
description-file = "README.md"
44-
requires-python = ">=3.11,<3.14"
45+
requires-python = ">=3.11,<3.15"
4546

4647
[tool.flit.metadata.urls]
4748
Documentation = "https://workfloworchestrator.org/"

tests/test_opa_graphql_decision.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
async def test_opa_graphql_decision_auto_error():
1616
oauth2lib_settings.OAUTH2_ACTIVE = False
1717
authorization = GraphQLOPAAuthorization(opa_url="https://opa_url.test")
18-
assert await authorization.authorize("", cast(OIDCUserModel, {})) is None
18+
assert await authorization.authorize("", "QUERY", cast(OIDCUserModel, {})) is None
1919
oauth2lib_settings.OAUTH2_ACTIVE = True
2020

2121

@@ -28,13 +28,13 @@ async def test_opa_graphql_decision_user_not_allowed_autoerror_true(make_mock_as
2828
with patch("oauth2_lib.fastapi.AsyncClient", return_value=mock_async_client):
2929
authorization = GraphQLOPAAuthorization(opa_url="https://opa_url.test", auto_error=True)
3030
with pytest.raises(HTTPException) as exception_info:
31-
await authorization.authorize("/test/path", user_info=user_info_matching)
31+
await authorization.authorize("/test/path", "QUERY", user_info=user_info_matching)
3232

3333
assert exception_info.value.status_code == HTTPStatus.FORBIDDEN
3434
expected_detail = f"User is not allowed to access resource: /test/path Decision was taken with id: {'8ef9daf0-1a23-4a6b-8433-c64ef028bee8'}"
3535
assert exception_info.value.detail == expected_detail
3636

37-
opa_input = {"input": {**user_info_matching, "resource": "/test/path", "method": "POST"}}
37+
opa_input = {"input": {**user_info_matching, "resource": "/test/path", "method": "QUERY"}}
3838
mock_async_client.client.post.assert_called_with("https://opa_url.test", json=opa_input)
3939

4040

@@ -46,14 +46,14 @@ async def test_opa_graphql_decision_user_not_allowed_autoerror_false(make_mock_a
4646

4747
with patch("oauth2_lib.fastapi.AsyncClient", return_value=mock_async_client):
4848
authorization = GraphQLOPAAuthorization(opa_url="https://opa_url.test", auto_error=False)
49-
result = await authorization.authorize("/test/path", user_info_matching)
49+
result = await authorization.authorize("/test/path", "QUERY", user_info_matching)
5050

5151
assert result is False
5252
opa_input = {
5353
"input": {
5454
**user_info_matching,
5555
"resource": "/test/path",
56-
"method": "POST",
56+
"method": "QUERY",
5757
}
5858
}
5959
mock_async_client.client.post.assert_called_with("https://opa_url.test", json=opa_input)
@@ -67,14 +67,14 @@ async def test_opa_graphql_decision_user_allowed(make_mock_async_client):
6767

6868
with patch("oauth2_lib.fastapi.AsyncClient", return_value=mock_async_client):
6969
authorization = GraphQLOPAAuthorization(opa_url="https://opa_url.test", auto_error=False)
70-
result = await authorization.authorize("/test/path", user_info_matching)
70+
result = await authorization.authorize("/test/path", "QUERY", user_info_matching)
7171

7272
assert result is True
7373
opa_input = {
7474
"input": {
7575
**user_info_matching,
7676
"resource": "/test/path",
77-
"method": "POST",
77+
"method": "QUERY",
7878
}
7979
}
8080
mock_async_client.client.post.assert_called_with("https://opa_url.test", json=opa_input)
@@ -88,7 +88,7 @@ async def test_opa_graphql_decision_network_or_type_error(make_mock_async_client
8888
authorization = GraphQLOPAAuthorization(opa_url="https://opa_url.test")
8989

9090
with pytest.raises(HTTPException) as exception:
91-
await authorization.authorize("/test/path", user_info_matching)
91+
await authorization.authorize("/test/path", "QUERY", user_info_matching)
9292

9393
assert exception.value.status_code == 503
9494
assert exception.value.detail == "Policy agent is unavailable"
@@ -105,7 +105,7 @@ async def test_opa_graphql_decision_kwargs(make_mock_async_client):
105105
opa_url="https://opa_url.test", auto_error=False, opa_kwargs={"extra": 3}
106106
)
107107

108-
result = await authorization.authorize("/test/path", user_info_matching)
108+
result = await authorization.authorize("/test/path", "QUERY", user_info_matching)
109109

110110
assert result is True
111111

@@ -114,7 +114,7 @@ async def test_opa_graphql_decision_kwargs(make_mock_async_client):
114114
"extra": 3,
115115
**user_info_matching,
116116
"resource": "/test/path",
117-
"method": "POST",
117+
"method": "QUERY",
118118
}
119119
}
120120
mock_async_client.client.post.assert_called_with("https://opa_url.test", json=opa_input)
@@ -131,15 +131,15 @@ async def test_opa_decision_auto_error_not_allowed(make_mock_async_client):
131131
opa_url="https://opa_url.test", opa_kwargs={"extra": 3}, auto_error=False
132132
)
133133

134-
result = await authorization.authorize("/test/path", user_info_matching)
134+
result = await authorization.authorize("/test/path", "QUERY", user_info_matching)
135135

136136
assert result is False
137137
opa_input = {
138138
"input": {
139139
"extra": 3,
140140
**user_info_matching,
141141
"resource": "/test/path",
142-
"method": "POST",
142+
"method": "QUERY",
143143
}
144144
}
145145
mock_async_client.client.post.assert_called_with("https://opa_url.test", json=opa_input)
@@ -156,15 +156,15 @@ async def test_opa_graphql_decision_auto_error_allowed(make_mock_async_client):
156156
opa_url="https://opa_url.test", opa_kwargs={"extra": 3}, auto_error=False
157157
)
158158

159-
result = await authorization.authorize("/test/path", user_info_matching)
159+
result = await authorization.authorize("/test/path", "QUERY", user_info_matching)
160160

161161
assert result is True
162162
opa_input = {
163163
"input": {
164164
"extra": 3,
165165
**user_info_matching,
166166
"resource": "/test/path",
167-
"method": "POST",
167+
"method": "QUERY",
168168
}
169169
}
170170
mock_async_client.client.post.assert_called_with("https://opa_url.test", json=opa_input)

0 commit comments

Comments
 (0)