Skip to content

Commit 9a32b95

Browse files
committed
apply suggestions from code review
1 parent b88d3df commit 9a32b95

File tree

3 files changed

+79
-39
lines changed

3 files changed

+79
-39
lines changed

CHANGELOG.md

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,92 +3,123 @@
33
Observes [Semantic Versioning](https://semver.org/spec/v2.0.0.html) standard and [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) convention.
44

55
## [0.5.1] - 2022-09-27
6+
67
### Added
8+
79
- Schema templating for insert queries using query params PR #131
10+
- Add support for OIDC login flow PR #130
811

912
## [0.5.0] - 2022-09-21
13+
1014
### Fixed
15+
1116
- Bugs with returning UUID and NaN values PR #128
1217

1318
### Added
19+
1420
- Support schemas with a `-` by specifying instead with `__` in dynamic spec PR #128
1521
- Support for new `antd-table` component. Prior `table` component will be deprecated in the next minor release. PR #128
1622
- Support for InsertComponent
1723

1824
## [0.4.1] - 2022-03-24
25+
1926
### Fixed
27+
2028
- Bug with otumat version not being tied to the latest PR #119
2129

2230
## [0.4.0] - 2022-03-18
31+
2332
### Fixed
33+
2434
- Bug with `order_by` not applying from fetch args PR #117
2535

2636
### Added
37+
2738
- Support for new `slider` and `dropdown-query` components PR #118
2839
- Numpy parser for `component_interface.py` to remove numpy types for json serialization PR #118
2940
- Support for loginless mode PR #118
3041

3142
## [0.3.0] - 2022-01-21
43+
3244
### Changed
45+
3346
- Hot-reload mechanism to use `otumat watch` PR #116
3447
- Renamed environment variable defining spec sheet to `PHARUS_SPEC_PATH` PR #116
3548

3649
### Added
37-
- Autoformatting strategy using `black` PR #116
50+
51+
- Autoformatting strategy using `black` PR #116
3852
- Support for sci-viz components `metadata`, `image`, `dynamic grid` PR #116
3953
- `component interface` for users to be able to load their own custom interface for sci-viz PR #116
4054

4155
### Fixed
56+
4257
- Various bugs related to datetime PR #116
4358

4459
## [0.2.3] - 2021-11-18
60+
4561
### Added
62+
4663
- Support for plot component PR #155
4764
- Fetch argument specification in `dj_query` PR #155
4865

4966
## [0.2.2] - 2021-11-10
67+
5068
### Fixed
69+
5170
- Optimize dynamic api virtual modules. PR #113
5271

5372
## [0.2.1] - 2021-11-08
73+
5474
### Fixed
75+
5576
- Error with retrieving the module's installation root path. PR #112
5677

5778
## [0.2.0] - 2021-11-02
79+
5880
### Added
81+
5982
- Dynamic api generation from spec sheet.(#103, #104, #105, #107, #108, #110) PR #106, #109
6083
- `dynamic_api_gen.py` Python script that generates `dynamic_api.py`.
6184
- Add Tests for the new dynamic api.
6285
- `server.py` now loads the routes generated dynamically from `dynamic_api.py` when it is present.
6386

6487
## [0.1.0] - 2021-03-31
88+
6589
### Added
90+
6691
- Local database instance pre-populated with sample data for `dev` Docker Compose environment. PR #99
6792
- Capability to insert multiple, update multiple, and delete multiple. PR #99
6893
- Allow dependency restriction to include secondary attributes from parent table. PR #99
6994

7095
### Changed
96+
7197
- Update `datajoint` to newly released `0.13.0`. PR #97
7298
- Rename service `pharus` to `pharus-docs` in `docs` Docker Compose environment to allow simulataneous development. PR #99
7399
- Update NGINX reverse proxy image reference. PR #99
74100
- Refactored API design to align with common REST resource naming convention. (#38) PR #99
75101
- Hide classes and methods that are internal and subject to change. PR #99
76102

77103
### Removed
104+
78105
- `InvalidDeleteRequest` exception is no longer available as it is now allowed to delete more than 1 record at a time. PR #99
79106

80107
### Fixed
108+
81109
- `uuid` types not properly restricted on `GET /record`, `DELETE /record`, and `GET /dependency`. PR #102
82110

83111
## [0.1.0b2] - 2021-03-12
84112

85113
### Fixed
114+
86115
- Fixed behavior where using list_table with a nonexistent schema_name creates it instead of returning an error message (#65) PR #63
87116

88117
### Changed
118+
89119
- Contribution policy to follow directly the general DataJoint Contribution Guideline. (#91) PR #94, #95
90120

91121
### Added
122+
92123
- Issue templates for bug reports and enhancement requests. PR #94, #95
93124
- Docker environment for documentation build. (#92) PR #94, #95
94125
- Add Sphinx-based documentation source and fix parsing issues. (#92) PR #94, #95
@@ -97,29 +128,36 @@ Observes [Semantic Versioning](https://semver.org/spec/v2.0.0.html) standard and
97128
## [0.1.0b0] - 2021-02-26
98129

99130
### Security
131+
100132
- Documentation with detail regarding warning on bearer token. (#83) PR #88
101133

102134
### Fixed
135+
103136
- Incorrect virtual module reference of `schema_virtual_module` in table metadata. (#85) PR #88
104137

105138
### Added
139+
106140
- Docker `dev` environment that supports hot reloading. PR #79
107141
- Documentation on setting up environments within `docker-compose` header. PR #79
108142
- `cascade` option for `/delete_tuple` route. (#86) PR #88
109143
- When delete with `cascade=False` fails due to foreign key relations, returns a HTTP error code of `409 Conflict` with a JSON body containing specifics of 1st child. (#86) PR #88
110144

111145
### Changed
146+
112147
- Replaced `DJConnector.snake_to_camel_case` usage with `datajoint.utils.to_camel_case`. PR #88
113148
- Default behavior for `/delete_tuple` now deletes without cascading. (#86) PR #88
114149
- Consolidated `pytest` fixtures into `__init__.py` to facilitate reuse. PR #88
115150
- Modify dependency check to not perform deep check and use accessible fk relations only. (#89) PR #90
116151
- Update nginx image to pull from datajoint organization. (#80) PR #90
117152

118153
### Removed
154+
119155
- Docker `base` environment to simplify dependencies. PR #79
120156

121157
## [0.1.0a5] - 2021-02-18
158+
122159
### Added
160+
123161
- List schemas method.
124162
- List tables method.
125163
- Data entry, update, delete, and view operations for DataJoint table tiers: `dj.Manual`, `dj.Lookup`.
@@ -138,4 +176,4 @@ Observes [Semantic Versioning](https://semver.org/spec/v2.0.0.html) standard and
138176
[0.1.0]: https://github.com/datajoint/pharus/compare/0.1.0b2...0.1.0
139177
[0.1.0b2]: https://github.com/datajoint/pharus/compare/0.1.0b0...0.1.0b2
140178
[0.1.0b0]: https://github.com/datajoint/pharus/compare/0.1.0a5...0.1.0b0
141-
[0.1.0a5]: https://github.com/datajoint/pharus/releases/tag/0.1.0a5
179+
[0.1.0a5]: https://github.com/datajoint/pharus/releases/tag/0.1.0a5

pharus/interface.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,21 @@ class _DJConnector:
1616
"""Primary connector that communicates with a DataJoint database server."""
1717

1818
@staticmethod
19-
def _attempt_login(database_address: str, username: str, password: str):
19+
def _attempt_login(databaseAddress: str, username: str, password: str):
2020
"""
2121
Attempts to authenticate against database with given username and address.
2222
23-
:param database_address: Address of database
24-
:type database_address: str
23+
:param databaseAddress: Address of database
24+
:type databaseAddress: str
2525
:param username: Username of user
2626
:type username: str
2727
:param password: Password of user
2828
:type password: str
2929
"""
30-
dj.config["database.host"] = database_address
30+
dj.config["database.host"] = databaseAddress
3131
dj.config["database.user"] = username
3232
dj.config["database.password"] = password
33-
33+
print(dj.config, flush=True)
3434
# Attempt to connect return true if successful, false is failed
3535
dj.conn(reset=True)
3636

pharus/server.py

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from typing import Callable
66
from functools import wraps
77
from typing import Union
8+
import traceback
89

910
# Crypto libaries
1011
from cryptography.hazmat.primitives import serialization as crypto_serialization
@@ -62,16 +63,19 @@ def protected_route(function: Callable) -> Callable:
6263
def wrapper(**kwargs):
6364
try:
6465
if "database_host" in request.args:
65-
jwt_payload = jwt.decode(
66-
request.headers.get("Authorization").split()[1],
67-
environ["PHARUS_OIDC_PUBLIC_KEY"],
68-
algorithms="RS256",
69-
)
70-
connect_creds = dict(
71-
databaseAddress=request.args["database_host"],
72-
username=jwt_payload[environ.get("PHARUS_OIDC_SUBJECT_KEY")],
73-
password=request.headers.get("Authorization").split()[1],
74-
)
66+
encoded_jwt = request.headers.get("Authorization").split()[1]
67+
connect_creds = {
68+
"databaseAddress": request.args["database_host"],
69+
"username": jwt.decode(
70+
encoded_jwt,
71+
crypto_serialization.load_der_public_key(
72+
b64decode(environ.get("PHARUS_OIDC_PUBLIC_KEY").encode())
73+
),
74+
algorithms="RS256",
75+
options=dict(verify_aud=False),
76+
)[environ.get("PHARUS_OIDC_SUBJECT_KEY")],
77+
"password": encoded_jwt,
78+
}
7579
else:
7680
connect_creds = jwt.decode(
7781
request.headers.get("Authorization").split()[1],
@@ -80,7 +84,7 @@ def wrapper(**kwargs):
8084
)
8185
return function(connect_creds, **kwargs)
8286
except Exception as e:
83-
return str(e), 401
87+
return traceback.format_exc(), 401
8488

8589
wrapper.__name__ = function.__name__
8690
return wrapper
@@ -195,13 +199,6 @@ def login() -> dict:
195199
:statuscode 500: Unexpected error encountered. Returns the error message as a string.
196200
"""
197201
if request.method == "POST":
198-
# Check if request has the correct fields
199-
# if ( "database_host" not in request.headers and
200-
# not request.json.keys() >= {"databaseAddress", "username", "password"}
201-
202-
# ):
203-
# return dict(error="Invalid Request, check headers and/or json body")
204-
205202
# Try to login in with the database connection info, if true then create jwt key
206203
try:
207204
if "database_host" in request.args:
@@ -227,26 +224,31 @@ def login() -> dict:
227224
headers=headers,
228225
auth=auth,
229226
)
230-
access_token = result.json()["access_token"]
231-
_DJConnector._attempt_login(
232-
request.args["database_host"],
233-
jwt.decode(access_token, environ.get("PHARUS_OIDC_PUBLIC_KEY")),
234-
access_token,
235-
)
236-
return dict(jwt=access_token)
227+
encoded_jwt = result.json()["access_token"]
228+
connect_creds = {
229+
"databaseAddress": request.args["database_host"],
230+
"username": jwt.decode(
231+
encoded_jwt,
232+
crypto_serialization.load_der_public_key(
233+
b64decode(environ.get("PHARUS_OIDC_PUBLIC_KEY").encode())
234+
),
235+
algorithms="RS256",
236+
options=dict(verify_aud=False),
237+
)[environ.get("PHARUS_OIDC_SUBJECT_KEY")],
238+
"password": encoded_jwt,
239+
}
237240
else: # Database login
238-
_DJConnector._attempt_login(
239-
request.json["databaseAddress"],
240-
request.json["username"],
241-
request.json["password"],
242-
)
243241
# Generate JWT key and send it back
244242
encoded_jwt = jwt.encode(
245243
request.json, environ["PHARUS_PRIVATE_KEY"], algorithm="RS256"
246244
)
247-
return dict(jwt=encoded_jwt)
245+
connect_creds = request.json
246+
if connect_creds.keys() < {"databaseAddress", "username", "password"}:
247+
return dict(error="Invalid Request, check headers and/or json body")
248+
_DJConnector._attempt_login(**connect_creds)
249+
return dict(jwt=encoded_jwt)
248250
except Exception as e:
249-
return str(e), 500
251+
return traceback.format_exc(), 500
250252

251253

252254
@app.route(f"{environ.get('PHARUS_PREFIX', '')}/schema", methods=["GET"])

0 commit comments

Comments
 (0)