1
0
mirror of https://github.com/taigaio/taiga-back synced 2025-10-06 00:02:52 +02:00
Files
taiga-back/taiga/auth/backends.py
2024-03-27 12:29:15 +01:00

131 lines
4.9 KiB
Python

# -*- coding: utf-8 -*-
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# Copyright (c) 2021-present Kaleidos INC
#
# The code is partially taken (and modified) from djangorestframework-simplejwt v. 4.7.1
# (https://github.com/jazzband/djangorestframework-simplejwt/tree/5997c1aee8ad5182833d6b6759e44ff0a704edb4)
# that is licensed under the following terms:
#
# Copyright 2017 David Sanders
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to do
# so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import jwt
from django.utils.translation import gettext_lazy as _
from jwt import InvalidAlgorithmError, InvalidTokenError, algorithms
from taiga.base.api.authentication import BaseAuthentication
from .exceptions import TokenBackendError
from .utils import format_lazy
class Session(BaseAuthentication):
"""
Session based authentication like the standard
`taiga.base.api.authentication.SessionAuthentication`
but with csrf disabled (for obvious reasons because
it is for api.
NOTE: this is only for api web interface. Is not used
for common api usage and should be disabled on production.
"""
def authenticate(self, request):
http_request = request._request
user = getattr(http_request, 'user', None)
if not user or not user.is_active:
return None
return (user, None)
ALLOWED_ALGORITHMS = (
'HS256',
'HS384',
'HS512',
'RS256',
'RS384',
'RS512',
)
class TokenBackend:
def __init__(self, algorithm, signing_key=None, verifying_key=None, audience=None, issuer=None):
self._validate_algorithm(algorithm)
self.algorithm = algorithm
self.signing_key = signing_key
self.audience = audience
self.issuer = issuer
if algorithm.startswith('HS'):
self.verifying_key = signing_key
else:
self.verifying_key = verifying_key
def _validate_algorithm(self, algorithm):
"""
Ensure that the nominated algorithm is recognized, and that cryptography is installed for those
algorithms that require it
"""
if algorithm not in ALLOWED_ALGORITHMS:
raise TokenBackendError(format_lazy(_("Unrecognized algorithm type '{}'"), algorithm))
if algorithm in algorithms.requires_cryptography and not algorithms.has_crypto:
raise TokenBackendError(format_lazy(_("You must have cryptography installed to use {}."), algorithm))
def encode(self, payload):
"""
Returns an encoded token for the given payload dictionary.
"""
jwt_payload = payload.copy()
if self.audience is not None:
jwt_payload['aud'] = self.audience
if self.issuer is not None:
jwt_payload['iss'] = self.issuer
token = jwt.encode(jwt_payload, self.signing_key, algorithm=self.algorithm)
if isinstance(token, bytes):
# For PyJWT <= 1.7.1
return token.decode('utf-8')
# For PyJWT >= 2.0.0a1
return token
def decode(self, token, verify=True):
"""
Performs a validation of the given token and returns its payload
dictionary.
Raises a `TokenBackendError` if the token is malformed, if its
signature check fails, or if its 'exp' claim indicates it has expired.
"""
try:
return jwt.decode(
token, self.verifying_key, algorithms=[self.algorithm], verify=verify,
audience=self.audience, issuer=self.issuer,
options={'verify_aud': self.audience is not None, "verify_signature": verify}
)
except InvalidAlgorithmError as ex:
raise TokenBackendError(_('Invalid algorithm specified')) from ex
except InvalidTokenError:
raise TokenBackendError(_('Token is invalid or expired'))