bemade-addons/unifi_integration/models/unifi_auth_session.py
2025-03-27 15:34:13 -04:00

249 lines
8 KiB
Python

# -*- coding: utf-8 -*-
# These imports will work in an Odoo environment, even if your IDE marks them as not found
# pylint: disable=import-error
from odoo import models, fields, api, _
# pylint: enable=import-error
import logging
from datetime import datetime, timedelta
_logger = logging.getLogger(__name__)
class UnifiAuthSession(models.Model):
"""Manages authentication sessions for UniFi APIs
This model stores authentication tokens, cookies, and session information
for both the Site Manager API and Controller API. It handles token refresh
and session validation.
"""
_name = 'unifi.auth.session'
_description = 'UniFi Authentication Session'
site_id = fields.Many2one(
comodel_name='unifi.site',
string='Site',
required=True,
ondelete='cascade',
help='The site this authentication session belongs to'
)
auth_type = fields.Selection(
selection=[
('site_manager', 'Site Manager API'),
('controller', 'Controller API')
],
string='Authentication Type',
required=True,
help='Type of authentication'
)
token = fields.Char(
string='Authentication Token',
help='Authentication token or cookie'
)
csrf_token = fields.Char(
string='CSRF Token',
help='Cross-Site Request Forgery protection token'
)
cookie = fields.Text(
string='Session Cookie',
help='Session cookie for Controller API'
)
endpoint = fields.Char(
string='Authentication Endpoint',
help='The endpoint used for authentication (e.g. /api/login or /api/auth/login)'
)
is_udm_pro = fields.Boolean(
string='Is UDM Pro',
default=False,
help='Indicates if this session is for a UDM Pro or UDM Pro SE device'
)
expiry = fields.Datetime(
string='Expiry Date',
help='Date and time when this session expires'
)
is_valid = fields.Boolean(
string='Is Valid',
compute='_compute_is_valid',
store=False,
help='Whether this session is currently valid'
)
last_used = fields.Datetime(
string='Last Used',
default=fields.Datetime.now,
help='Date and time when this session was last used'
)
created_at = fields.Datetime(
string='Created At',
default=fields.Datetime.now,
readonly=True,
help='Date and time when this session was created'
)
@api.depends('expiry')
def _compute_is_valid(self):
"""Compute whether the session is valid based on expiry date"""
now = fields.Datetime.now()
for session in self:
if not session.expiry:
session.is_valid = False
else:
session.is_valid = session.expiry > now
@api.onchange('auth_type')
def _onchange_auth_type(self):
"""Handle changes to auth_type field
This method is triggered when the auth_type field is changed.
It clears fields that are not relevant to the selected authentication type.
"""
if self.auth_type == 'site_manager':
# Clear controller-specific fields
self.cookie = False
elif self.auth_type == 'controller':
# Clear site manager-specific fields
self.csrf_token = False
def validate(self):
"""Validate the session and refresh if necessary
Returns:
bool: True if the session is valid, False otherwise
"""
self.ensure_one()
# Check if the session is expired
if not self.is_valid:
# Try to refresh the session
return self.refresh()
# Update last used timestamp
self.write({'last_used': fields.Datetime.now()})
return True
def refresh(self):
"""Refresh the authentication session
Returns:
bool: True if the session was refreshed successfully, False otherwise
"""
self.ensure_one()
try:
if self.auth_type == 'site_manager':
return self._refresh_site_manager_session()
elif self.auth_type == 'controller':
return self._refresh_controller_session()
return False
except Exception as e:
_logger.error('Error refreshing authentication session: %s', str(e))
return False
def _refresh_site_manager_session(self):
"""Refresh a Site Manager API session
Returns:
bool: True if the session was refreshed successfully, False otherwise
"""
# This is a placeholder - will be implemented with actual API calls
try:
# Logic to refresh Site Manager API session
# Update session data
self.write({
'expiry': fields.Datetime.now() + timedelta(hours=1),
'last_used': fields.Datetime.now()
})
return True
except (ValueError, TypeError) as e:
_logger.error('Error refreshing Site Manager session: %s', str(e))
return False
except Exception as e:
_logger.error('Unexpected error refreshing Site Manager session: %s', str(e))
return False
def _refresh_controller_session(self):
"""Refresh a Controller API session
Returns:
bool: True if the session was refreshed successfully, False otherwise
"""
# This is a placeholder - will be implemented with actual API calls
try:
# Logic to refresh Controller API session
# Update session data
self.write({
'expiry': fields.Datetime.now() + timedelta(hours=1),
'last_used': fields.Datetime.now()
})
return True
except (ValueError, TypeError) as e:
_logger.error('Error refreshing Controller session: %s', str(e))
return False
except Exception as e:
_logger.error('Unexpected error refreshing Controller session: %s', str(e))
return False
@api.model
def create_session(self, site_id, auth_type, token=None, csrf_token=None, cookie=None, expiry=None):
"""Create a new authentication session
Args:
site_id (int): ID of the site
auth_type (str): Type of authentication ('site_manager' or 'controller')
token (str, optional): Authentication token
csrf_token (str, optional): CSRF token
cookie (str, optional): Session cookie
expiry (datetime, optional): Expiry date and time
Returns:
unifi.auth.session: The created session record
"""
# Set default expiry if not provided
if not expiry:
expiry = fields.Datetime.now() + timedelta(hours=1)
# Create the session
return self.create({
'site_id': site_id,
'auth_type': auth_type,
'token': token,
'csrf_token': csrf_token,
'cookie': cookie,
'expiry': expiry,
'last_used': fields.Datetime.now(),
})
def invalidate(self):
"""Invalidate the session
Returns:
bool: True if the session was invalidated successfully, False otherwise
"""
self.ensure_one()
try:
# Set expiry to a past date to invalidate the session
self.write({
'expiry': fields.Datetime.now() - timedelta(days=1)
})
return True
except (ValueError, TypeError) as e:
_logger.error('Error invalidating session: %s', str(e))
return False
except Exception as e:
_logger.error('Unexpected error invalidating session: %s', str(e))
return False