Esempio n. 1
0
    def expire_token(self, token):
        """
        Given a token, makes a request to the authentication server to expire
        it immediately.  This is considered a responsible way to log out a
        user.  If you simply remove the session your application has for the
        user without expiring their token, the user is not _really_ logged out.

        :param token: The OAuth token you wish to expire
        :type token: str

        :returns: If the expiration attempt succeeded.
        :rtype: bool

        :raises ApiError: If the expiration attempt failed.
        """
        r = requests.post(self._login_uri("/oauth/token/expire"),
                          data={
                              "client_id": self.client_id,
                              "client_secret": self.client_secret,
                              "token": token,
                          })

        if r.status_code != 200:
            raise ApiError("Failed to expire token!", r)
        return True
Esempio n. 2
0
    def set_thumbnail(self, thumbnail):
        """
        Sets the thumbnail for this OAuth Client.  If thumbnail is bytes,
        uploads it as a png.  Otherwise, assumes thumbnail is a path to the
        thumbnail and reads it in as bytes before uploading.
        """
        headers = {
            "Authorization": "token {}".format(self._client.token),
            "Content-type": "image/png",
        }

        # TODO this check needs to be smarter - python2 doesn't do it right
        if not isinstance(thumbnail, bytes):
            with open(thumbnail, 'rb') as f:
                thumbnail = f.read()

        result = requests.put('{}/{}/thumbnail'.format(
            self._client.base_url,
            OAuthClient.api_endpoint.format(id=self.id)),
                              headers=headers,
                              data=thumbnail)

        if not result.status_code == 200:
            errors = []
            j = result.json()
            if 'errors' in j:
                errors = [e['reason'] for e in j['errors']]
            raise ApiError('{}: {}'.format(result.status_code, errors), json=j)

        return True
Esempio n. 3
0
    def upload_attachment(self, attachment):
        content = None
        with open(attachment) as f:
            content = f.read()

        if not content:
            raise ValueError('Nothing to upload!')

        headers = {
            "Authorization": "token {}".format(self._client.token),
            "Content-type": "multipart/form-data",
        }

        result = requests.post('{}{}/attachments'.format(self._client.base_url,
                SupportTicket.api_endpoint.format(id=self.id)),
                headers=headers, files=content)

        if not result.status_code == 200:
            errors = []
            j = result.json()
            if 'errors' in j:
                errors = [ e['reason'] for e in j['errors'] ]
            raise ApiError('{}: {}'.format(result.status_code, errors), json=j)

        return True
    def _api_call(self,
                  endpoint,
                  model=None,
                  method=None,
                  data=None,
                  filters=None):
        """
        Makes a call to the linode api.  Data should only be given if the method is
        POST or PUT, and should be a dictionary
        """
        if not self.token:
            raise RuntimeError("You do not have an API token!")

        if not method:
            raise ValueError("Method is required for API calls!")

        if model:
            endpoint = endpoint.format(**vars(model))
        url = '{}{}'.format(self.base_url, endpoint)
        headers = {
            'Authorization': "Bearer {}".format(self.token),
            'Content-Type': 'application/json',
            'User-Agent': self._user_agent,
        }

        if filters:
            headers['X-Filter'] = json.dumps(filters)

        body = None
        if data is not None:
            body = json.dumps(data)

        response = method(url, headers=headers, data=body)

        warning = response.headers.get('Warning', None)
        if warning:
            logger.warning('Received warning from server: {}'.format(warning))

        if 399 < response.status_code < 600:
            j = None
            error_msg = '{}: '.format(response.status_code)
            try:
                j = response.json()
                if 'errors' in j.keys():
                    for e in j['errors']:
                        error_msg += '{}; '.format(e['reason']) \
                                if 'reason' in e.keys() else ''
            except:
                pass
            raise ApiError(error_msg, status=response.status_code, json=j)

        if response.status_code != 204:
            j = response.json()
        else:
            j = None  # handle no response body

        return j
    def finish_oauth(self, code):
        """
        Given an OAuth Exchange Code, completes the OAuth exchange with the
        authentication server.  This should be called once the user has already
        been directed to the login_uri, and has been sent back after successfully
        authenticating.  For example, in `Flask`_, this might be implemented as
        a route like this::

           @app.route("/oauth-redirect")
           def oauth_redirect():
               exchange_code = request.args.get("code")
               login_client = LinodeLoginClient(client_id, client_secret)

               token, scopes = login_client.finish_oauth(exchange_code)

               # store the user's OAuth token in their session for later use
               # and mark that they are logged in.

               return redirect("/")

        .. _Flask: http://flask.pocoo.org

        :param code: The OAuth Exchange Code returned from the authentication
                     server in the query string.
        :type code: str

        :returns: The new OAuth token, and a list of scopes the token has, when
                  the token expires, and a refresh token that can generate a new
                  valid token when this one is expired.
        :rtype: tuple(str, list)

        :raise ApiError: If the OAuth exchange fails.
        """
        r = requests.post(self._login_uri("/oauth/token"),
                          data={
                              "code": code,
                              "client_id": self.client_id,
                              "client_secret": self.client_secret
                          })

        if r.status_code != 200:
            raise ApiError("OAuth token exchange failed",
                           status=r.status_code,
                           json=r.json())

        token = r.json()["access_token"]
        scopes = OAuthScopes.parse(r.json()["scopes"])
        expiry = datetime.now() + timedelta(seconds=r.json()['expires_in'])
        refresh_token = r.json()['refresh_token']

        return token, scopes, expiry, refresh_token
Esempio n. 6
0
    def thumbnail(self, dump_to=None):
        """
        This returns binary data that represents a 128x128 image.
        If dump_to is given, attempts to write the image to a file
        at the given location.
        """
        headers = {"Authorization": "token {}".format(self._client.token)}

        result = requests.get('{}/{}/thumbnail'.format(
            self._client.base_url,
            OAuthClient.api_endpoint.format(id=self.id)),
                              headers=headers)

        if not result.status_code == 200:
            raise ApiError('No thumbnail found for OAuthClient {}'.format(
                self.id))

        if dump_to:
            with open(dump_to, 'wb+') as f:
                f.write(result.content)
        return result.content
    def refresh_oauth_token(self, refresh_token):
        """
        Some tokens are generated with refresh tokens (namely tokens generated
        through an OAuth Exchange).  These tokens may be renewed, or "refreshed",
        with the auth server, generating a new OAuth Token with a new (later)
        expiry.  This method handles refreshing an OAuth Token using the refresh
        token that was generated at the time of its issuance, and returns a new
        OAuth token and refresh token for the same client and user.

        :param refresh_token: The refresh token returned for the OAuth Token we
                              are renewing.
        :type refresh_token: str

        :returns: The new OAuth token, and a list of scopes the token has, when
                  the token expires, and a refresh token that can generate a new
                  valid token when this one is expired.
        :rtype: tuple(str, list)

        :raise ApiError: If the refresh fails..
        """
        r = requests.post(self._login_uri("/oauth/token"),
                          data={
                              "grant_type": "refresh_token",
                              "client_id": self.client_id,
                              "client_secret": self.client_secret,
                              "refresh_token": refresh_token,
                          })

        if r.status_code != 200:
            raise ApiError("Refresh failed", r)

        token = r.json()["access_token"]
        scopes = OAuthScopes.parse(r.json()["scopes"])
        expiry = datetime.now() + timedelta(seconds=r.json()['expires_in'])
        refresh_token = r.json()['refresh_token']

        return token, scopes, expiry, refresh_token