Skip to content

Commit

Permalink
Merge pull request #31 from jjjermiah/docs/updateDocs
Browse files Browse the repository at this point in the history
Docs/update docs
  • Loading branch information
jjjermiah committed Dec 16, 2023
2 parents f9c1c8a + 5141005 commit 359a30d
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 119 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
Continuous-Development:
needs: Continuous-Integration

if: github.event_name == 'push' && github.ref == 'refs/heads/main'
if: github.ref == 'refs/heads/main' # github.event_name == 'push' &&

runs-on: ubuntu-latest

Expand Down
123 changes: 82 additions & 41 deletions src/nbiatoolkit/auth.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import requests
import time

from typing import Union

class OAuth2:
"""
Expand All @@ -14,16 +14,7 @@ class OAuth2:
to the collections tagged with "limited access" you can use those
credentials to access those collections.
NOTE::This class is mainly for developers looking to add functionality
to the nbiatoolkit package. If you are a user looking to access the NBIA
API, you can use the `NBIAClient` class without knowledge of this class.
TODO::implement better access token handling
TODO::implement better error handling
TODO::implement refresh token functionality
TODO::implement logout functionality
TODO::implement encryption for username and password
Attributes
----------
client_id : str
Expand All @@ -32,8 +23,18 @@ class OAuth2:
The username for authentication.
password : str
The password for authentication.
access_token : str
access_token : str or None
The access token retrieved from the API.
api_headers : dict or None
The authentication headers containing the access token.
expiry_time : str or None
The expiry time of the access token.
refresh_token : str or None
The refresh token for obtaining a new access token.
refresh_expiry : int or None
The expiry time of the refresh token.
scope : str or None
The scope of the access token.
Methods
-------
Expand All @@ -43,34 +44,53 @@ class OAuth2:
Example Usage
-------------
>>> from nbiatoolkit import OAuth2
>>> from nbiatoolkit.auth import OAuth2
To use the NBIA Guest account:
>>> oauth = OAuth2()
To use a custom account:
>>> oauth = OAuth2(username="my_username", password="my_password")
Notes
-----
This class is mainly for developers looking to add functionality
to the nbiatoolkit package. If you are a user looking to access the NBIA
API, you can use the `NBIAClient` class without knowledge of this class.
As there are many packages for handling OAuth2 authentication, this class
was for myself to learn how OAuth2 works and to provide a simple way to
authenticate with the NBIA API. If you have any suggestions for improving
this class, please open an issue on the GitHub repository.
"""

def __init__(self, username: str = "nbia_guest", password: str = "", client_id: str = "NBIA"):
"""
Initialize the OAuth2 class.
Parameters
----------
client_id : str, optional
The client ID for authentication. Default is "NBIA".
username : str, optional
The username for authentication. Default is "nbia_guest".
password : str, optional
The password for authentication. Default is an empty string.
client_id : str, optional
The client ID for authentication. Default is "NBIA".
"""
self.client_id = client_id
self.username = username
self.password = password
self.access_token = None
self.api_headers = None
self.expiry_time = None
self.refresh_token = None
self.refresh_expiry = None
self.scope = None

def getToken(self):
def getToken(self) -> Union[dict, int]:
"""
Retrieves the access token from the API.
Expand All @@ -89,7 +109,7 @@ def getToken(self):
"""
# Check if the access token is valid and not expired
if self.access_token is not None:
return 401 if self.access_token == 401 else self.access_token
return 401 if self.access_token == -1 else self.access_token

