diracx-db 0.0.1a11__tar.gz → 0.0.1a12__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/PKG-INFO +1 -1
  2. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx/db/sql/auth/db.py +19 -12
  3. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx/db/sql/auth/schema.py +2 -4
  4. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx_db.egg-info/PKG-INFO +1 -1
  5. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/tests/auth/test_authorization_flow.py +2 -3
  6. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/tests/auth/test_device_flow.py +11 -6
  7. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/README.md +0 -0
  8. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/pyproject.toml +0 -0
  9. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/setup.cfg +0 -0
  10. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx/db/__init__.py +0 -0
  11. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx/db/__main__.py +0 -0
  12. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx/db/exceptions.py +0 -0
  13. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx/db/os/__init__.py +0 -0
  14. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx/db/os/job_parameters.py +0 -0
  15. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx/db/os/utils.py +0 -0
  16. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx/db/py.typed +0 -0
  17. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx/db/sql/__init__.py +0 -0
  18. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx/db/sql/auth/__init__.py +0 -0
  19. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx/db/sql/dummy/__init__.py +0 -0
  20. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx/db/sql/dummy/db.py +0 -0
  21. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx/db/sql/dummy/schema.py +0 -0
  22. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx/db/sql/jobs/__init__.py +0 -0
  23. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx/db/sql/jobs/db.py +0 -0
  24. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx/db/sql/jobs/schema.py +0 -0
  25. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx/db/sql/jobs/status_utility.py +0 -0
  26. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx/db/sql/sandbox_metadata/__init__.py +0 -0
  27. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx/db/sql/sandbox_metadata/db.py +0 -0
  28. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx/db/sql/sandbox_metadata/schema.py +0 -0
  29. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx/db/sql/utils.py +0 -0
  30. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx_db.egg-info/SOURCES.txt +0 -0
  31. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx_db.egg-info/dependency_links.txt +0 -0
  32. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx_db.egg-info/entry_points.txt +0 -0
  33. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx_db.egg-info/requires.txt +0 -0
  34. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/src/diracx_db.egg-info/top_level.txt +0 -0
  35. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/tests/auth/test_refresh_token.py +0 -0
  36. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/tests/jobs/test_jobDB.py +0 -0
  37. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/tests/jobs/test_jobLoggingDB.py +0 -0
  38. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/tests/opensearch/test_connection.py +0 -0
  39. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/tests/opensearch/test_index_template.py +0 -0
  40. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/tests/opensearch/test_search.py +0 -0
  41. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/tests/test_dummyDB.py +0 -0
  42. {diracx-db-0.0.1a11 → diracx-db-0.0.1a12}/tests/test_sandbox_metadata.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: diracx-db
3
- Version: 0.0.1a11
3
+ Version: 0.0.1a12
4
4
  Summary: TODO
5
5
  License: GPL-3.0-only
6
6
  Classifier: Intended Audience :: Science/Research
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import hashlib
3
4
  import secrets
4
5
  from datetime import datetime
5
6
  from uuid import uuid4
@@ -63,7 +64,7 @@ class AuthDB(BaseSQLDB):
63
64
  ),
64
65
  ).with_for_update()
65
66
  stmt = stmt.where(
66
- DeviceFlows.device_code == device_code,
67
+ DeviceFlows.device_code == hashlib.sha256(device_code.encode()).hexdigest(),
67
68
  )
68
69
  res = dict((await self.conn.execute(stmt)).one()._mapping)
69
70
 
@@ -74,7 +75,10 @@ class AuthDB(BaseSQLDB):
74
75
  # Update the status to Done before returning
75
76
  await self.conn.execute(
76
77
  update(DeviceFlows)
77
- .where(DeviceFlows.device_code == device_code)
78
+ .where(
79
+ DeviceFlows.device_code
80
+ == hashlib.sha256(device_code.encode()).hexdigest()
81
+ )
78
82
  .values(status=FlowStatus.DONE)
79
83
  )
80
84
  return res
@@ -110,7 +114,6 @@ class AuthDB(BaseSQLDB):
110
114
  self,
111
115
  client_id: str,
112
116
  scope: str,
113
- audience: str,
114
117
  ) -> tuple[str, str]:
115
118
  # Because the user_code might be short, there is a risk of conflicts
116
119
  # This is why we retry multiple times
