Skip to content

Commit 74e6fb7

Browse files
npalaskaportante
authored andcommitted
Remove Auth class definition entirely
Converted to a series of module methods and properties.
1 parent e78c8ef commit 74e6fb7

File tree

9 files changed

+167
-168
lines changed

9 files changed

+167
-168
lines changed

lib/pbench/server/api/resources/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from sqlalchemy.orm.query import Query
1414

1515
from pbench.server import JSON, JSONOBJECT, JSONVALUE, OperationCode, PbenchServerConfig
16-
from pbench.server.auth.auth import Auth
16+
import pbench.server.auth.auth as Auth
1717
from pbench.server.database.models.audit import (
1818
Audit,
1919
AuditReason,
@@ -1470,7 +1470,7 @@ def _get_dataset_metadata(
14701470
native_key = Metadata.get_native_key(i)
14711471
user_id = None
14721472
if native_key == Metadata.USER:
1473-
user_id = Auth.get_user_id()
1473+
user_id = Auth.get_current_user_id()
14741474
try:
14751475
metadata[i] = Metadata.getvalue(
14761476
dataset=dataset, key=i, user_id=user_id

lib/pbench/server/api/resources/datasets_metadata.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
ParamType,
1919
Schema,
2020
)
21-
from pbench.server.auth.auth import Auth
21+
import pbench.server.auth.auth as Auth
2222
from pbench.server.database.models.audit import AuditType
2323
from pbench.server.database.models.datasets import (
2424
Metadata,
@@ -191,7 +191,7 @@ def _put(
191191
native_key = Metadata.get_native_key(k)
192192
user_id = None
193193
if native_key == Metadata.USER:
194-
user_id = Auth.get_user_id()
194+
user_id = Auth.get_current_user_id()
195195
try:
196196
Metadata.setvalue(key=k, value=v, dataset=dataset, user_id=user_id)
197197
except MetadataError as e:

lib/pbench/server/api/resources/query_apis/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
SchemaError,
2929
UnauthorizedAccess,
3030
)
31-
from pbench.server.auth.auth import Auth
31+
import pbench.server.auth.auth as Auth
3232
from pbench.server.database.models.audit import AuditReason, AuditStatus
3333
from pbench.server.database.models.datasets import Dataset, Metadata
3434
from pbench.server.database.models.template import Template

lib/pbench/server/api/resources/upload_api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import humanize
1212

1313
from pbench.common.utils import Cleanup, validate_hostname
14-
from pbench.server.auth.auth import Auth
14+
import pbench.server.auth.auth as Auth
1515
from pbench.server.cache_manager import CacheManager
1616
from pbench.server.database.models.audit import (
1717
Audit,

lib/pbench/server/api/resources/users_api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import jwt
1010
from sqlalchemy.exc import IntegrityError, SQLAlchemyError
1111

12-
from pbench.server.auth.auth import Auth
12+
import pbench.server.auth.auth as Auth
1313
from pbench.server.database.models.active_tokens import ActiveTokens
1414
from pbench.server.database.models.server_config import ServerConfig
1515
from pbench.server.database.models.users import User

lib/pbench/server/auth/auth.py

Lines changed: 157 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -12,169 +12,168 @@
1212
from pbench.server.database.models.active_tokens import ActiveTokens
1313
from pbench.server.database.models.users import User
1414

15-
16-
class Auth:
17-
token_auth = HTTPTokenAuth("Bearer")
18-
secret_key = ""
19-
20-
@staticmethod
21-
def get_user_id() -> Optional[str]:
22-
"""
23-
Returns the user id of the current authenticated user.
24-
If the user not authenticated this would return None
25-
"""
26-
user_id = None
27-
user = Auth.token_auth.current_user()
28-
if user:
29-
user_id = str(user.id)
30-
return user_id
31-
32-
@staticmethod
33-
def _get_secret_key():
34-
if not Auth.secret_key:
35-
Auth.secret_key = os.getenv("SECRET_KEY", "my_precious")
36-
return Auth.secret_key
37-
38-
@staticmethod
39-
def encode_auth_token(time_delta: datetime.timedelta, user_id: int) -> str:
40-
"""
41-
Generates the Auth Token
42-
Args:
43-
time_delta: Token lifetime
44-
user_id: Authorized user's internal ID
45-
Returns:
46-
JWT token string
47-
"""
48-
current_utc = datetime.datetime.now(datetime.timezone.utc)
49-
payload = {
50-
"iat": current_utc,
51-
"exp": current_utc + time_delta,
52-
"sub": user_id,
53-
}
54-
55-
# Get jwt key
56-
jwt_key = Auth._get_secret_key()
57-
return jwt.encode(payload, jwt_key, algorithm="HS256")
58-
59-
@staticmethod
60-
def get_auth_token():
61-
# get auth token
62-
auth_header = request.headers.get("Authorization")
63-
64-
if not auth_header:
65-
abort(
66-
HTTPStatus.FORBIDDEN,
67-
message="Please add authorization token as 'Authorization: Bearer <session_token>'",
68-
)
69-
70-
try:
71-
auth_schema, auth_token = auth_header.split()
72-
except ValueError:
15+
token_auth = HTTPTokenAuth("Bearer")
16+
_secret_key = ""
17+
18+
19+
def get_current_user_id() -> Optional[str]:
20+
"""Returns the user id of the current authenticated user.
21+
If the user is not authenticated returns None
22+
"""
23+
user_id = None
24+
user = token_auth.current_user()
25+
if user:
26+
user_id = str(user.id)
27+
return user_id
28+
29+
30+
def _get_secret_key():
31+
global _secret_key
32+
if not _secret_key:
33+
_secret_key = os.getenv("SECRET_KEY", "my_precious")
34+
return _secret_key
35+
36+
37+
def encode_auth_token(time_delta: datetime.timedelta, user_id: int) -> str:
38+
"""
39+
Generates the Auth Token
40+
Args:
41+
time_delta: Token lifetime
42+
user_id: Authorized user's internal ID
43+
Returns:
44+
JWT token string
45+
"""
46+
current_utc = datetime.datetime.now(datetime.timezone.utc)
47+
payload = {
48+
"iat": current_utc,
49+
"exp": current_utc + time_delta,
50+
"sub": user_id,
51+
}
52+
53+
# Get jwt key
54+
jwt_key = _get_secret_key()
55+
return jwt.encode(payload, jwt_key, algorithm="HS256")
56+
57+
58+
def get_auth_token():
59+
# get auth token
60+
auth_header = request.headers.get("Authorization")
61+
62+
if not auth_header:
63+
abort(
64+
HTTPStatus.FORBIDDEN,
65+
message="Please add authorization token as 'Authorization: Bearer <session_token>'",
66+
)
67+
68+
try:
69+
auth_schema, auth_token = auth_header.split()
70+
except ValueError:
71+
abort(
72+
HTTPStatus.UNAUTHORIZED,
73+
message="Malformed Authorization header, please add request header as Authorization: Bearer <session_token>",
74+
)
75+
else:
76+
if auth_schema.lower() != "bearer":
7377
abort(
7478
HTTPStatus.UNAUTHORIZED,
75-
message="Malformed Authorization header, please add request header as Authorization: Bearer <session_token>",
79+
message="Malformed Authorization header, request needs bearer token: Bearer <session_token>",
7680
)
77-
else:
78-
if auth_schema.lower() != "bearer":
79-
abort(
80-
HTTPStatus.UNAUTHORIZED,
81-
message="Malformed Authorization header, request needs bearer token: Bearer <session_token>",
82-
)
83-
return auth_token
84-
85-
@staticmethod
86-
@token_auth.verify_token
87-
def verify_auth(auth_token):
88-
"""
89-
Validates the auth token.
90-
Note: Since we are not encoding 'aud' claim in our JWT tokens
91-
we need to set 'verify_aud' to False while validating the token.
92-
With issue https://issues.redhat.com/browse/PBENCH-895 we can
93-
set it to True when we start validating third party OIDC tokens.
94-
:param auth_token:
95-
:return: User object/None
96-
"""
81+
return auth_token
82+
83+
84+
@token_auth.verify_token
85+
def verify_auth(auth_token):
86+
"""
87+
Validates the auth token.
88+
Note: Since we are not encoding 'aud' claim in our JWT tokens
89+
we need to set 'verify_aud' to False while validating the token.
90+
With issue https://issues.redhat.com/browse/PBENCH-895 we can
91+
set it to True when we start validating third party OIDC tokens.
92+
:param auth_token:
93+
:return: User object/None
94+
"""
95+
try:
96+
payload = jwt.decode(
97+
auth_token,
98+
os.getenv("SECRET_KEY", "my_precious"),
99+
algorithms="HS256",
100+
options={
101+
"verify_signature": True,
102+
"verify_aud": False,
103+
"verify_exp": True,
104+
},
105+
)
106+
user_id = payload["sub"]
107+
if ActiveTokens.valid(auth_token):
108+
user = User.query(id=user_id)
109+
return user
110+
except jwt.ExpiredSignatureError:
97111
try:
98-
payload = jwt.decode(
99-
auth_token,
100-
Auth._get_secret_key(),
101-
algorithms="HS256",
102-
options={
103-
"verify_signature": True,
104-
"verify_aud": False,
105-
"verify_exp": True,
106-
},
107-
)
108-
user_id = payload["sub"]
109-
if ActiveTokens.valid(auth_token):
110-
user = User.query(id=user_id)
111-
return user
112-
except jwt.ExpiredSignatureError:
113-
try:
114-
ActiveTokens.delete(auth_token)
115-
except Exception as e:
116-
current_app.logger.error(
117-
"User passed expired token but we could not delete the token from the database. token: {!r}: {}",
118-
auth_token,
119-
e,
120-
)
121-
except jwt.InvalidTokenError:
122-
pass # Ignore this silently; client is unauthenticated
112+
ActiveTokens.delete(auth_token)
123113
except Exception as e:
124-
current_app.logger.exception(
125-
"Unexpected exception occurred while verifying the auth token {!r}: {}",
114+
current_app.logger.error(
115+
"User passed expired token but we could not delete the token from the database. token: {!r}: {}",
126116
auth_token,
127117
e,
128118
)
129-
return None
130-
131-
@staticmethod
132-
def verify_third_party_token(
133-
auth_token: str, oidc_client: OpenIDClient, logger: Logger
134-
) -> bool:
135-
"""
136-
Verify a token provided to the Pbench server which was obtained from a
137-
third party identity provider.
138-
Args:
139-
auth_token: Token to authenticate
140-
oidc_client: OIDC client to call to authenticate the token
141-
Returns:
142-
True if the verification succeeds else False
143-
"""
144-
try:
145-
oidc_client.token_introspect_offline(
146-
token=auth_token,
147-
key=oidc_client.get_oidc_public_key(),
148-
audience=oidc_client.client_id,
149-
options={
150-
"verify_signature": True,
151-
"verify_aud": True,
152-
"verify_exp": True,
153-
},
154-
)
155-
return True
156-
except (
157-
jwt.ExpiredSignatureError,
158-
jwt.InvalidTokenError,
159-
jwt.InvalidAudienceError,
160-
):
161-
logger.error("OIDC token verification failed")
162-
return False
163-
except Exception:
164-
logger.exception(
165-
"Unexpected exception occurred while verifying the auth token {}",
166-
auth_token,
167-
)
168-
169-
if not oidc_client.TOKENINFO_ENDPOINT:
170-
logger.warning("Can not perform OIDC online token verification")
171-
return False
172-
173-
try:
174-
token_payload = oidc_client.token_introspect_online(
175-
token=auth_token, token_info_uri=oidc_client.TOKENINFO_ENDPOINT
176-
)
177-
except OpenIDClientError:
178-
return False
179-
180-
return "aud" in token_payload and oidc_client.client_id in token_payload["aud"]
119+
except jwt.InvalidTokenError:
120+
pass # Ignore this silently; client is unauthenticated
121+
except Exception as e:
122+
current_app.logger.exception(
123+
"Unexpected exception occurred while verifying the auth token {!r}: {}",
124+
auth_token,
125+
e,
126+
)
127+
return None
128+
129+
130+
def verify_third_party_token(
131+
auth_token: str, oidc_client: OpenIDClient, logger: Logger
132+
) -> bool:
133+
"""
134+
Verify a token provided to the Pbench server which was obtained from a
135+
third party identity provider.
136+
Args:
137+
auth_token: Token to authenticate
138+
oidc_client: OIDC client to call to authenticate the token
139+
Returns:
140+
True if the verification succeeds else False
141+
"""
142+
identity_provider_pubkey = oidc_client.get_oidc_public_key(auth_token)
143+
try:
144+
oidc_client.token_introspect_offline(
145+
token=auth_token,
146+
key=identity_provider_pubkey,
147+
audience=oidc_client.client_id,
148+
options={
149+
"verify_signature": True,
150+
"verify_aud": True,
151+
"verify_exp": True,
152+
},
153+
)
154+
return True
155+
except (
156+
jwt.ExpiredSignatureError,
157+
jwt.InvalidTokenError,
158+
jwt.InvalidAudienceError,
159+
):
160+
logger.error("OIDC token verification failed")
161+
return False
162+
except Exception:
163+
logger.exception(
164+
"Unexpected exception occurred while verifying the auth token {}",
165+
auth_token,
166+
)
167+
168+
if not oidc_client.TOKENINFO_ENDPOINT:
169+
logger.warning("Can not perform OIDC online token verification")
170+
return False
171+
172+
try:
173+
token_payload = oidc_client.token_introspect_online(
174+
token=auth_token, token_info_uri=oidc_client.TOKENINFO_ENDPOINT
175+
)
176+
except OpenIDClientError:
177+
return False
178+
179+
return "aud" in token_payload and oidc_client.client_id in token_payload["aud"]

lib/pbench/test/unit/server/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from pbench.common.logger import get_pbench_logger
1919
from pbench.server import PbenchServerConfig
2020
from pbench.server.api import create_app, get_server_config
21-
from pbench.server.auth.auth import Auth
21+
import pbench.server.auth.auth as Auth
2222
from pbench.server.database.database import Database
2323
from pbench.server.database.models.active_tokens import ActiveTokens
2424
from pbench.server.database.models.datasets import Dataset, Metadata, States

0 commit comments

Comments
 (0)