auth.py 3.91 KB
Newer Older
1
2
3
"""
Authentication service
"""
Barbora Kompišová's avatar
Barbora Kompišová committed
4
5
6
import logging

from flask_jwt_extended import get_jwt_identity
Barbora Kompišová's avatar
Barbora Kompišová committed
7

Barbora Kompišová's avatar
Barbora Kompišová committed
8
from portal.database.models import Client
9
from portal.service import errors
10

Barbora Kompišová's avatar
Barbora Kompišová committed
11
log = logging.getLogger(__name__)
12

Barbora Kompišová's avatar
Barbora Kompišová committed
13

14
15
16
class AuthService:
    def __init__(self, rest_service):
        self._rest_service = rest_service
Barbora Kompišová's avatar
Barbora Kompišová committed
17

18
19
20
    @property
    def client(self):
        return self.find_client()
Barbora Kompišová's avatar
Barbora Kompišová committed
21

22
23
24
25
    @property
    def gitlab_factory(self):
        from portal import gitlab_factory
        return gitlab_factory
26

27
28
29
    def login_client(self, **data) -> Client:
        if not data.get('type'):
            raise errors.PortalAPIError(400, message="Missing login type.")
30

31
32
33
34
        login_type = data['type']
        types = dict(gitlab=self.login_gitlab,
                     username_password=self.login_username_password,
                     secret=self.login_secret)
35

36
37
38
39
        if login_type not in types.keys():
            raise errors.PortalAPIError(400, message="Invalid login type.")
        identifier = data.get('identifier', None)
        secret = data.get('secret', None)
40

41
        return types[login_type](identifier, secret)
Barbora Kompišová's avatar
Barbora Kompišová committed
42

43
44
    def login_gitlab(self, identifier: str, secret: str) -> Client:
        """Verifies GitLab access token and username combination.
45

46
47
48
49
50
51
52
53
            Args:
                identifier(str): username of the user attempting to log in
                secret(str): access token string from gitlab

            Returns(User): the authenticated user
            """
        if secret is None:
            raise errors.PortalAPIError(400, 'No gitlab access token found.')
Barbora Kompišová's avatar
Barbora Kompišová committed
54

55
56
57
58
59
        self.validate_gitlab_token(secret, username=identifier)

        user = self._rest_service.find.user(identifier, throws=False)
        if user is None:
            raise errors.InvalidGitlabAccessTokenError()
Barbora Kompišová's avatar
Barbora Kompišová committed
60
        return user
Barbora Kompišová's avatar
Barbora Kompišová committed
61

62
63
64
65
66
    def login_username_password(self, identifier: str, secret: str) -> Client:
        """Verifies user login credentials.
        Args:
            identifier(str): username to log in
            secret(str): user's password
Barbora Kompišová's avatar
Barbora Kompišová committed
67

68
        Returns(Client): the authenticated user
Barbora Kompišová's avatar
Barbora Kompišová committed
69

70
71
72
73
        """
        user = self._rest_service.find.user(identifier, throws=False)
        if user is None or secret is None:
            raise errors.IncorrectCredentialsError()
Barbora Kompišová's avatar
Barbora Kompišová committed
74

75
76
        if user.verify_password(password=secret):
            return user
Barbora Kompišová's avatar
Barbora Kompišová committed
77

78
        raise errors.IncorrectCredentialsError()
Barbora Kompišová's avatar
Barbora Kompišová committed
79

80
81
    def login_secret(self, identifier: str, secret: str) -> Client:
        """Verifies the provided Client secret.
Barbora Kompišová's avatar
Barbora Kompišová committed
82

83
84
85
        Args:
            identifier: identifier of the Client to log in
            secret: the provided secret
Barbora Kompišová's avatar
Barbora Kompišová committed
86

87
        Returns:
88

89
90
91
92
93
        """
        client = self._find_client_helper(identifier)
        if client.verify_secret(secret):
            return client
        raise errors.UnauthorizedError(f"[LOGIN] Invalid secret.")
94

95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
    def validate_gitlab_token(self, token: str, username: str, throws: bool = True):
        """Validates gitlab access token using the gitlab client
        Args:
            token(str): Gitlab access token
            username(str): Username
            throws(bool): Throws an exception if the token is not valid
        Returns(Bool):
        """
        client = self.gitlab_factory.instance(oauth_token=token)
        client.auth()
        user = client.user
        if user.username != username:
            if throws:
                raise errors.InvalidGitlabAccessTokenError()
            return False
        return True

112
    def find_client(self, throw=True) -> Client:
113
        identifier = get_jwt_identity()
114
        return self._find_client_helper(identifier, throw=throw)
115

116
    def _find_client_helper(self, identifier: str, throw=True) -> Client:
117
        log.trace(f"[FIND] Finding client using identifier: {identifier}")
118
        client = self._rest_service.find.client(identifier, throws=False)
119
        if not client and throw:
120
121
            raise errors.UnauthorizedError(f"[LOGIN] Unknown client identifier {identifier}.")
        return client