@@ -119,14 +122,16 @@ class AuthDB(BaseSQLDB):
119
122
  secrets.choice(USER_CODE_ALPHABET)
120
123
  for _ in range(DeviceFlows.user_code.type.length) # type: ignore
121
124
  )
122
- # user_code = "2QRKPY"
123
125
  device_code = secrets.token_urlsafe()
126
+
127
+ # Hash the the device_code to avoid leaking information
128
+ hashed_device_code = hashlib.sha256(device_code.encode()).hexdigest()
129
+
124
130
  stmt = insert(DeviceFlows).values(
125
131
  client_id=client_id,
126
132
  scope=scope,
127
- audience=audience,
128
133
  user_code=user_code,
129
- device_code=device_code,
134
+ device_code=hashed_device_code,
130
135
  )
131
136
  try:
132
137
  await self.conn.execute(stmt)
@@ -143,7 +148,6 @@ class AuthDB(BaseSQLDB):
143
148
  self,
144
149
  client_id: str,
145
150
  scope: str,
146
- audience: str,
147
151
  code_challenge: str,
148
152
  code_challenge_method: str,
149
153
  redirect_uri: str,
@@ -154,7 +158,6 @@ class AuthDB(BaseSQLDB):
154
158
  uuid=uuid,
155
159
  client_id=client_id,
156
160
  scope=scope,
157
- audience=audience,
158
161
  code_challenge=code_challenge,
159
162
  code_challenge_method=code_challenge_method,
160
163
  redirect_uri=redirect_uri,
@@ -172,7 +175,10 @@ class AuthDB(BaseSQLDB):
172
175
  :raises: AuthorizationError if no such uuid or status not pending