# Prepare the request data
data = {
Expand All @@ -102,30 +122,51 @@ def getToken(self):

response = requests.post(token_url, data=data)

try:
response.raise_for_status()
except requests.exceptions.HTTPError as e:
print(f"HTTP Error occurred: {e}")
print(f"Failed to get access token. Status code: {response.status_code}")

self.access_token = response.status_code
return response.status_code
try:
response = requests.post(token_url, data=data)
response.raise_for_status() # Raise an HTTPError for bad responses
except requests.exceptions.RequestException as e:
self.access_token = -1
raise requests.exceptions.RequestException(\
f'Failed to get access token. Status code:\
{response.status_code}') from e
else:
# Code to execute if there is no exception
token_data = response.json()
self.access_token = token_data.get('access_token')

self.api_headers = {
'Authorization': f'Bearer {self.access_token}'
}

self.expiry_time = time.ctime(time.time() + token_data.get('expires_in'))
self.refresh_token = token_data.get('refresh_token')
self.refresh_expiry = token_data.get('refresh_expires_in')
self.scope = token_data.get('scope')

return self.api_headers

@property
def token(self):
"""
Returns the access token.
token_data = response.json()
self.access_token = token_data.get('access_token')
Returns
-------
access_token : str or None
The access token retrieved from the API.
"""
return self.access_token

self.api_headers = {
'Authorization':f'Bearer {self.access_token}'
}
@property
def headers(self):
"""
Returns the API headers.
self.expiry_time = time.ctime(time.time() + token_data.get('expires_in'))
self.refresh_token = token_data.get('refresh_token')
self.refresh_expiry = token_data.get('refresh_expires_in')
self.scope = token_data.get('scope')
return self.api_headers

# def logout(self):
# # Request for logout
# # curl -X -v -d "Authorization:Bearer YOUR_ACCESS_TOKEN" -k "https://services.cancerimagingarchive.net/nbia-api/logout"


Returns
-------
api_headers : dict or None
The authentication headers containing the access token.
"""
return self.api_headers
61 changes: 0 additions & 61 deletions tests/oldtest_nbia.py

This file was deleted.

42 changes: 26 additions & 16 deletions tests/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import pytest
from nbiatoolkit import OAuth2
import time

import requests

@pytest.fixture(scope="session")
def oauth2():
Expand All @@ -17,35 +17,45 @@ def oauth2():
@pytest.fixture(scope="session")
def failed_oauth2():
oauth = OAuth2(username="bad_username", password="bad_password")
oauth.getToken()
return oauth

def test_getToken(oauth2):
assert oauth2.access_token is not None
assert oauth2.token is not None

def test_expiry(oauth2):
# expiry should be in the form of :'Tue Jun 29 13:58:57 2077'
# and test for roughly 2 hours from now
print(oauth2.expiry_time)
assert oauth2.expiry_time <= time.ctime(time.time() + 7200)

def test_failed_oauth(failed_oauth2,capsys):
# Answer should be Failed to get access token. Status code: 401
# because the username and password are incorrect
# assert Status code 401
captured = capsys.readouterr()
assert failed_oauth2.access_token == 401
def test_failed_oauth(failed_oauth2):
# should raise requests.exceptions.RequestException
with pytest.raises(requests.exceptions.RequestException):
failed_oauth2.getToken()
assert failed_oauth2.getToken() == 401
assert failed_oauth2.access_token == -1
assert failed_oauth2.token == -1
assert failed_oauth2.getToken() == 401
assert failed_oauth2.headers is None
assert failed_oauth2.api_headers is None
assert failed_oauth2.expiry_time is None
assert failed_oauth2.refresh_token is None
assert failed_oauth2.refresh_expiry is None
assert failed_oauth2.scope is None

def test_failed_oauth_retried(failed_oauth2,capsys):
failed_oauth2.getToken()
captured = capsys.readouterr()
assert failed_oauth2.access_token == 401

def test_getToken_valid_token(oauth2):
# Test if the access token is valid and not expired
assert oauth2.getToken() == oauth2.access_token
assert oauth2.getToken() != 401
assert oauth2.access_token != -1
assert oauth2.token != -1
assert oauth2.api_headers is not None
assert oauth2.headers is not None
assert oauth2.expiry_time is not None
assert oauth2.refresh_token is not None
assert oauth2.refresh_expiry is not None
assert oauth2.scope is not None


def test_getToken_failed_token(failed_oauth2, capsys):
# Test if the access token retrieval fails with incorrect credentials
assert failed_oauth2.getToken() == 401
captured = capsys.readouterr()

0 comments on commit 359a30d

Please sign in to comment.