summaryrefslogtreecommitdiff
path: root/tests/e2e/bonafide/cred_srp.py
blob: 9fcb8d9ef053aec7bc612c84722255f23f00210d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# -*- coding: utf-8 -*-
# srp_cred.py
# Copyright (C) 2015 LEAP
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

"""
Credential module for authenticating SRP requests against the LEAP platform.
"""

# ----------------- DOC ------------------------------------------------------
# See examples of cred modules:
# https://github.com/oubiwann-unsupported/txBrowserID/blob/master/browserid/checker.py
# http://stackoverflow.com/questions/19171686/book-twisted-network-programming-essentials-example-9-1-does-not-work
# ----------------- DOC ------------------------------------------------------

from zope.interface import implements, implementer, Interface

from twisted.cred import portal, credentials, error as credError
from twisted.cred.checkers import ICredentialsChecker
from twisted.internet import defer

from session import Session


@implementer(ICredentialsChecker)
class SRPCredentialsChecker(object):

    # TODO need to decide if the credentials that we pass here are per provider
    # or not.
    # I think it's better to have the credentials passed with the full user_id,
    # and here split user/provider.
    # XXX then we need to check if the provider is properly configured, to get
    # the right api info AND the needed certificates.
    # XXX might need to initialize credential checker with a ProviderAPI

    credentialInterfaces = (credentials.IUsernamePassword,)

    def requestAvatarId(self, credentials):
        # TODO If we are already authenticated, we should just
        # return the session object, somehow.
        # XXX If not authenticated (ie, no cached credentials?)
        # we pass credentials to srpauth.authenticate method
        # another srpauth class should interface with the blocking srpauth
        # library, and chain all the calls needed to do the handshake.
        # Therefore:
        # should keep reference to the srpauth instances somewhere
        # TODO If we want to return an anonymous user (useful for getting the
        # anon-vpn cert), we should return an empty tuple from here.

        return defer.maybeDeferred(_get_leap_session(credentials)).addCallback(
            self._check_srp_auth)

    def _check_srp_auth(session, username):
        if session.is_authenticated:
            # is ok! --- should add it to some global cache?
            return defer.succeed(username)
        else:
            return defer.fail(credError.UnauthorizedLogin(
                "Bad username/password combination"))


def _get_leap_session(credentials):
    session = Session(credentials)
    d = session.authenticate()
    d.addCallback(lambda _: session)
    return d


class ILeapUserAvatar(Interface):

    # TODO add attributes for username, uuid, token, session_id

    def logout():
        """
        Clean up per-login resource allocated to this avatar.
        """


@implementer(ILeapUserAvatar)
class LeapUserAvatar(object):

    # TODO initialize with: username, uuid, token, session_id
    # TODO initialize provider data (for api)
    # TODO how does this relate to LeapSession? maybe we should get one passed?

    def logout(self):

        # TODO reset the (global?) srpauth object.
        # https://leap.se/en/docs/design/bonafide#logout
        # DELETE API_BASE/logout(.json)
        pass


class LeapAuthRealm(object):
    """
    The realm corresponds to an application domain and is in charge of avatars,
    which are network-accessible business logic objects.
    """

    # TODO should be initialized with provider API objects.

    implements(portal.IRealm)

    def requestAvatar(self, avatarId, mind, *interfaces):

        if ILeapUserAvatar in interfaces:
            # XXX how should we get the details for the requested avatar?
            avatar = LeapUserAvatar()
            return ILeapUserAvatar, avatar, avatar.logout

        raise NotImplementedError(
            "This realm only supports the ILeapUserAvatar interface.")