173
176
  """
174
177
 
178
+ # Hash the code to avoid leaking information
175
179
  code = secrets.token_urlsafe()
180
+ hashed_code = hashlib.sha256(code.encode()).hexdigest()
181
+
176
182
  stmt = update(AuthorizationFlows)
177
183
 
178
184
  stmt = stmt.where(
@@ -181,7 +187,7 @@ class AuthDB(BaseSQLDB):
181
187
  AuthorizationFlows.creation_time > substract_date(seconds=max_validity),
182
188
  )
183
189
 
184
- stmt = stmt.values(id_token=id_token, code=code, status=FlowStatus.READY)
190
+ stmt = stmt.values(id_token=id_token, code=hashed_code, status=FlowStatus.READY)
185
191
  res = await self.conn.execute(stmt)
186
192
 
187
193
  if res.rowcount != 1:
@@ -190,15 +196,16 @@ class AuthDB(BaseSQLDB):
190
196
  stmt = select(AuthorizationFlows.code, AuthorizationFlows.redirect_uri)
191
197
  stmt = stmt.where(AuthorizationFlows.uuid == uuid)
192
198
  row = (await self.conn.execute(stmt)).one()
193
- return row.code, row.redirect_uri
199
+ return code, row.redirect_uri
194
200
 
195
201
  async def get_authorization_flow(self, code: str, max_validity: int):
202
+ hashed_code = hashlib.sha256(code.encode()).hexdigest()
196
203
  # The with_for_update
197
204
  # prevents that the token is retrieved
198
205
  # multiple time concurrently
199
206
  stmt = select(AuthorizationFlows).with_for_update()
200
207
  stmt = stmt.where(
201
- AuthorizationFlows.code == code,
208
+ AuthorizationFlows.code == hashed_code,
202
209
  AuthorizationFlows.creation_time > substract_date(seconds=max_validity),
203
210
  )
204
211
 
@@ -208,7 +215,7 @@ class AuthDB(BaseSQLDB):
208
215
  # Update the status to Done before returning
209
216
  await self.conn.execute(
210
217
  update(AuthorizationFlows)
211
- .where(AuthorizationFlows.code == code)
218
+ .where(AuthorizationFlows.code == hashed_code)
212
219
  .values(status=FlowStatus.DONE)
213
220
  )
214
221
 
@@ -45,8 +45,7 @@ class DeviceFlows(Base):
45
45
  creation_time = DateNowColumn()
46
46
  client_id = Column(String(255))
47
47
  scope = Column(String(1024))
48
- audience = Column(String(255))
49
- device_code = Column(String(128), unique=True) # hash it ?
48
+ device_code = Column(String(128), unique=True) # Should be a hash
50
49
  id_token = NullColumn(JSON())
51
50
 
52
51
 
@@ -57,11 +56,10 @@ class AuthorizationFlows(Base):
57
56
  client_id = Column(String(255))
58
57
  creation_time = DateNowColumn()
59
58
  scope = Column(String(1024))
60
- audience = Column(String(255))
61
59
  code_challenge = Column(String(255))
62
60
  code_challenge_method = Column(String(8))
63
61
  redirect_uri = Column(String(255))
64
- code = NullColumn(String(255)) # hash it ?
62
+ code = NullColumn(String(255)) # Should be a hash
65
63
  id_token = NullColumn(JSON())
66
64
 
67
65
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: diracx-db
3
- Version: 0.0.1a11
3
+ Version: 0.0.1a12
4
4
  Summary: TODO
5
5
  License: GPL-3.0-only
6
6
  Classifier: Intended Audience :: Science/Research
@@ -23,7 +23,7 @@ async def test_insert_id_token(auth_db: AuthDB):
23
23
  # First insert
24
24
  async with auth_db as auth_db:
25
25
  uuid = await auth_db.insert_authorization_flow(
26
- "client_id", "scope", "audience", "code_challenge", "S256", "redirect_uri"
26
+ "client_id", "scope", "code_challenge", "S256", "redirect_uri"
27
27
  )
28
28
 
29
29
  id_token = {"sub": "myIdToken"}
@@ -68,12 +68,11 @@ async def test_insert(auth_db: AuthDB):
68
68
  # First insert
69
69
  async with auth_db as auth_db:
70
70
  uuid1 = await auth_db.insert_authorization_flow(
71
- "client_id", "scope", "audience", "code_challenge", "S256", "redirect_uri"
71
+ "client_id", "scope", "code_challenge", "S256", "redirect_uri"
72
72
  )
73
73
  uuid2 = await auth_db.insert_authorization_flow(
74
74
  "client_id2",
75
75
  "scope2",
76
- "audience2",
77
76
  "code_challenge2",
78
77
  "S256",
79
78
  "redirect_uri2",
@@ -28,20 +28,22 @@ async def test_device_user_code_collision(auth_db: AuthDB, monkeypatch):
28
28
  # First insert should work
29
29
  async with auth_db as auth_db:
30
30
  code, device = await auth_db.insert_device_flow(
31
- "client_id", "scope", "audience"
31
+ "client_id",
32
+ "scope",
32
33
  )
33
34
  assert code == "A" * USER_CODE_LENGTH
34
35
  assert device
35
36
 
36
37
  async with auth_db as auth_db:
37
38
  with pytest.raises(NotImplementedError, match="insert new device flow"):
38
- await auth_db.insert_device_flow("client_id", "scope", "audience")
39
+ await auth_db.insert_device_flow("client_id", "scope")
39
40
 
40
41
  monkeypatch.setattr(secrets, "choice", lambda _: "B")
41
42
 
42
43
  async with auth_db as auth_db:
43
44
  code, device = await auth_db.insert_device_flow(
44
- "client_id", "scope", "audience"
45
+ "client_id",
46
+ "scope",
45
47
  )
46
48
  assert code == "B" * USER_CODE_LENGTH
47
49
  assert device
@@ -59,10 +61,12 @@ async def test_device_flow_lookup(auth_db: AuthDB, monkeypatch):
59
61
  # First insert
60
62
  async with auth_db as auth_db:
61
63
  user_code1, device_code1 = await auth_db.insert_device_flow(
62
- "client_id1", "scope1", "audience1"
64
+ "client_id1",
65
+ "scope1",
63
66
  )
64
67
  user_code2, device_code2 = await auth_db.insert_device_flow(
65
- "client_id2", "scope2", "audience2"
68
+ "client_id2",
69
+ "scope2",
66
70
  )
67
71
 
68
72
  assert user_code1 != user_code2
@@ -123,7 +127,8 @@ async def test_device_flow_insert_id_token(auth_db: AuthDB):
123
127
  # First insert
124
128
  async with auth_db as auth_db:
125
129
  user_code, device_code = await auth_db.insert_device_flow(
126
- "client_id", "scope", "audience"
130
+ "client_id",
131
+ "scope",
127
132
  )
128
133
 
129
134
  # Make sure it exists, and is Pending
File without changes
File without changes