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 raised as an 66 exception for the caller to deal with as appropriate (most likely 67 by failing). 68 * Any other value returned is taken as a valid response from the 69 server without making another request. In many cases, this can just 70 be the original exception. 71 """ 72 if exc.code == 401: 73 if self.connection._auth: 74 # Stored auth appears to be invalid, clear and retry 75 self.connection._auth = None 76 self.login(self.connection.get_option('remote_user'), self.connection.get_option('password')) 77 return True 78 else: 79 # Unauthorized and there's no token. Return an error 80 return False 81 82 return exc 83 84 @abstractmethod 85 def send_request(self, data, **message_kwargs): 86 """Prepares and sends request(s) to device.""" 87 pass 88