1# (c) 2018 Red Hat Inc.
2# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
3
4from __future__ import (absolute_import, division, print_function)
5__metaclass__ = type
6
7from abc import abstractmethod
8
9from ansible.plugins import AnsiblePlugin
10
11
12class HttpApiBase(AnsiblePlugin):
13    def __init__(self, connection):
14        super(HttpApiBase, self).__init__()
15
16        self.connection = connection
17        self._become = False
18        self._become_pass = ''
19
20    def set_become(self, become_context):
21        self._become = become_context.become
22        self._become_pass = getattr(become_context, 'become_pass') or ''
23
24    def login(self, username, password):
25        """Call a defined login endpoint to receive an authentication token.
26
27        This should only be implemented if the API has a single endpoint which
28        can turn HTTP basic auth into a token which can be reused for the rest
29        of the calls for the session.
30        """
31        pass
32
33    def logout(self):
34        """ Call to implement session logout.
35
36        Method to clear session gracefully e.g. tokens granted in login
37        need to be revoked.
38        """
39        pass
40
41    def update_auth(self, response, response_text):
42        """Return per-request auth token.
43
44        The response should be a dictionary that can be plugged into the
45        headers of a request. The default implementation uses cookie data.
46        If no authentication data is found, return None
47        """
48        cookie = response.info().get('Set-Cookie')
49        if cookie:
50            return {'Cookie': cookie}
51
52        return None
53
54    def handle_httperror(self, exc):
55        """Overridable method for dealing with HTTP codes.
56
57        This method will attempt to handle known cases of HTTP status codes.
58        If your API uses status codes to convey information in a regular way,
59        you can override this method to handle it appropriately.
60
61        :returns:
62            * True if the code has been handled in a way that the request
63            may be resent without changes.
64            * False if the error cannot be handled or recovered from by the
65            plugin. This will result in the HTTPError being returned to the
66            caller to deal with as appropriate.
67            * Any other value returned is taken as a valid response from the
68            server without making another request. In many cases, this can just
69            be the original exception.
70            """
71        if exc.code == 401 and self.connection._auth:
72            # Stored auth appears to be invalid, clear and retry
73            self.connection._auth = None
74            self.login(self.connection.get_option('remote_user'), self.connection.get_option('password'))
75            return True
76
77        return exc
78
79    @abstractmethod
80    def send_request(self, data, **message_kwargs):
81        """Prepares and sends request(s) to device."""
82        pass
83