<commit_before>from __future__ import absolute_import

import json
import flask
import requests

try:
    from urlparse import urljoin
except ImportError:
    from urllib.parse import urljoin

from .oauth import OAuthBase

import solvebio


class SolveBioAuth(OAuthBase):
    """Handles OAuth2 flows with the SolveBio API."""
    AUTH_COOKIE_NAME = 'dash_solvebio_auth'
    TOKEN_COOKIE_NAME = 'solvebio_oauth_token'

    OAUTH2_TOKEN_URL = urljoin(
        solvebio.api_host, '/v1/oauth2/token')
    OAUTH2_REVOKE_TOKEN_URL = urljoin(
        solvebio.api_host, '/v1/oauth2/revoke_token')
    DEFAULT_SOLVEBIO_URL = 'https://my.solvebio.com'
    DEFAULT_GRANT_TYPE = 'authorization_code'

    def __init__(self, app, app_url, client_id, **kwargs):
        super(SolveBioAuth, self).__init__(app, app_url, client_id)

        # Add logout URL
        app.server.add_url_rule(
            '{}_dash-logout'.format(app.config['routes_pathname_prefix']),
            view_func=self.logout,
            methods=['get']
        )

        self._oauth_redirect_uri = urljoin(
            self._app_url,
            '{}_oauth-redirect'.format(
                self._app.config['requests_pathname_prefix']))

        # Handle optional parameters
        self._oauth_client_secret = kwargs.get('client_secret')
        self._solvebio_url = \
            kwargs.get('solvebio_url') or self.DEFAULT_SOLVEBIO_URL
        self._oauth_grant_type = \
            kwargs.get('grant_type') or self.DEFAULT_GRANT_TYPE
        if self._oauth_grant_type == 'implicit':
            self._oauth_response_type = 'token'
        elif self._oauth_grant_type == 'authorization_code':
            self._oauth_response_type = 'code'
        else:
            raise Exception(
                'SolveBioAuth Error: Unsupported grant type "{}"'
                .format(self._oauth_grant_type))

    def html(self, script):
        return ('''
            <!doctype html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <title>Log In</title>
            </head>
            <body>
              <div id="react-root"></div>
            </body>
            <script id="_auth-config" type="application/json">
            {}
            </script>
            <script type="text/javascript">{}</script>
            </html>
        '''.format(json.dumps({
            'oauth_client_id': self._oauth_client_id,
            'oauth_response_type': self._oauth_response_type,
            'oauth_state': self._access_codes['access_granted'],
            'solvebio_url': self._solvebio_url,
            'requests_pathname_prefix':
            self._app.config['requests_pathname_prefix']
        }), script))

    def check_view_access(self, oauth_token):
        client = solvebio.SolveClient(token=oauth_token, token_type='Bearer')
        try:
            client.User.retrieve()
            return True
        except:
            return False

    def login_api(self):
        oauth_data = flask.request.get_json()

        if self._oauth_grant_type == 'authorization_code':
            # Authorization Code flow
            auth_code = oauth_data['code']

            # Request the access token with the auth code
            oauth_data = requests.post(
                self.OAUTH2_TOKEN_URL,
                data={
                    'client_id': self._oauth_client_id,
                    'grant_type': self._oauth_grant_type,
                    'redirect_uri': self._oauth_redirect_uri,
                    'code': auth_code
                }).json()
        else:
            raise Exception(
                'SolveBio Auth Error: unsupported grant type "{}"'
                .format(self._oauth_grant_type))

        # Implicit flow returns the access_token in the initial redirect.
        # TODO: Support refresh tokens for authorization code flow.
        oauth_token = oauth_data['access_token']
        client = solvebio.SolveClient(token=oauth_token, token_type='Bearer')
        user = client.User.retrieve()
        response = flask.Response(
            json.dumps(user),
            mimetype='application/json',
            status=200
        )

        self.set_cookie(
            response=response,
            name=self.TOKEN_COOKIE_NAME,
            value=oauth_token,
            max_age=None
        )

        return response

    def logout(self):
        """Revoke the token and remove the cookie."""
        if self._oauth_client_secret:
            try:
                oauth_token = flask.request.cookies[self.TOKEN_COOKIE_NAME]
                # Revoke the token
                requests.post(
                    self.OAUTH2_REVOKE_TOKEN_URL,
                    data={
                        'client_id': self._oauth_client_id,
                        'client_secret': self._oauth_client_secret,
                        'token': oauth_token
                    })
            except:
                pass

        response = flask.redirect('/')
        self.clear_cookies(response)<commit_msg>include additional oauth error response content in the view (#231)<commit_after>from __future__ import absolute_import

import json
import flask
import requests

try:
    from urlparse import urljoin
except ImportError:
    from urllib.parse import urljoin

from .oauth import OAuthBase

import solvebio


class SolveBioAuth(OAuthBase):
    """Handles OAuth2 flows with the SolveBio API."""
    AUTH_COOKIE_NAME = 'dash_solvebio_auth'
    TOKEN_COOKIE_NAME = 'solvebio_oauth_token'

    DEFAULT_SOLVEBIO_URL = 'https://my.solvebio.com'
    DEFAULT_GRANT_TYPE = 'authorization_code'

    OAUTH2_TOKEN_PATH = '/v1/oauth2/token'
    OAUTH2_REVOKE_TOKEN_PATH = '/v1/oauth2/revoke_token'

    def __init__(self, app, app_url, client_id, **kwargs):
        super(SolveBioAuth, self).__init__(app, app_url, client_id)

        # Add logout URL
        app.server.add_url_rule(
            '{}_dash-logout'.format(app.config['routes_pathname_prefix']),
            view_func=self.logout,
            methods=['get']
        )

        self._oauth_redirect_uri = urljoin(
            self._app_url,
            '{}_oauth-redirect'.format(
                self._app.config['requests_pathname_prefix']))

        # Handle optional parameters
        self._solvebio_url = \
            kwargs.get('solvebio_url') or self.DEFAULT_SOLVEBIO_URL
        self._api_host = kwargs.get('api_host') or solvebio.api_host
        self._oauth_client_secret = kwargs.get('client_secret')
        self._oauth_grant_type = \
            kwargs.get('grant_type') or self.DEFAULT_GRANT_TYPE

        if self._oauth_grant_type == 'implicit':
            self._oauth_response_type = 'token'
        elif self._oauth_grant_type == 'authorization_code':
            self._oauth_response_type = 'code'
        else:
            raise Exception(
                'SolveBioAuth Error: Unsupported grant type "{}"'
                .format(self._oauth_grant_type))

    def html(self, script):
        return ('''
            <!doctype html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <title>Log In</title>
            </head>
            <body>
              <div id="react-root"></div>
            </body>
            <script id="_auth-config" type="application/json">
            {}
            </script>
            <script type="text/javascript">{}</script>
            </html>
        '''.format(json.dumps({
            'oauth_client_id': self._oauth_client_id,
            'oauth_response_type': self._oauth_response_type,
            'oauth_state': self._access_codes['access_granted'],
            'solvebio_url': self._solvebio_url,
            'requests_pathname_prefix':
            self._app.config['requests_pathname_prefix']
        }), script))

    def check_view_access(self, oauth_token):
        client = solvebio.SolveClient(token=oauth_token, token_type='Bearer')
        try:
            client.User.retrieve()
            return True
        except:
            return False

    def login_api(self):
        oauth_data = flask.request.get_json()

        if self._oauth_grant_type == 'authorization_code':
            # Authorization Code flow
            auth_code = oauth_data['code']

            # Request the access token with the auth code
            oauth_data = requests.post(
                urljoin(self._api_host, self.OAUTH2_TOKEN_PATH),
                data={
                    'client_id': self._oauth_client_id,
                    'grant_type': self._oauth_grant_type,
                    'redirect_uri': self._oauth_redirect_uri,
                    'code': auth_code
                }).json()
        else:
            raise Exception(
                'SolveBio Auth Error: unsupported grant type "{}"'
                .format(self._oauth_grant_type))

        # Implicit flow returns the access_token in the initial redirect.
        # TODO: Support refresh tokens for authorization code flow.
        oauth_token = oauth_data.get('access_token')
        if not oauth_token:
            # Return the error response to the frontend view
            return flask.Response(
                json.dumps(oauth_data),
                mimetype='application/json',
                status=500
            )

        client = solvebio.SolveClient(token=oauth_token, token_type='Bearer')
        user = client.User.retrieve()
        response = flask.Response(
            json.dumps(user),
            mimetype='application/json',
            status=200
        )

        self.set_cookie(
            response=response,
            name=self.TOKEN_COOKIE_NAME,
            value=oauth_token,
            max_age=None
        )

        return response

    def logout(self):
        """Revoke the token and remove the cookie."""
        if self._oauth_client_secret:
            try:
                oauth_token = flask.request.cookies[self.TOKEN_COOKIE_NAME]
                # Revoke the token
                requests.post(
                    urljoin(self._api_host, self.OAUTH2_REVOKE_TOKEN_PATH),
                    data={
                        'client_id': self._oauth_client_id,
                        'client_secret': self._oauth_client_secret,
                        'token': oauth_token
                    })
            except:
                pass

        response = flask.redirect('/')
        self.clear_cookies(response)
{'fraction_non_alphanumeric': 0.09527913434836732, 'fraction_numerical': 0.0030642535669826677, 'mean_word_length': 1.8668679659621192, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 35, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2542304', 'n_tokens_mistral': 3106, 'n_tokens_neox': 2946, 'n_words': 558}