mirror of
https://github.com/fuckpiracyshield/api.git
synced 2024-12-22 10:40:48 +01:00
Added sessions support.
This commit is contained in:
parent
183fa3e27a
commit
0fb6d08a7f
9 changed files with 115 additions and 60 deletions
|
@ -23,17 +23,19 @@ class ErrorCode:
|
||||||
|
|
||||||
TOKEN_FORMAT_NON_VALID = '1008'
|
TOKEN_FORMAT_NON_VALID = '1008'
|
||||||
|
|
||||||
NON_VALID_PARAMETERS = '1009'
|
TOKEN_EXPIRED = '1009'
|
||||||
|
|
||||||
MISSING_PARAMETERS = '1010'
|
NON_VALID_PARAMETERS = '1010'
|
||||||
|
|
||||||
TOO_MANY_PARAMETERS = '1011'
|
MISSING_PARAMETERS = '1011'
|
||||||
|
|
||||||
MISSING_FILE = '1012'
|
TOO_MANY_PARAMETERS = '1012'
|
||||||
|
|
||||||
CHANGE_PASSWORD = '1013'
|
MISSING_FILE = '1013'
|
||||||
|
|
||||||
IP_ADDRESS_BLACKLISTED = '1014'
|
CHANGE_PASSWORD = '1014'
|
||||||
|
|
||||||
|
IP_ADDRESS_BLACKLISTED = '1015'
|
||||||
|
|
||||||
class ErrorMessage:
|
class ErrorMessage:
|
||||||
|
|
||||||
|
@ -63,6 +65,8 @@ class ErrorMessage:
|
||||||
|
|
||||||
TOKEN_FORMAT_NON_VALID = 'Token format non valid.'
|
TOKEN_FORMAT_NON_VALID = 'Token format non valid.'
|
||||||
|
|
||||||
|
TOKEN_EXPIRED = 'This token is expired.'
|
||||||
|
|
||||||
# json POST parameters
|
# json POST parameters
|
||||||
|
|
||||||
NON_VALID_PARAMETERS = 'Expecting JSON data.'
|
NON_VALID_PARAMETERS = 'Expecting JSON data.'
|
||||||
|
@ -77,6 +81,6 @@ class ErrorMessage:
|
||||||
|
|
||||||
# account settings
|
# account settings
|
||||||
|
|
||||||
CHANGE_PASSWORD = 'A password change has been activated for your account. You must first authenticate via web app and follow the instructions.'
|
CHANGE_PASSWORD = 'A password change has been activated for your account. You must authenticate via web interface and follow the instructions. You should now discard this tokens pairs.'
|
||||||
|
|
||||||
IP_ADDRESS_BLACKLISTED = 'Your IP address is temporary blacklisted.'
|
IP_ADDRESS_BLACKLISTED = 'Your IP address is temporary blacklisted.'
|
||||||
|
|
|
@ -2,6 +2,8 @@ from .base import BaseHandler
|
||||||
|
|
||||||
from piracyshield_component.exception import ApplicationException
|
from piracyshield_component.exception import ApplicationException
|
||||||
|
|
||||||
|
from piracyshield_service.security.blacklist.exists_by_access_token import SecurityBlacklistExistsByAccessTokenService
|
||||||
|
|
||||||
from piracyshield_service.authentication.verify_access_token import AuthenticationVerifyAccessTokenService
|
from piracyshield_service.authentication.verify_access_token import AuthenticationVerifyAccessTokenService
|
||||||
|
|
||||||
from piracyshield_service.permission.service import PermissionService
|
from piracyshield_service.permission.service import PermissionService
|
||||||
|
@ -28,6 +30,8 @@ class ProtectedHandler(BaseHandler):
|
||||||
account_data = {}
|
account_data = {}
|
||||||
|
|
||||||
async def prepare(self):
|
async def prepare(self):
|
||||||
|
self.security_blacklist_exists_by_access_token_service = SecurityBlacklistExistsByAccessTokenService()
|
||||||
|
|
||||||
self.authentication_verify_access_token_service = AuthenticationVerifyAccessTokenService()
|
self.authentication_verify_access_token_service = AuthenticationVerifyAccessTokenService()
|
||||||
|
|
||||||
await super().prepare()
|
await super().prepare()
|
||||||
|
@ -52,12 +56,19 @@ class ProtectedHandler(BaseHandler):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# get the token only
|
# get the token only
|
||||||
token = authorization_header[7:]
|
self.current_access_token = authorization_header[7:]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
if self.security_blacklist_exists_by_access_token_service.execute(
|
||||||
|
access_token = self.current_access_token
|
||||||
|
) == True:
|
||||||
|
self.error(status_code = 401, error_code = ErrorCode.TOKEN_EXPIRED, message = ErrorMessage.TOKEN_EXPIRED)
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
# set the current account data
|
# set the current account data
|
||||||
# TODO: absolutely need to validate the payload.
|
# TODO: absolutely need to validate the payload.
|
||||||
self.account_data = self.authentication_verify_access_token_service.execute(token)
|
self.account_data = self.authentication_verify_access_token_service.execute(self.current_access_token)
|
||||||
|
|
||||||
if not self.account_data.get('email'):
|
if not self.account_data.get('email'):
|
||||||
self.error(status_code = 401, error_code = ErrorCode.TOKEN_FORMAT_NON_VALID, message = ErrorMessage.TOKEN_FORMAT_NON_VALID)
|
self.error(status_code = 401, error_code = ErrorCode.TOKEN_FORMAT_NON_VALID, message = ErrorMessage.TOKEN_FORMAT_NON_VALID)
|
||||||
|
|
|
@ -15,7 +15,7 @@ class TestReporterCreateTicket:
|
||||||
ticket_wait_time = 76
|
ticket_wait_time = 76
|
||||||
|
|
||||||
ticket_parameters = {
|
ticket_parameters = {
|
||||||
'dda_id': '2326485749e94573bf5724ff5006f30c',
|
'dda_id': '002ad48ea02a43db9003b4f15f1da9b3',
|
||||||
'description': '__MOCK_TICKET__',
|
'description': '__MOCK_TICKET__',
|
||||||
'forensic_evidence': {
|
'forensic_evidence': {
|
||||||
'hash': {}
|
'hash': {}
|
||||||
|
@ -44,6 +44,8 @@ class TestReporterCreateTicket:
|
||||||
|
|
||||||
create_response = authenticated_post_request('/api/v1/ticket/create', self.access_token, self.ticket_parameters)
|
create_response = authenticated_post_request('/api/v1/ticket/create', self.access_token, self.ticket_parameters)
|
||||||
|
|
||||||
|
print(" RES -> ", create_response.json())
|
||||||
|
|
||||||
assert create_response.status_code == 200
|
assert create_response.status_code == 200
|
||||||
assert create_response.json()['status'] == 'success'
|
assert create_response.json()['status'] == 'success'
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,10 @@ import pytest
|
||||||
import os
|
import os
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
application_config = Config('api').get('general')
|
application_config = Config('application').get('general')
|
||||||
|
api_config = Config('application').get('api')
|
||||||
|
|
||||||
URL = f"http://127.0.0.1:{application_config['port']}"
|
URL = f"{application_config.get('domain')}:{api_config.get('port')}"
|
||||||
|
|
||||||
def get_request(endpoint: str):
|
def get_request(endpoint: str):
|
||||||
return requests.get(f'{URL}{endpoint}')
|
return requests.get(f'{URL}{endpoint}')
|
||||||
|
|
41
v1/handlers/account/session/get_all.py
Normal file
41
v1/handlers/account/session/get_all.py
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
# I hate python imports
|
||||||
|
current = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
parent = os.path.dirname(current)
|
||||||
|
sys.path.append(parent)
|
||||||
|
|
||||||
|
import tornado
|
||||||
|
|
||||||
|
from ioutils.protected import ProtectedHandler
|
||||||
|
|
||||||
|
from piracyshield_service.permission.service import PermissionService
|
||||||
|
from piracyshield_service.account.session.get_all_by_account_ordered import AccountSessionGetAllByAccountOrderedService
|
||||||
|
|
||||||
|
from piracyshield_component.exception import ApplicationException
|
||||||
|
|
||||||
|
class GetAllSessionAccountHandler(ProtectedHandler):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Handles getting multiple active sessions.
|
||||||
|
"""
|
||||||
|
|
||||||
|
async def get(self):
|
||||||
|
if self.initialize_account() == False:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
account_session_get_all_by_account_ordered_service = AccountSessionGetAllByAccountOrderedService()
|
||||||
|
|
||||||
|
response = await tornado.ioloop.IOLoop.current().run_in_executor(
|
||||||
|
None,
|
||||||
|
account_session_get_all_by_account_ordered_service.execute,
|
||||||
|
self.account_data.get('account_id'),
|
||||||
|
self.current_access_token
|
||||||
|
)
|
||||||
|
|
||||||
|
self.success(data = response)
|
||||||
|
|
||||||
|
except ApplicationException as e:
|
||||||
|
self.error(status_code = 400, error_code = e.code, message = e.message)
|
|
@ -11,8 +11,6 @@ from ioutils.base import BaseHandler
|
||||||
from ioutils.errors import ErrorCode, ErrorMessage
|
from ioutils.errors import ErrorCode, ErrorMessage
|
||||||
|
|
||||||
from piracyshield_service.authentication.authenticate import AuthenticationAuthenticateService
|
from piracyshield_service.authentication.authenticate import AuthenticationAuthenticateService
|
||||||
from piracyshield_service.authentication.generate_access_token import AuthenticationGenerateAccessTokenService
|
|
||||||
from piracyshield_service.authentication.generate_refresh_token import AuthenticationGenerateRefreshTokenService
|
|
||||||
|
|
||||||
from piracyshield_component.exception import ApplicationException
|
from piracyshield_component.exception import ApplicationException
|
||||||
|
|
||||||
|
@ -36,14 +34,19 @@ class AuthenticationLoginHandler(BaseHandler):
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
authentication_authenticate_service = AuthenticationAuthenticateService()
|
||||||
|
|
||||||
access_token, refresh_token = await tornado.ioloop.IOLoop.current().run_in_executor(
|
access_token, refresh_token = await tornado.ioloop.IOLoop.current().run_in_executor(
|
||||||
None,
|
None,
|
||||||
self.process,
|
authentication_authenticate_service.execute,
|
||||||
self.request_data.get('email'),
|
self.request_data.get('email'),
|
||||||
self.request_data.get('password'),
|
self.request_data.get('password'),
|
||||||
self.request.remote_ip
|
self.request.remote_ip
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# store the refresh token in a http-only secure cookie
|
||||||
|
self.set_refresh_cookie(value = refresh_token)
|
||||||
|
|
||||||
self.success(data = {
|
self.success(data = {
|
||||||
'access_token': access_token,
|
'access_token': access_token,
|
||||||
'refresh_token': refresh_token
|
'refresh_token': refresh_token
|
||||||
|
@ -51,25 +54,3 @@ class AuthenticationLoginHandler(BaseHandler):
|
||||||
|
|
||||||
except ApplicationException as e:
|
except ApplicationException as e:
|
||||||
self.error(status_code = 400, error_code = e.code, message = e.message)
|
self.error(status_code = 400, error_code = e.code, message = e.message)
|
||||||
|
|
||||||
def process(self, email: str, password: str, ip_address: str) -> tuple:
|
|
||||||
authentication_authenticate_service = AuthenticationAuthenticateService()
|
|
||||||
|
|
||||||
# try to authenticate
|
|
||||||
payload = authentication_authenticate_service.execute(
|
|
||||||
email = email,
|
|
||||||
password = password,
|
|
||||||
ip_address = ip_address
|
|
||||||
)
|
|
||||||
|
|
||||||
authentication_generate_access_token_service = AuthenticationGenerateAccessTokenService()
|
|
||||||
authentication_generate_refresh_token_service = AuthenticationGenerateRefreshTokenService()
|
|
||||||
|
|
||||||
# generate token pairs
|
|
||||||
access_token = authentication_generate_access_token_service.execute(payload)
|
|
||||||
refresh_token = authentication_generate_refresh_token_service.execute(payload)
|
|
||||||
|
|
||||||
# store the refresh_token in a http-only cookie
|
|
||||||
self.set_refresh_cookie(value = refresh_token)
|
|
||||||
|
|
||||||
return access_token, refresh_token
|
|
||||||
|
|
|
@ -7,19 +7,31 @@ sys.path.append(parent)
|
||||||
|
|
||||||
from ioutils.protected import ProtectedHandler
|
from ioutils.protected import ProtectedHandler
|
||||||
|
|
||||||
|
from piracyshield_service.account.session.destroy_current_sessions import AccountSessionDestroyCurrentSessionsService
|
||||||
|
|
||||||
from piracyshield_component.exception import ApplicationException
|
from piracyshield_component.exception import ApplicationException
|
||||||
|
|
||||||
class AuthenticationLogoutHandler(ProtectedHandler):
|
class AuthenticationLogoutHandler(ProtectedHandler):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Removes the authentication refresh token.
|
Removes the authentication refresh token and blacklists both the tokens.
|
||||||
The effective logout remains on the access token expiration time, this is why it should be set to a short time.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get(self):
|
def get(self):
|
||||||
if self.initialize_account() == False:
|
if self.initialize_account() == False:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
account_session_destroy_current_sessions_service = AccountSessionDestroyCurrentSessionsService()
|
||||||
|
|
||||||
|
account_session_destroy_current_sessions_service.execute(
|
||||||
|
self.account_data.get('account_id'),
|
||||||
|
self.current_access_token
|
||||||
|
)
|
||||||
|
|
||||||
self.clear_cookie('refresh_token')
|
self.clear_cookie('refresh_token')
|
||||||
|
|
||||||
self.success(data = 'Goodbye!')
|
self.success(data = 'Goodbye!')
|
||||||
|
|
||||||
|
except ApplicationException as e:
|
||||||
|
self.error(status_code = 400, error_code = e.code, message = e.message)
|
||||||
|
|
|
@ -10,8 +10,9 @@ import tornado
|
||||||
from ioutils.base import BaseHandler
|
from ioutils.base import BaseHandler
|
||||||
from ioutils.errors import ErrorCode, ErrorMessage
|
from ioutils.errors import ErrorCode, ErrorMessage
|
||||||
|
|
||||||
from piracyshield_service.authentication.verify_refresh_token import AuthenticationVerifyRefreshTokenService
|
from piracyshield_service.security.blacklist.exists_by_refresh_token import SecurityBlacklistExistsByRefreshTokenService
|
||||||
from piracyshield_service.authentication.generate_access_token import AuthenticationGenerateAccessTokenService
|
|
||||||
|
from piracyshield_service.authentication.refresh_access_token import AuthenticationRefreshAccessTokenService
|
||||||
|
|
||||||
from piracyshield_component.exception import ApplicationException
|
from piracyshield_component.exception import ApplicationException
|
||||||
|
|
||||||
|
@ -41,10 +42,22 @@ class AuthenticationRefreshHandler(BaseHandler):
|
||||||
refresh_token = self.request_data.get('refresh_token')
|
refresh_token = self.request_data.get('refresh_token')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
security_blacklist_exists_by_refresh_token_service = SecurityBlacklistExistsByRefreshTokenService()
|
||||||
|
|
||||||
|
if security_blacklist_exists_by_refresh_token_service.execute(
|
||||||
|
refresh_token = refresh_token
|
||||||
|
) == True:
|
||||||
|
self.error(status_code = 401, error_code = ErrorCode.TOKEN_EXPIRED, message = ErrorMessage.TOKEN_EXPIRED)
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
authentication_refresh_access_token_service = AuthenticationRefreshAccessTokenService()
|
||||||
|
|
||||||
access_token = await tornado.ioloop.IOLoop.current().run_in_executor(
|
access_token = await tornado.ioloop.IOLoop.current().run_in_executor(
|
||||||
None,
|
None,
|
||||||
self.process,
|
authentication_refresh_access_token_service.execute,
|
||||||
refresh_token
|
refresh_token,
|
||||||
|
self.request.remote_ip
|
||||||
)
|
)
|
||||||
|
|
||||||
# return the access_token
|
# return the access_token
|
||||||
|
@ -54,18 +67,3 @@ class AuthenticationRefreshHandler(BaseHandler):
|
||||||
|
|
||||||
except ApplicationException as e:
|
except ApplicationException as e:
|
||||||
self.error(status_code = 400, error_code = e.code, message = e.message)
|
self.error(status_code = 400, error_code = e.code, message = e.message)
|
||||||
|
|
||||||
def process(self, refresh_token: str) -> str:
|
|
||||||
authentication_verify_refresh_token_service = AuthenticationVerifyRefreshTokenService()
|
|
||||||
|
|
||||||
# verify the token and unwrap the payload
|
|
||||||
payload = authentication_verify_refresh_token_service.execute(
|
|
||||||
token = refresh_token
|
|
||||||
)
|
|
||||||
|
|
||||||
authentication_generate_access_token_service = AuthenticationGenerateAccessTokenService()
|
|
||||||
|
|
||||||
# generate a new access token
|
|
||||||
access_token = authentication_generate_access_token_service.execute(payload)
|
|
||||||
|
|
||||||
return access_token
|
|
||||||
|
|
|
@ -31,6 +31,8 @@ from .handlers.account.provider.set_status import SetStatusActiveProviderAccount
|
||||||
from .handlers.account.provider.change_password import ChangePasswordProviderAccountHandler
|
from .handlers.account.provider.change_password import ChangePasswordProviderAccountHandler
|
||||||
from .handlers.account.provider.remove import RemoveProviderAccountHandler
|
from .handlers.account.provider.remove import RemoveProviderAccountHandler
|
||||||
|
|
||||||
|
from .handlers.account.session.get_all import GetAllSessionAccountHandler
|
||||||
|
|
||||||
from .handlers.ticket.create import CreateTicketHandler
|
from .handlers.ticket.create import CreateTicketHandler
|
||||||
from .handlers.ticket.get import GetTicketHandler
|
from .handlers.ticket.get import GetTicketHandler
|
||||||
from .handlers.ticket.get_all import GetAllTicketHandler
|
from .handlers.ticket.get_all import GetAllTicketHandler
|
||||||
|
@ -139,6 +141,9 @@ class APIv1:
|
||||||
(r"/account/provider/change_password", ChangePasswordProviderAccountHandler),
|
(r"/account/provider/change_password", ChangePasswordProviderAccountHandler),
|
||||||
(r"/account/provider/remove", RemoveProviderAccountHandler),
|
(r"/account/provider/remove", RemoveProviderAccountHandler),
|
||||||
|
|
||||||
|
# sessions
|
||||||
|
(r"/account/session/get/all", GetAllSessionAccountHandler),
|
||||||
|
|
||||||
# blocking ticket management
|
# blocking ticket management
|
||||||
(r"/ticket/create", CreateTicketHandler),
|
(r"/ticket/create", CreateTicketHandler),
|
||||||
(r"/ticket/get", GetTicketHandler),
|
(r"/ticket/get", GetTicketHandler),
|
||||||
|
|
Loading…
Reference in a new issue