-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #149 from ral-facilities/feature/python-icat-backe…
…nd-login-endpoints-#135 Python ICAT Backend: Login endpoints & session validation
- Loading branch information
Showing
12 changed files
with
2,084 additions
and
1,873 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,4 @@ venv/ | |
*.pyc | ||
logs.log | ||
config.json | ||
.vscode/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
import logging | ||
|
||
import icat.client | ||
from icat.exception import ICATSessionError | ||
|
||
from common.backend import Backend | ||
from common.helpers import queries_records | ||
from common.python_icat_helpers import requires_session_id, get_session_details_helper, logout_icat_client, refresh_client_session | ||
from common.config import config | ||
from common.exceptions import AuthenticationError | ||
from common.models.db_models import SESSION | ||
|
||
log = logging.getLogger() | ||
|
||
class PythonICATBackend(Backend): | ||
""" | ||
Class that contains functions to access and modify data in an ICAT database directly | ||
""" | ||
|
||
def __init__(self): | ||
# Client object is created here as well as in login() to avoid uncaught exceptions | ||
# where the object is None. This could happen where a user tries to use an endpoint before | ||
# logging in. Also helps to give a bit of certainty to what's stored here | ||
self.client = icat.client.Client(config.get_icat_url(), checkCert=config.get_icat_check_cert()) | ||
|
||
def login(self, credentials): | ||
# Client object is re-created here so session IDs aren't overwritten in the database | ||
self.client = icat.client.Client(config.get_icat_url(), checkCert=config.get_icat_check_cert()) | ||
|
||
# Syntax for Python ICAT | ||
login_details = {'username': credentials['username'], 'password': credentials['password']} | ||
try: | ||
session_id = self.client.login(credentials["mechanism"], login_details) | ||
return session_id | ||
except ICATSessionError: | ||
raise AuthenticationError("User credentials are incorrect") | ||
|
||
@requires_session_id | ||
def get_session_details(self, session_id): | ||
self.client.sessionId = session_id | ||
return get_session_details_helper(self.client) | ||
|
||
@requires_session_id | ||
def refresh(self, session_id): | ||
self.client.sessionId = session_id | ||
return refresh_client_session(self.client) | ||
|
||
@requires_session_id | ||
@queries_records | ||
def logout(self, session_id): | ||
self.client.sessionId = session_id | ||
return logout_icat_client(self.client) | ||
|
||
@requires_session_id | ||
@queries_records | ||
def get_with_filters(self, session_id, table, filters): | ||
pass | ||
|
||
@requires_session_id | ||
@queries_records | ||
def create(self, session_id, table, data): | ||
pass | ||
|
||
@requires_session_id | ||
@queries_records | ||
def update(self, session_id, table, data): | ||
pass | ||
|
||
@requires_session_id | ||
@queries_records | ||
def get_one_with_filters(self, session_id, table, filters): | ||
pass | ||
|
||
@requires_session_id | ||
@queries_records | ||
def count_with_filters(self, session_id, table, filters): | ||
pass | ||
|
||
@requires_session_id | ||
@queries_records | ||
def get_with_id(self, session_id, table, id): | ||
pass | ||
|
||
@requires_session_id | ||
@queries_records | ||
def delete_with_id(self, session_id, table, id): | ||
pass | ||
|
||
@requires_session_id | ||
@queries_records | ||
def update_with_id(self, session_id, table, id, data): | ||
pass | ||
|
||
@requires_session_id | ||
@queries_records | ||
def get_instrument_facilitycycles_with_filters(self, session_id, instrument_id, filters): | ||
pass | ||
|
||
@requires_session_id | ||
@queries_records | ||
def count_instrument_facilitycycles_with_filters(self, session_id, instrument_id, filters): | ||
pass | ||
#return get_facility_cycles_for_instrument_count(instrument_id, filters) | ||
|
||
@requires_session_id | ||
@queries_records | ||
def get_instrument_facilitycycle_investigations_with_filters(self, session_id, instrument_id, facilitycycle_id, filters): | ||
pass | ||
#return get_investigations_for_instrument_in_facility_cycle(instrument_id, facilitycycle_id, filters) | ||
|
||
@requires_session_id | ||
@queries_records | ||
def count_instrument_facilitycycles_investigations_with_filters(self, session_id, instrument_id, facilitycycle_id, filters): | ||
pass | ||
#return get_investigations_for_instrument_in_facility_cycle_count(instrument_id, facilitycycle_id, filters) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
from functools import wraps | ||
import logging | ||
from datetime import datetime, timedelta | ||
|
||
|
||
from icat.exception import ICATSessionError | ||
from common.exceptions import AuthenticationError | ||
|
||
log = logging.getLogger() | ||
|
||
def requires_session_id(method): | ||
""" | ||
Decorator for Python ICAT backend methods that looks out for session errors when using the API. | ||
The API call runs and an ICATSessionError may be raised due to an expired session, invalid | ||
session ID etc. This does not explictly check whether a session ID is valid or not, | ||
:param method: The method for the backend operation | ||
:raises AuthenticationError, if a valid session_id is not provided with the request | ||
""" | ||
|
||
@wraps(method) | ||
def wrapper_requires_session(*args, **kwargs): | ||
try: | ||
|
||
client = args[0].client | ||
# Find out if session has expired | ||
session_time = client.getRemainingMinutes() | ||
log.info("Session time: {}".format(session_time)) | ||
if session_time < 0: | ||
raise AuthenticationError("Forbidden") | ||
else: | ||
return method(*args, **kwargs) | ||
except ICATSessionError: | ||
raise AuthenticationError("Forbidden") | ||
|
||
return wrapper_requires_session | ||
|
||
|
||
def queries_records(method): | ||
""" | ||
Docstring | ||
""" | ||
|
||
@wraps(method) | ||
def wrapper_gets_records(*args, **kwargs): | ||
pass | ||
|
||
return wrapper_gets_records | ||
|
||
|
||
def get_session_details_helper(client): | ||
# Remove rounding | ||
session_time_remaining = client.getRemainingMinutes() | ||
session_expiry_time = datetime.now() + timedelta(minutes=session_time_remaining) | ||
|
||
username = client.getUserName() | ||
|
||
return {"ID": client.sessionId, "EXPIREDATETIME": str(session_expiry_time), "USERNAME": username} | ||
|
||
|
||
def logout_icat_client(client): | ||
client.logout() | ||
|
||
|
||
def refresh_client_session(client): | ||
client.refresh() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.