Beispiel #1
0
def make_twitch_blueprint(
    client_id=None,
    client_secret=None,
    *,
    scope=None,
    redirect_url=None,
    redirect_to=None,
    login_url=None,
    authorized_url=None,
    session_class=ClientIdHeaderOAuth2Session,
    storage=None,
    rule_kwargs=None,
):
    """Make a blueprint for authenticating with Twitch using OAuth 2.

    This requires a client ID and client secret from Twitch.
    You should either pass them to this constructor, or make sure that your
    Flask application config defines them, using the variables
    :envvar:`TWITCH_OAUTH_CLIENT_ID` and :envvar:`TWITCH_OAUTH_CLIENT_SECRET`.

    Args:
        client_id (str): The client ID for your application on Twitch.
            Defaults to app config "TWITCH_OAUTH_CLIENT_ID".
        client_secret (str): The client Secret for your application on Twitch.
            Defaults to app config "TWITCH_OAUTH_CLIENT_SECRET".
        scope (list, optional): Comma-separated list of scopes for the OAuth token.
            Defaults to None.
        redirect_url (str): the URL to redirect to after the authentication
            dance is complete
        redirect_to (str): if ``redirect_url`` is not defined, the name of the
            view to redirect to after the authentication dance is complete.
            The actual URL will be determined by :func:`flask.url_for`
        login_url (str, optional): the URL path for the ``login`` view.
            Defaults to ``/twitch``
        authorized_url (str, optional): the URL path for the ``authorized`` view.
            Defaults to ``/twitch/authorized``.
        session_class (class, optional): The class to use for creating a
            Requests session. Defaults to
            :class:`~flask_dance.contrib.twitch.ClientIdHeaderOAuth2Session`.
        storage: A token storage class, or an instance of a token storage
                class, to use for this blueprint. Defaults to
                :class:`~flask_dance.consumer.storage.session.SessionStorage`.
        rule_kwargs (dict, optional): Additional arguments that should be passed when adding
            the login and authorized routes. Defaults to ``None``.

    Returns:
        :class:`~flask_dance.consumer.OAuth2ConsumerBlueprint` A :doc:`blueprint <flask:blueprints>` to attach to your Flask app.
    """
    twitch_bp = OAuth2ConsumerBlueprint(
        "twitch",
        __name__,
        client_id=client_id,
        client_secret=client_secret,
        scope=scope,
        base_url="https://api.twitch.tv/helix/",
        authorization_url="https://id.twitch.tv/oauth2/authorize",
        token_url="https://id.twitch.tv/oauth2/token",
        token_url_params={"include_client_id": True},
        redirect_url=redirect_url,
        redirect_to=redirect_to,
        login_url=login_url,
        authorized_url=authorized_url,
        session_class=session_class,
        storage=storage,
        rule_kwargs=rule_kwargs,
    )

    twitch_bp.from_config["client_id"] = "TWITCH_OAUTH_CLIENT_ID"
    twitch_bp.from_config["client_secret"] = "TWITCH_OAUTH_CLIENT_SECRET"

    # TODO: The key won't auto renew. See https://github.com/singingwolfboy/flask-dance/issues/35
    # I think this will work but needs a test.
    twitch_bp.auto_refresh_url = twitch_bp.token_url
    twitch_bp.auto_refresh_kwargs = {
        "client_id": twitch_bp.client_id,
        "client_secret": twitch_bp.client_secret,
    }

    @twitch_bp.before_app_request
    def set_applocal_session():
        ctx = stack.top
        ctx.twitch_oauth = twitch_bp.session

    return twitch_bp
Beispiel #2
0
def make_github_blueprint(
    client_id=None,
    client_secret=None,
    scope=None,
    redirect_url=None,
    redirect_to=None,
    login_url=None,
    authorized_url=None,
    session_class=None,
    backend=None,
    storage=None,
):
    """
    Make a blueprint for authenticating with GitHub using OAuth 2. This requires
    a client ID and client secret from GitHub. You should either pass them to
    this constructor, or make sure that your Flask application config defines
    them, using the variables GITHUB_OAUTH_CLIENT_ID and GITHUB_OAUTH_CLIENT_SECRET.

    Args:
        client_id (str): The client ID for your application on GitHub.
        client_secret (str): The client secret for your application on GitHub
        scope (str, optional): comma-separated list of scopes for the OAuth token
        redirect_url (str): the URL to redirect to after the authentication
            dance is complete
        redirect_to (str): if ``redirect_url`` is not defined, the name of the
            view to redirect to after the authentication dance is complete.
            The actual URL will be determined by :func:`flask.url_for`
        login_url (str, optional): the URL path for the ``login`` view.
            Defaults to ``/github``
        authorized_url (str, optional): the URL path for the ``authorized`` view.
            Defaults to ``/github/authorized``.
        session_class (class, optional): The class to use for creating a
            Requests session. Defaults to
            :class:`~flask_dance.consumer.requests.OAuth2Session`.
        storage: A token storage class, or an instance of a token storage
                class, to use for this blueprint. Defaults to
                :class:`~flask_dance.consumer.storage.session.SessionStorage`.

    :rtype: :class:`~flask_dance.consumer.OAuth2ConsumerBlueprint`
    :returns: A :ref:`blueprint <flask:blueprints>` to attach to your Flask app.
    """
    github_bp = OAuth2ConsumerBlueprint(
        "github",
        __name__,
        client_id=client_id,
        client_secret=client_secret,
        scope=scope,
        base_url="https://api.github.com/",
        authorization_url="https://github.com/login/oauth/authorize",
        token_url="https://github.com/login/oauth/access_token",
        redirect_url=redirect_url,
        redirect_to=redirect_to,
        login_url=login_url,
        authorized_url=authorized_url,
        session_class=session_class,
        backend=backend,
        storage=storage,
    )
    github_bp.from_config["client_id"] = "GITHUB_OAUTH_CLIENT_ID"
    github_bp.from_config["client_secret"] = "GITHUB_OAUTH_CLIENT_SECRET"

    @github_bp.before_app_request
    def set_applocal_session():
        ctx = stack.top
        ctx.github_oauth = github_bp.session

    return github_bp
Beispiel #3
0
def create_app(oidc_blueprint=None):
    app = Flask(__name__)
    app.wsgi_app = ProxyFix(app.wsgi_app,
                            x_for=1,
                            x_proto=1,
                            x_host=1,
                            x_port=1,
                            x_prefix=1)
    app.secret_key = "8210f566-4981-11ea-92d1-f079596e599b"
    app.config.from_json('config.json')
    settings = Settings(app.config)
    cred = Credentials(settings.db_url)
    infra = Infrastructures(settings.db_url)

    toscaTemplates = utils.loadToscaTemplates(settings.toscaDir)
    toscaInfo = utils.extractToscaInfo(settings.toscaDir,
                                       settings.toscaParamsDir, toscaTemplates)

    app.jinja_env.filters['tojson_pretty'] = utils.to_pretty_json
    app.logger.debug("TOSCA INFO: " + json.dumps(toscaInfo))

    loglevel = app.config.get("LOG_LEVEL") if app.config.get(
        "LOG_LEVEL") else "INFO"

    numeric_level = getattr(logging, loglevel.upper(), None)
    if not isinstance(numeric_level, int):
        raise ValueError('Invalid log level: %s' % loglevel)

    logging.basicConfig(level=numeric_level)

    oidc_base_url = app.config['OIDC_BASE_URL']
    oidc_token_url = oidc_base_url + '/token'
    oidc_refresh_url = oidc_base_url + '/token'
    oidc_authorization_url = oidc_base_url + '/authorize'

    if not oidc_blueprint:
        oidc_blueprint = OAuth2ConsumerBlueprint(
            "oidc",
            __name__,
            client_id=app.config['OIDC_CLIENT_ID'],
            client_secret=app.config['OIDC_CLIENT_SECRET'],
            scope=app.config['OIDC_SCOPES'],
            base_url=oidc_base_url,
            token_url=oidc_token_url,
            auto_refresh_url=oidc_refresh_url,
            authorization_url=oidc_authorization_url,
            redirect_to='home')
    app.register_blueprint(oidc_blueprint, url_prefix="/login")

    @app.before_request
    def before_request_checks():
        if 'external_links' not in session:
            session['external_links'] = settings.external_links
        g.analytics_tag = settings.analytics_tag
        g.settings = settings

    def authorized_with_valid_token(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):

            try:
                if not oidc_blueprint.session.authorized or 'username' not in session:
                    return redirect(url_for('login'))

                if oidc_blueprint.session.token['expires_in'] < 20:
                    app.logger.debug("Force refresh token")
                    oidc_blueprint.session.get('/userinfo')
            except (InvalidTokenError, TokenExpiredError):
                flash("Token expired.", 'warning')
                return redirect(url_for('login'))

            return f(*args, **kwargs)

        return decorated_function

    @app.route('/settings')
    @authorized_with_valid_token
    def show_settings():
        return render_template('settings.html',
                               oidc_url=settings.oidcUrl,
                               im_url=settings.imUrl)

    @app.route('/login')
    def login():
        session.clear()
        return render_template('home.html', oidc_name=settings.oidcName)

    @app.route('/')
    def home():
        if not oidc_blueprint.session.authorized:
            return redirect(url_for('login'))

        try:
            account_info = oidc_blueprint.session.get(
                urlparse(settings.oidcUrl)[2] + "/userinfo")
        except (InvalidTokenError, TokenExpiredError):
            flash("Token expired.", 'warning')
            return redirect(url_for('login'))

        if account_info.ok:
            account_info_json = account_info.json()

            session["vos"] = None
            if 'eduperson_entitlement' in account_info_json:
                session["vos"] = utils.getUserVOs(
                    account_info_json['eduperson_entitlement'])

            if settings.oidcGroups:
                user_groups = []
                if 'groups' in account_info_json:
                    user_groups = account_info_json['groups']
                elif 'eduperson_entitlement' in account_info_json:
                    user_groups = account_info_json['eduperson_entitlement']
                if not set(settings.oidcGroups).issubset(user_groups):
                    app.logger.debug(
                        "No match on group membership. User group membership: "
                        + json.dumps(user_groups))
                    message = Markup(
                        'You need to be a member of the following groups: {0}. <br>'
                        ' Please, visit <a href="{1}">{1}</a> and apply for the requested '
                        'membership.'.format(json.dumps(settings.oidcGroups),
                                             settings.oidcUrl))
                    raise Forbidden(description=message)

            session['userid'] = account_info_json['sub']
            if 'name' in account_info_json:
                session['username'] = account_info_json['name']
            else:
                session['username'] = ""
                if 'given_name' in account_info_json:
                    session['username'] = account_info_json['given_name']
                if 'family_name' in account_info_json:
                    session[
                        'username'] += " " + account_info_json['family_name']
                if session['username'] == "":
                    session['username'] = account_info_json['sub']
            if 'email' in account_info_json:
                session['gravatar'] = utils.avatar(account_info_json['email'],
                                                   26)
            else:
                session['gravatar'] = utils.avatar(account_info_json['sub'],
                                                   26)

            return render_template('portfolio.html', templates=toscaInfo)
        else:
            flash("Error getting User info: \n" + account_info.text, 'error')
            return render_template('home.html', oidc_name=settings.oidcName)

    @app.route('/vminfo/<infid>/<vmid>')
    @authorized_with_valid_token
    def showvminfo(infid=None, vmid=None):
        access_token = oidc_blueprint.session.token['access_token']

        auth_data = utils.getUserAuthData(access_token, cred,
                                          session["userid"])
        headers = {"Authorization": auth_data, "Accept": "application/json"}

        url = "%s/infrastructures/%s/vms/%s" % (settings.imUrl, infid, vmid)
        response = requests.get(url, headers=headers)

        vminfo = {}
        state = ""
        nets = ""
        deployment = ""
        if not response.ok:
            flash("Error retrieving VM info: \n" + response.text, 'error')
        else:
            app.logger.debug("VM Info: %s" % response.text)
            vminfo = utils.format_json_radl(response.json()["radl"])
            if "cpu.arch" in vminfo:
                del vminfo["cpu.arch"]
            if "state" in vminfo:
                state = vminfo["state"]
                del vminfo["state"]
            if "provider.type" in vminfo:
                deployment = vminfo["provider.type"]
                del vminfo["provider.type"]
            if "provider.host" in vminfo:
                if "provider.port" in vminfo:
                    deployment += ": %s:%s" % (vminfo["provider.host"],
                                               vminfo["provider.port"])
                    del vminfo["provider.port"]
                else:
                    deployment += ": " + vminfo["provider.host"]
                del vminfo["provider.host"]

            cont = 0
            while "net_interface.%s.ip" % cont in vminfo:
                if cont > 0:
                    nets += Markup('<br/>')
                nets += Markup('<i class="fa fa-network-wired"></i>')
                nets += " %s: %s" % (cont,
                                     vminfo["net_interface.%s.ip" % cont])
                del vminfo["net_interface.%s.ip" % cont]
                cont += 1

            cont = 0
            while "net_interface.%s.connection" % cont in vminfo:
                del vminfo["net_interface.%s.connection" % cont]
                cont += 1

            for elem in vminfo:
                if elem.endswith("size") and isinstance(vminfo[elem], int):
                    vminfo[elem] = "%d GB" % (vminfo[elem] / 1073741824)

        return render_template('vminfo.html',
                               infid=infid,
                               vmid=vmid,
                               vminfo=vminfo,
                               state=state,
                               nets=nets,
                               deployment=deployment)

    @app.route('/managevm/<op>/<infid>/<vmid>')
    @authorized_with_valid_token
    def managevm(op=None, infid=None, vmid=None):
        access_token = oidc_blueprint.session.token['access_token']

        auth_data = utils.getUserAuthData(access_token, cred,
                                          session["userid"])
        headers = {"Authorization": auth_data, "Accept": "application/json"}

        op = op.lower()
        if op in ["stop", "start", "reboot"]:
            url = "%s/infrastructures/%s/vms/%s/%s" % (settings.imUrl, infid,
                                                       vmid, op)
            response = requests.put(url, headers=headers)
        elif op == "terminate":
            url = "%s/infrastructures/%s/vms/%s" % (settings.imUrl, infid,
                                                    vmid)
            response = requests.delete(url, headers=headers)
        else:
            flash("Error: invalid operation: %s." % op, 'error')
            return redirect(url_for('showinfrastructures'))

        if response.ok:
            flash("Operation '%s' successfully made on VM ID: %s" % (op, vmid),
                  'info')
        else:
            flash(
                "Error making %s op on VM %s: \n%s" %
                (op, vmid, response.text), 'error')

        if op == "terminate":
            return redirect(url_for('showinfrastructures'))
        else:
            return redirect(url_for('showvminfo', infid=infid, vmid=vmid))

    @app.route('/infrastructures')
    @authorized_with_valid_token
    def showinfrastructures():
        access_token = oidc_blueprint.session.token['access_token']

        auth_data = utils.getUserAuthData(access_token, cred,
                                          session["userid"])
        headers = {"Authorization": auth_data, "Accept": "application/json"}

        url = "%s/infrastructures" % settings.imUrl
        response = requests.get(url, headers=headers)

        infrastructures = {}
        if not response.ok:
            flash("Error retrieving infrastructure list: \n" + response.text,
                  'error')
        else:
            app.logger.debug("Infrastructures: %s" % response.text)
            state_res = response.json()
            if "uri-list" in state_res:
                inf_id_list = [elem["uri"] for elem in state_res["uri-list"]]
            else:
                inf_id_list = []
            for inf_id in inf_id_list:
                url = "%s/state" % inf_id
                response = requests.get(url, headers=headers)
                if not response.ok:
                    flash(
                        "Error retrieving infrastructure %s state: \n%s" %
                        (inf_id, response.text), 'warning')
                else:
                    inf_state = response.json()
                    infrastructures[os.path.basename(
                        inf_id)] = inf_state['state']

                    try:
                        infra_name = infra.get_infra(
                            os.path.basename(inf_id))["name"]
                    except Exception:
                        infra_name = ""

                    infrastructures[os.path.basename(
                        inf_id)]['name'] = infra_name

        return render_template('infrastructures.html',
                               infrastructures=infrastructures)

    @app.route('/reconfigure/<infid>')
    @authorized_with_valid_token
    def infreconfigure(infid=None):
        access_token = oidc_blueprint.session.token['access_token']
        auth_data = utils.getUserAuthData(access_token, cred,
                                          session["userid"])
        headers = {"Authorization": auth_data}

        url = "%s/infrastructures/%s/reconfigure" % (settings.imUrl, infid)
        response = requests.put(url, headers=headers)

        if response.ok:
            flash("Infrastructure successfuly reconfigured.", "info")
        else:
            flash("Error reconfiguring Infrastructure: \n" + response.text,
                  "error")

        return redirect(url_for('showinfrastructures'))

    @app.route('/template/<infid>')
    @authorized_with_valid_token
    def template(infid=None):
        access_token = oidc_blueprint.session.token['access_token']
        auth_data = utils.getUserAuthData(access_token, cred,
                                          session["userid"])
        headers = {"Authorization": auth_data}

        url = "%s/infrastructures/%s/tosca" % (settings.imUrl, infid)
        response = requests.get(url, headers=headers)

        if not response.ok:
            flash("Error getting template: \n" + response.text, "error")
            template = ""
        else:
            template = response.text
        return render_template('deptemplate.html', template=template)

    @app.route('/log/<infid>')
    @authorized_with_valid_token
    def inflog(infid=None):
        access_token = oidc_blueprint.session.token['access_token']
        auth_data = utils.getUserAuthData(access_token, cred,
                                          session["userid"])
        headers = {"Authorization": auth_data}

        url = "%s/infrastructures/%s/contmsg" % (settings.imUrl, infid)
        response = requests.get(url, headers=headers, verify=False)

        if not response.ok:
            log = "Not found"
        else:
            log = response.text
        return render_template('inflog.html', log=log)

    @app.route('/vmlog/<infid>/<vmid>')
    @authorized_with_valid_token
    def vmlog(infid=None, vmid=None):

        access_token = oidc_blueprint.session.token['access_token']
        auth_data = utils.getUserAuthData(access_token, cred,
                                          session["userid"])
        headers = {"Authorization": auth_data}

        url = "%s/infrastructures/%s/vms/%s/contmsg" % (settings.imUrl, infid,
                                                        vmid)
        response = requests.get(url, headers=headers, verify=False)

        if not response.ok:
            log = "Not found"
        else:
            log = response.text
        return render_template('inflog.html', log=log, vmid=vmid)

    @app.route('/outputs/<infid>')
    @authorized_with_valid_token
    def infoutputs(infid=None):

        access_token = oidc_blueprint.session.token['access_token']
        auth_data = utils.getUserAuthData(access_token, cred,
                                          session["userid"])
        headers = {"Authorization": auth_data}

        url = "%s/infrastructures/%s/outputs" % (settings.imUrl, infid)
        response = requests.get(url, headers=headers, verify=False)

        if not response.ok:
            outputs = {}
        else:
            outputs = response.json()["outputs"]
            for elem in outputs:
                if isinstance(outputs[elem],
                              str) and (outputs[elem].startswith('http://') or
                                        outputs[elem].startswith('https://')):
                    outputs[elem] = Markup(
                        "<a href='%s' target='_blank'>%s</a>" %
                        (outputs[elem], outputs[elem]))

        return render_template('outputs.html', infid=infid, outputs=outputs)

    @app.route('/delete/<infid>/<force>')
    @authorized_with_valid_token
    def infdel(infid=None, force=0):
        access_token = oidc_blueprint.session.token['access_token']
        auth_data = utils.getUserAuthData(access_token, cred,
                                          session["userid"])
        headers = {"Authorization": auth_data}

        url = "%s/infrastructures/%s?async=1" % (settings.imUrl, infid)
        if force:
            url += "&force=1"
        response = requests.delete(url, headers=headers)

        if not response.ok:
            flash("Error deleting infrastructure: " + response.text, "error")
        else:
            flash("Infrastructure '%s' successfuly deleted." % infid, "info")
            try:
                infra.delete_infra(infid)
            except Exception as ex:
                flash("Error deleting infrastructure name: %s" + str(ex),
                      "warning")

        return redirect(url_for('showinfrastructures'))

    @app.route('/configure')
    @authorized_with_valid_token
    def configure():

        selected_tosca = request.args['selected_tosca']

        app.logger.debug("Template: " + json.dumps(toscaInfo[selected_tosca]))

        vos = utils.getStaticVOs()
        vos.extend(appdb.get_vo_list())
        vos = list(set(vos))
        if session["vos"]:
            vos = [vo for vo in vos if vo in session["vos"]]

        return render_template('createdep.html',
                               template=toscaInfo[selected_tosca],
                               selectedTemplate=selected_tosca,
                               vos=vos)

    @app.route('/sites/<vo>')
    def getsites(vo=None):
        res = ""
        appdb_sites = appdb.get_sites(vo)
        for site_name, (_, critical, _) in appdb_sites.items():
            if critical:
                critical = " (WARNING: %s state!)" % critical
            res += '<option name="selectedSite" value=%s>%s%s</option>' % (
                site_name, site_name, critical)

        for site_name, _ in utils.getStaticSites(vo).items():
            # avoid site duplication
            if site_name not in appdb_sites:
                res += '<option name="selectedSite" value=%s>%s</option>' % (
                    site_name, site_name)

        return res

    @app.route('/images/<site>/<vo>')
    def getimages(site=None, vo=None):
        res = ""
        if vo == "local":
            access_token = oidc_blueprint.session.token['access_token']
            for image_name, image_id in utils.get_site_images(
                    site, vo, access_token, cred, session["userid"]):
                res += '<option name="selectedSiteImage" value=%s>%s</option>' % (
                    image_id, image_name)
        else:
            for image in appdb.get_images(site, vo):
                res += '<option name="selectedImage" value=%s>%s</option>' % (
                    image, image)
        return res

    def add_image_to_template(template, image):
        # Add the image to all compute nodes

        for node in list(
                template['topology_template']['node_templates'].values()):
            if node["type"] == "tosca.nodes.indigo.Compute":
                node["capabilities"]["os"]["properties"]["image"] = image

        app.logger.debug(yaml.dump(template, default_flow_style=False))

        return template

    def add_auth_to_template(template, auth_data):
        # Add the auth_data ElasticCluster node

        for node in list(
                template['topology_template']['node_templates'].values()):
            if node["type"] == "tosca.nodes.ec3.ElasticCluster":
                if "properties" not in node:
                    node["properties"] = {}
                node["properties"]["im_auth"] = auth_data

        app.logger.debug(yaml.dump(template, default_flow_style=False))

        return template

    def set_inputs_to_template(template, inputs):
        # Add the image to all compute nodes

        for name, value in template['topology_template']['inputs'].items():
            if name in inputs:
                if value["type"] == "integer":
                    value["default"] = int(inputs[name])
                elif value["type"] == "float":
                    value["default"] = float(inputs[name])
                elif value["type"] == "boolean":
                    if inputs[name].lower() in ['yes', 'true', '1']:
                        value["default"] = True
                    else:
                        value["default"] = False
                # Special case for ports, convert a comma separated list of ints
                # to a PortSpec map
                elif value["type"] == "map" and name == "ports":
                    ports = inputs[name].split(",")
                    ports_value = {}
                    for port in ports:
                        # Should we also open UDP?
                        ports_value["port_%s" % port] = {
                            "protocol": "tcp",
                            "source": int(port)
                        }
                    value["default"] = ports_value
                else:
                    value["default"] = inputs[name]

        app.logger.debug(yaml.dump(template, default_flow_style=False))
        return template

    @app.route('/submit', methods=['POST'])
    @authorized_with_valid_token
    def createdep():

        form_data = request.form.to_dict()
        vo = form_data['extra_opts.selectedVO']
        site = form_data['extra_opts.selectedSite']

        access_token = oidc_blueprint.session.token['access_token']
        auth_data = utils.getUserAuthData(access_token, cred,
                                          session["userid"], vo, site)

        app.logger.debug("Form data: " + json.dumps(request.form.to_dict()))

        with io.open(settings.toscaDir +
                     request.args.get('template')) as stream:
            template = yaml.full_load(stream)

            if form_data['extra_opts.selectedImage'] != "":
                image = "appdb://%s/%s?%s" % (
                    form_data['extra_opts.selectedSite'],
                    form_data['extra_opts.selectedImage'],
                    form_data['extra_opts.selectedVO'])
            elif form_data['extra_opts.selectedSiteImage'] != "":
                site_url = utils.get_ost_image_url(
                    form_data['extra_opts.selectedSite'])
                image = "ost://%s/%s" % (
                    site_url, form_data['extra_opts.selectedSiteImage'])
            else:
                flash("No correct image selected.", "error")
                return redirect(url_for('showinfrastructures'))

            template = add_image_to_template(template, image)

            template = add_auth_to_template(template, auth_data)

            inputs = {
                k: v
                for (k, v) in form_data.items()
                if not k.startswith("extra_opts.")
            }

            app.logger.debug("Parameters: " + json.dumps(inputs))

            template = set_inputs_to_template(template, inputs)

            payload = yaml.dump(template,
                                default_flow_style=False,
                                sort_keys=False)

        headers = {"Authorization": auth_data, "Content-Type": "text/yaml"}

        url = "%s/infrastructures?async=1" % settings.imUrl
        response = requests.post(url, headers=headers, data=payload)

        if not response.ok:
            flash("Error creating infrastrucrure: \n" + response.text, "error")
        else:
            try:
                inf_id = os.path.basename(response.text)
                infra.write_infra(inf_id, {"name": form_data['infra_name']})
            except Exception as ex:
                flash("Error storing Infrastructure name: %s" % str(ex),
                      "warning")

        return redirect(url_for('showinfrastructures'))

    @app.route('/manage_creds')
    @authorized_with_valid_token
    def manage_creds():
        sites = {}

        try:
            sites = utils.getCachedSiteList()
        except Exception as e:
            flash("Error retrieving sites list: \n" + str(e), 'warning')

        return render_template('service_creds.html', sites=sites)

    @app.route('/write_creds', methods=['GET', 'POST'])
    @authorized_with_valid_token
    def write_creds():
        serviceid = request.args.get('service_id', "")
        servicename = request.args.get('service_name', "")
        app.logger.debug("service_id={}".format(serviceid))

        if request.method == 'GET':
            res = {}
            projects = {}
            try:
                res = cred.get_cred(servicename, session["userid"])
                projects = utils.getStaticSitesProjectIDs(serviceid)
                projects.update(appdb.get_project_ids(serviceid))

                if session["vos"]:
                    filter_projects = {}
                    for vo, project in projects.items():
                        if vo in session["vos"]:
                            filter_projects[vo] = project
                    projects = filter_projects
            except Exception as ex:
                flash("Error reading credentials %s!" % ex, 'error')

            return render_template('modal_creds.html',
                                   service_creds=res,
                                   service_id=serviceid,
                                   service_name=servicename,
                                   projects=projects)
        else:
            app.logger.debug("Form data: " +
                             json.dumps(request.form.to_dict()))

            creds = request.form.to_dict()
            try:
                cred.write_creds(servicename, session["userid"], creds)
                flash("Credentials successfully written!", 'info')
            except Exception as ex:
                flash("Error writing credentials %s!" % ex, 'error')

            return redirect(url_for('manage_creds'))

    @app.route('/delete_creds')
    @authorized_with_valid_token
    def delete_creds():

        serviceid = request.args.get('service_id', "")
        try:
            cred.delete_cred(serviceid, session["userid"])
            flash("Credentials successfully deleted!", 'info')
        except Exception as ex:
            flash("Error deleting credentials %s!" % ex, 'error')

        return redirect(url_for('manage_creds'))

    @app.route('/addresourcesform/<infid>')
    @authorized_with_valid_token
    def addresourcesform(infid=None):

        access_token = oidc_blueprint.session.token['access_token']

        auth_data = utils.getUserAuthData(access_token, cred,
                                          session["userid"])
        headers = {"Authorization": auth_data, "Accept": "text/plain"}

        url = "%s/infrastructures/%s/radl" % (settings.imUrl, infid)
        response = requests.get(url, headers=headers)

        if response.ok:
            try:
                radl = radl_parse.parse_radl(response.text)
            except Exception as ex:
                flash("Error parsing RADL: \n%s" % str(ex), 'error')

            return render_template('addresource.html',
                                   infid=infid,
                                   systems=radl.systems)
        else:
            flash("Error getting RADL: \n%s" % (response.text), 'error')
            return redirect(url_for('showinfrastructures'))

    @app.route('/addresources/<infid>', methods=['POST'])
    @authorized_with_valid_token
    def addresources(infid=None):

        access_token = oidc_blueprint.session.token['access_token']

        auth_data = utils.getUserAuthData(access_token, cred,
                                          session["userid"])
        headers = {"Authorization": auth_data, "Accept": "text/plain"}

        form_data = request.form.to_dict()

        url = "%s/infrastructures/%s/radl" % (settings.imUrl, infid)
        response = requests.get(url, headers=headers)

        if response.ok:
            try:
                radl = radl_parse.parse_radl(response.text)
                radl.deploys = []
                for system in radl.systems:
                    if "%s_num" % system.name in form_data:
                        vm_num = int(form_data["%s_num" % system.name])
                        if vm_num > 0:
                            radl.deploys.append(deploy(system.name, vm_num))
            except Exception as ex:
                flash(
                    "Error parsing RADL: \n%s\n%s" % (str(ex), response.text),
                    'error')

            headers = {
                "Authorization": auth_data,
                "Accept": "application/json"
            }
            url = "%s/infrastructures/%s" % (settings.imUrl, infid)
            response = requests.post(url, headers=headers, data=str(radl))

            if response.ok:
                num = len(response.json()["uri-list"])
                flash("%d nodes added successfully" % num, 'info')
            else:
                flash("Error adding nodesL: \n%s" % (response.text), 'error')

            return redirect(url_for('showinfrastructures'))
        else:
            flash("Error getting RADL: \n%s" % (response.text), 'error')
            return redirect(url_for('showinfrastructures'))

    @app.route('/logout')
    def logout():
        session.clear()
        oidc_blueprint.session.get("/logout")
        return redirect(url_for('login'))

    @app.errorhandler(403)
    def forbidden(error):
        return render_template('error_pages/403.html',
                               message=error.description)

    @app.errorhandler(404)
    def page_not_found(error):
        app.logger.error('Page not found: %s', (request.path))
        return render_template('error_pages/404.html'), 404

    @app.errorhandler(500)
    def internal_server_error(error):
        app.logger.error('Server Error: %s', (error))
        return render_template(
            'error_pages/500.html',
            support_email=app.config.get('SUPPORT_EMAIL')), 500

    return app
Beispiel #4
0
def make_kkbox_blueprint(client_id=None,
                         client_secret=None,
                         authorization_url_params=None,
                         scope=None,
                         redirect_url=None,
                         redirect_to=None,
                         login_url=None,
                         authorized_url=None,
                         rerequest_declined_permissions=False,
                         session_class=None,
                         backend=None):
    """
    Make a blueprint for authenticating with KKBOX using OAuth 2. This requires
    a client ID and client secret from KKBOX. You should either pass them to
    this constructor, or make sure that your Flask application config defines
    them, using the variables KKBOX_OAUTH_CLIENT_ID and KKBOX_OAUTH_CLIENT_SECRET.

    Args:
        client_id (str): The client ID for your application on KKBOX.
        client_secret (str): The client secret for your application on KKBOX
        scope (str, optional): comma-separated list of scopes for the OAuth token
        redirect_url (str): the URL to redirect to after the authentication
            dance is complete
        redirect_to (str): if ``redirect_url`` is not defined, the name of the
            view to redirect to after the authentication dance is complete.
            The actual URL will be determined by :func:`flask.url_for`
        login_url (str, optional): the URL path for the ``login`` view.
            Defaults to ``/kkbox``
        authorized_url (str, optional): the URL path for the ``authorized`` view.
            Defaults to ``/kkbox/authorized``.
        rerequest_declined_permissions (bool, optional): should the blueprint ask again for declined permissions.
            Defaults to ``False``
        session_class (class, optional): The class to use for creating a
            Requests session. Defaults to
            :class:`~flask_dance.consumer.requests.OAuth2Session`.
        backend: A storage backend class, or an instance of a storage
                backend class, to use for this blueprint. Defaults to
                :class:`~flask_dance.consumer.backend.session.SessionBackend`.

    :rtype: :class:`~flask_dance.consumer.OAuth2ConsumerBlueprint`
    :returns: A :ref:`blueprint <flask:blueprints>` to attach to your Flask app.
    """
    kkbox_bp = OAuth2ConsumerBlueprint(
        "kkbox",
        __name__,
        client_id=client_id,
        client_secret=client_secret,
        scope=scope,
        base_url="https://account.kkbox.com/oauth2/",
        authorization_url="https://account.kkbox.com/oauth2/authorize/",
        authorization_url_params=authorization_url_params,
        token_url="https://account.kkbox.com/oauth2/token/",
        redirect_url=redirect_url,
        redirect_to=redirect_to,
        login_url=login_url,
        authorized_url=authorized_url,
        session_class=session_class,
        backend=backend,
    )
    kkbox_bp.from_config["client_id"] = "KKBOX_OAUTH_CLIENT_ID"
    kkbox_bp.from_config["client_secret"] = "KKBOX_OAUTH_CLIENT_SECRET"

    @kkbox_bp.before_app_request
    def set_applocal_session():
        ctx = stack.top
        ctx.facebook_oauth = kkbox_bp.session

    return kkbox_bp
Beispiel #5
0
def make_meetup_blueprint(
    key=None,
    secret=None,
    scope=None,
    redirect_url=None,
    redirect_to=None,
    login_url=None,
    authorized_url=None,
    session_class=None,
    backend=None,
    storage=None,
):
    """
    Make a blueprint for authenticating with Meetup using OAuth 2. This requires
    an OAuth consumer from Meetup. You should either pass the key and secret to
    this constructor, or make sure that your Flask application config defines
    them, using the variables MEETUP_OAUTH_KEY and MEETUP_OAUTH_SECRET.

    Args:
        key (str): The OAuth consumer key for your application on Meetup
        secret (str): The OAuth consumer secret for your application on Meetup
        scope (str, optional): comma-separated list of scopes for the OAuth token
        redirect_url (str): the URL to redirect to after the authentication
            dance is complete
        redirect_to (str): if ``redirect_url`` is not defined, the name of the
            view to redirect to after the authentication dance is complete.
            The actual URL will be determined by :func:`flask.url_for`
        login_url (str, optional): the URL path for the ``login`` view.
            Defaults to ``/meetup``
        authorized_url (str, optional): the URL path for the ``authorized`` view.
            Defaults to ``/meetup/authorized``.
        session_class (class, optional): The class to use for creating a
            Requests session. Defaults to
            :class:`~flask_dance.consumer.requests.OAuth2Session`.
        storage: A token storage class, or an instance of a token storage
                class, to use for this blueprint. Defaults to
                :class:`~flask_dance.consumer.storage.session.SessionStorage`.

    :rtype: :class:`~flask_dance.consumer.OAuth2ConsumerBlueprint`
    :returns: A :ref:`blueprint <flask:blueprints>` to attach to your Flask app.
    """
    scope = scope or ["basic"]
    meetup_bp = OAuth2ConsumerBlueprint(
        "meetup",
        __name__,
        client_id=key,
        client_secret=secret,
        scope=scope,
        base_url="https://api.meetup.com/2/",
        authorization_url="https://secure.meetup.com/oauth2/authorize",
        token_url="https://secure.meetup.com/oauth2/access",
        redirect_url=redirect_url,
        redirect_to=redirect_to,
        login_url=login_url,
        authorized_url=authorized_url,
        session_class=session_class or MeetupOAuth2Session,
        backend=backend,
        storage=storage,
    )
    meetup_bp.from_config["client_id"] = "MEETUP_OAUTH_KEY"
    meetup_bp.from_config["client_secret"] = "MEETUP_OAUTH_SECRET"

    @meetup_bp.before_app_request
    def set_applocal_session():
        ctx = stack.top
        ctx.meetup_oauth = meetup_bp.session

    return meetup_bp
Beispiel #6
0
def make_linkedin_blueprint(
    client_id=None,
    client_secret=None,
    scope=None,
    redirect_url=None,
    redirect_to=None,
    login_url=None,
    authorized_url=None,
    session_class=None,
    storage=None,
):
    """
    Make a blueprint for authenticating with LinkedIn using OAuth 2. This requires
    a client ID and client secret from LinkedIn. You should either pass them to
    this constructor, or make sure that your Flask application config defines
    them, using the variables :envvar:`LINKEDIN_OAUTH_CLIENT_ID` and
    :envvar:`LINKEDIN_OAUTH_CLIENT_SECRET`.

    Args:
        client_id (str): The client ID for your application on LinkedIn.
        client_secret (str): The client secret for your application on LinkedIn
        scope (str, optional): comma-separated list of scopes for the OAuth token
        redirect_url (str): the URL to redirect to after the authentication
            dance is complete
        redirect_to (str): if ``redirect_url`` is not defined, the name of the
            view to redirect to after the authentication dance is complete.
            The actual URL will be determined by :func:`flask.url_for`
        login_url (str, optional): the URL path for the ``login`` view.
            Defaults to ``/linkedin``
        authorized_url (str, optional): the URL path for the ``authorized`` view.
            Defaults to ``/linkedin/authorized``.
        session_class (class, optional): The class to use for creating a
            Requests session. Defaults to
            :class:`~flask_dance.consumer.requests.OAuth2Session`.
        storage: A token storage class, or an instance of a token storage
                class, to use for this blueprint. Defaults to
                :class:`~flask_dance.consumer.storage.session.SessionStorage`.

    :rtype: :class:`~flask_dance.consumer.OAuth2ConsumerBlueprint`
    :returns: A :ref:`blueprint <flask:blueprints>` to attach to your Flask app.
    """
    linkedin_bp = OAuth2ConsumerBlueprint(
        "linkedin",
        __name__,
        client_id=client_id,
        client_secret=client_secret,
        scope=scope,
        base_url="https://api.linkedin.com/v2/",
        authorization_url="https://www.linkedin.com/oauth/v2/authorization",
        token_url="https://www.linkedin.com/oauth/v2/accessToken",
        token_url_params={"include_client_id": True},
        redirect_url=redirect_url,
        redirect_to=redirect_to,
        login_url=login_url,
        authorized_url=authorized_url,
        session_class=session_class,
        storage=storage,
    )
    linkedin_bp.from_config["client_id"] = "LINKEDIN_OAUTH_CLIENT_ID"
    linkedin_bp.from_config["client_secret"] = "LINKEDIN_OAUTH_CLIENT_SECRET"

    @linkedin_bp.before_app_request
    def set_applocal_session():
        ctx = stack.top
        ctx.linkedin_oauth = linkedin_bp.session

    return linkedin_bp
Beispiel #7
0
def make_google_blueprint(
    client_id=None,
    client_secret=None,
    scope=None,
    offline=False,
    reprompt_consent=False,
    redirect_url=None,
    redirect_to=None,
    login_url=None,
    authorized_url=None,
    session_class=None,
    backend=None,
    hosted_domain=None,
):
    """
    Make a blueprint for authenticating with Google using OAuth 2. This requires
    a client ID and client secret from Google. You should either pass them to
    this constructor, or make sure that your Flask application config defines
    them, using the variables GOOGLE_OAUTH_CLIENT_ID and GOOGLE_OAUTH_CLIENT_SECRET.

    Args:
        client_id (str): The client ID for your application on Google
        client_secret (str): The client secret for your application on Google
        scope (str, optional): comma-separated list of scopes for the OAuth token.
            Defaults to the "https://www.googleapis.com/auth/userinfo.profile" scope.
        offline (bool): Whether to request `offline access
            <https://developers.google.com/accounts/docs/OAuth2WebServer#offline>`_
            for the OAuth token. Defaults to False
        reprompt_consent (bool): If True, force Google to re-prompt the user
            for their consent, even if the user has already given their
            consent. Defaults to False
        redirect_url (str): the URL to redirect to after the authentication
            dance is complete
        redirect_to (str): if ``redirect_url`` is not defined, the name of the
            view to redirect to after the authentication dance is complete.
            The actual URL will be determined by :func:`flask.url_for`
        login_url (str, optional): the URL path for the ``login`` view.
            Defaults to ``/google``
        authorized_url (str, optional): the URL path for the ``authorized`` view.
            Defaults to ``/google/authorized``.
        session_class (class, optional): The class to use for creating a
            Requests session. Defaults to
            :class:`~flask_dance.consumer.requests.OAuth2Session`.
        backend: A storage backend class, or an instance of a storage
                backend class, to use for this blueprint. Defaults to
                :class:`~flask_dance.consumer.backend.session.SessionBackend`.
        hosted_domain (str, optional): The domain of the G Suite user. Used to indicate that the account selection UI
            should be optimized for accounts at this domain. Note that this only provides UI optimization, and requires
            response validation (see warning).

    .. _google_hosted_domain_warning:
    .. warning::
       The ``hosted_domain`` argument **only provides UI optimization**. Don't rely on this argument to control
       who can access your application. You must verify that the ``hd`` claim of the response ID token matches the
       ``hosted_domain`` argument passed to ``make_google_blueprint``. For example:

       .. code-block:: python

            from flask import session, abort
            from flask_dance.consumer import oauth_authorized
            from flask_dance.contrib.google import make_google_blueprint, google
            import requests

            google_bp = make_google_blueprint(
                client_id="foo",
                client_secret="bar",
                scope=["profile", "email"],
                hosted_domain="example.com"
            )

            @oauth_authorized.connect_via(google_bp)
            def logged_in(blueprint, token):
                resp_json = google.get("/oauth2/v2/userinfo").json()
                if resp_json["hd"] != blueprint.authorization_url_params["hd"]:
                    requests.post(
                        "https://accounts.google.com/o/oauth2/revoke",
                        params={"token": token["access_token"]}
                    )
                    session.clear()
                    abort(403)


    :rtype: :class:`~flask_dance.consumer.OAuth2ConsumerBlueprint`
    :returns: A :ref:`blueprint <flask:blueprints>` to attach to your Flask app.
    """
    scope = scope or ["https://www.googleapis.com/auth/userinfo.profile"]
    authorization_url_params = {}
    auto_refresh_url = None
    if offline:
        authorization_url_params["access_type"] = "offline"
        auto_refresh_url = "https://accounts.google.com/o/oauth2/token"
    if reprompt_consent:
        authorization_url_params["approval_prompt"] = "force"
    if hosted_domain:
        authorization_url_params["hd"] = hosted_domain
    google_bp = OAuth2ConsumerBlueprint(
        "google",
        __name__,
        client_id=client_id,
        client_secret=client_secret,
        scope=scope,
        base_url="https://www.googleapis.com/",
        authorization_url="https://accounts.google.com/o/oauth2/auth",
        token_url="https://accounts.google.com/o/oauth2/token",
        auto_refresh_url=auto_refresh_url,
        redirect_url=redirect_url,
        redirect_to=redirect_to,
        login_url=login_url,
        authorized_url=authorized_url,
        authorization_url_params=authorization_url_params,
        session_class=session_class,
        backend=backend,
    )
    google_bp.from_config["client_id"] = "GOOGLE_OAUTH_CLIENT_ID"
    google_bp.from_config["client_secret"] = "GOOGLE_OAUTH_CLIENT_SECRET"

    @google_bp.before_app_request
    def set_applocal_session():
        ctx = stack.top
        ctx.google_oauth = google_bp.session

    return google_bp
Beispiel #8
0
def make_salesforce_blueprint(
    client_id=None,
    client_secret=None,
    *,
    scope=None,
    reprompt_consent=False,
    hostname=None,
    is_sandbox=False,
    redirect_url=None,
    redirect_to=None,
    login_url=None,
    authorized_url=None,
    session_class=None,
    storage=None,
):
    """
    Make a blueprint for authenticating with Salesforce using OAuth 2. This requires
    a client ID and client secret from Salesforce. You should either pass them to
    this constructor, or make sure that your Flask application config defines
    them, using the variables :envvar:`SALESFORCE_OAUTH_CLIENT_ID` and
    :envvar:`SALESFORCE_OAUTH_CLIENT_SECRET`.

    Args:
        client_id (str): The client ID for your application on Salesforce.
        client_secret (str): The client secret for your application on Salesforce.
        scope (str, optional): comma-separated list of scopes for the OAuth token.
        reprompt_consent (bool): If True, force Salesforce to re-prompt the user
            for their consent, even if the user has already given their
            consent. Defaults to False.
        hostname (str, optional): The hostname of your Salesforce instance.
            By default, Salesforce uses ``login.salesforce.com`` for production
            instances and ``test.salesforce.com`` for sandboxes.
        is_sandbox (bool): If hostname is not defined specify whether Salesforce
            instance is a sandbox. Defaults to False.
        redirect_url (str): the URL to redirect to after the authentication
            dance is complete.
        redirect_to (str): if ``redirect_url`` is not defined, the name of the
            view to redirect to after the authentication dance is complete.
            The actual URL will be determined by :func:`flask.url_for`.
        login_url (str, optional): the URL path for the ``login`` view.
            Defaults to ``/salesforce``.
        authorized_url (str, optional): the URL path for the ``authorized`` view.
            Defaults to ``/salesforce/authorized``.
        session_class (class, optional): The class to use for creating a
            Requests session. Defaults to
            :class:`~flask_dance.consumer.requests.OAuth2Session`.
        storage: A token storage class, or an instance of a token storage
                class, to use for this blueprint. Defaults to
                :class:`~flask_dance.consumer.storage.session.SessionStorage`.

    :rtype: :class:`~flask_dance.consumer.OAuth2ConsumerBlueprint`
    :returns: A :doc:`blueprint <flask:blueprints>` to attach to your Flask app.
    """
    authorization_url_params = {}
    if reprompt_consent:
        authorization_url_params["prompt"] = "consent"

    if not hostname:
        hostname = "test.salesforce.com" if is_sandbox else "login.salesforce.com"

    salesforce_bp = OAuth2ConsumerBlueprint(
        "salesforce",
        __name__,
        client_id=client_id,
        client_secret=client_secret,
        scope=scope,
        base_url=f"https://{hostname}/",
        authorization_url=f"https://{hostname}/services/oauth2/authorize",
        token_url=f"https://{hostname}/services/oauth2/token",
        redirect_url=redirect_url,
        redirect_to=redirect_to,
        login_url=login_url,
        authorized_url=authorized_url,
        authorization_url_params=authorization_url_params,
        session_class=session_class,
        storage=storage,
    )
    salesforce_bp.from_config["client_id"] = "SALESFORCE_OAUTH_CLIENT_ID"
    salesforce_bp.from_config[
        "client_secret"] = "SALESFORCE_OAUTH_CLIENT_SECRET"

    @salesforce_bp.before_app_request
    def set_applocal_session():
        ctx = stack.top
        ctx.salesforce_oauth = salesforce_bp.session

    return salesforce_bp
Beispiel #9
0
def make_atlassian_blueprint(
    client_id=None,
    client_secret=None,
    scope=None,
    reprompt_consent=False,
    redirect_url=None,
    redirect_to=None,
    login_url=None,
    authorized_url=None,
    session_class=None,
    storage=None,
):
    """
    Make a blueprint for authenticating with Atlassian using OAuth 2. This requires
    a client ID and client secret from Atlassian. You should either pass them to
    this constructor, or make sure that your Flask application config defines
    them, using the variables :envvar:`ATLASSIAN_OAUTH_CLIENT_ID` and
    :envvar:`ATLASSIAN_OAUTH_CLIENT_SECRET`.

    Args:
        client_id (str): The client ID for your application on Atlassian.
        client_secret (str): The client secret for your application on Atlassian.
        scope (str, optional): comma-separated list of scopes for the OAuth token.
        reprompt_consent (bool): If True, force Atlassian to re-prompt the user
            for their consent, even if the user has already given their
            consent. Defaults to False.
        redirect_url (str): the URL to redirect to after the authentication
            dance is complete.
        redirect_to (str): if ``redirect_url`` is not defined, the name of the
            view to redirect to after the authentication dance is complete.
            The actual URL will be determined by :func:`flask.url_for`.
        login_url (str, optional): the URL path for the ``login`` view.
            Defaults to ``/atlassian``.
        authorized_url (str, optional): the URL path for the ``authorized`` view.
            Defaults to ``/atlassian/authorized``.
        session_class (class, optional): The class to use for creating a
            Requests session. Defaults to
            :class:`~flask_dance.consumer.requests.OAuth2Session`.
        storage: A token storage class, or an instance of a token storage
                class, to use for this blueprint. Defaults to
                :class:`~flask_dance.consumer.storage.session.SessionStorage`.

    :rtype: :class:`~flask_dance.consumer.OAuth2ConsumerBlueprint`
    :returns: A :ref:`blueprint <flask:blueprints>` to attach to your Flask app.
    """
    authorization_url_params = {"audience": "api.atlassian.com"}
    if reprompt_consent:
        authorization_url_params["prompt"] = "consent"

    atlassian_bp = OAuth2ConsumerBlueprint(
        "atlassian",
        __name__,
        client_id=client_id,
        client_secret=client_secret,
        scope=scope,
        base_url="https://api.atlassian.com/",
        authorization_url="https://auth.atlassian.com/authorize",
        token_url="https://auth.atlassian.com/oauth/token",
        redirect_url=redirect_url,
        redirect_to=redirect_to,
        login_url=login_url,
        authorized_url=authorized_url,
        authorization_url_params=authorization_url_params,
        session_class=session_class,
        storage=storage,
    )
    atlassian_bp.from_config["client_id"] = "ATLASSIAN_OAUTH_CLIENT_ID"
    atlassian_bp.from_config["client_secret"] = "ATLASSIAN_OAUTH_CLIENT_SECRET"

    @atlassian_bp.before_app_request
    def set_applocal_session():
        ctx = stack.top
        ctx.atlassian_oauth = atlassian_bp.session

    return atlassian_bp
Beispiel #10
0
def make_azure_blueprint(client_id=None,
                         client_secret=None,
                         scope=None,
                         redirect_url=None,
                         redirect_to=None,
                         login_url=None,
                         authorized_url=None,
                         session_class=None,
                         backend=None,
                         tenant="common"):
    """
    Make a blueprint for authenticating with Azure AD using OAuth 2. This requires
    a client ID and client secret from Azure AD. You should either pass them to
    this constructor, or make sure that your Flask application config defines
    them, using the variables AZURE_OAUTH_CLIENT_ID and AZURE_OAUTH_CLIENT_SECRET.

    Args:
        client_id (str): The client ID for your application on Azure AD.
        client_secret (str): The client secret for your application on Azure AD
        scope (str, optional): comma-separated list of scopes for the OAuth token
        redirect_url (str): the URL to redirect to after the authentication
            dance is complete
        redirect_to (str): if ``redirect_url`` is not defined, the name of the
            view to redirect to after the authentication dance is complete.
            The actual URL will be determined by :func:`flask.url_for`
        login_url (str, optional): the URL path for the ``login`` view.
            Defaults to ``/azure``
        authorized_url (str, optional): the URL path for the ``authorized`` view.
            Defaults to ``/azure/authorized``.
        session_class (class, optional): The class to use for creating a
            Requests session. Defaults to
            :class:`~flask_dance.consumer.requests.OAuth2Session`.
        backend: A storage backend class, or an instance of a storage
                backend class, to use for this blueprint. Defaults to
                :class:`~flask_dance.consumer.backend.session.SessionBackend`.
        tenant: Determine which accounts are allowed to authenticate with Azure.
                `See the Azure documentation for more information about this parameter.
                <https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols#endpoints>`_
                Defaults to ``common``.


    :rtype: :class:`~flask_dance.consumer.OAuth2ConsumerBlueprint`
    :returns: A :ref:`blueprint <flask:blueprints>` to attach to your Flask app.
    """
    scope = scope or ["openid", "email", "profile", "User.Read"]
    azure_bp = OAuth2ConsumerBlueprint(
        "azure",
        __name__,
        client_id=client_id,
        client_secret=client_secret,
        scope=scope,
        base_url="https://graph.microsoft.com",
        authorization_url=
        "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize".
        format(tenant=tenant),
        token_url="https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token"
        .format(tenant=tenant),
        redirect_url=redirect_url,
        redirect_to=redirect_to,
        login_url=login_url,
        authorized_url=authorized_url,
        session_class=session_class,
        backend=backend,
    )
    azure_bp.from_config["client_id"] = "AZURE_OAUTH_CLIENT_ID"
    azure_bp.from_config["client_secret"] = "AZURE_OAUTH_CLIENT_SECRET"

    @azure_bp.before_app_request
    def set_applocal_session():
        ctx = stack.top
        ctx.azure_oauth = azure_bp.session

    return azure_bp
Beispiel #11
0
def make_facebook_blueprint(client_id=None,
                            client_secret=None,
                            scope=None,
                            redirect_url=None,
                            redirect_to=None,
                            login_url=None,
                            authorized_url=None,
                            session_class=None,
                            backend=None):
    """
    Make a blueprint for authenticating with Facebook using OAuth 2. This requires
    a client ID and client secret from Facebook. You should either pass them to
    this constructor, or make sure that your Flask application config defines
    them, using the variables FACEBOOK_OAUTH_CLIENT_ID and FACEBOOK_OAUTH_CLIENT_SECRET.

    Args:
        client_id (str): The client ID for your application on Facebook.
        client_secret (str): The client secret for your application on Facebook
        scope (str, optional): comma-separated list of scopes for the OAuth token
        redirect_url (str): the URL to redirect to after the authentication
            dance is complete
        redirect_to (str): if ``redirect_url`` is not defined, the name of the
            view to redirect to after the authentication dance is complete.
            The actual URL will be determined by :func:`flask.url_for`
        login_url (str, optional): the URL path for the ``login`` view.
            Defaults to ``/facebook``
        authorized_url (str, optional): the URL path for the ``authorized`` view.
            Defaults to ``/facebook/authorized``.
        session_class (class, optional): The class to use for creating a
            Requests session. Defaults to
            :class:`~flask_dance.consumer.requests.OAuth2Session`.
        backend: A storage backend class, or an instance of a storage
                backend class, to use for this blueprint. Defaults to
                :class:`~flask_dance.consumer.backend.session.SessionBackend`.

    :rtype: :class:`~flask_dance.consumer.OAuth2ConsumerBlueprint`
    :returns: A :ref:`blueprint <flask:blueprints>` to attach to your Flask app.
    """
    facebook_bp = OAuth2ConsumerBlueprint(
        "facebook",
        __name__,
        client_id=client_id,
        client_secret=client_secret,
        scope=scope,
        base_url="https://graph.facebook.com/",
        authorization_url="https://www.facebook.com/dialog/oauth",
        token_url="https://graph.facebook.com/oauth/access_token",
        redirect_url=redirect_url,
        redirect_to=redirect_to,
        login_url=login_url,
        authorized_url=authorized_url,
        session_class=session_class,
        backend=backend,
    )
    facebook_bp.from_config["client_id"] = "FACEBOOK_OAUTH_CLIENT_ID"
    facebook_bp.from_config["client_secret"] = "FACEBOOK_OAUTH_CLIENT_SECRET"

    @facebook_bp.before_app_request
    def set_applocal_session():
        ctx = stack.top
        ctx.facebook_oauth = facebook_bp.session

    return facebook_bp
Beispiel #12
0
from os import environ

from flask_dance.consumer import OAuth2ConsumerBlueprint

onshape = OAuth2ConsumerBlueprint(
    "onshape",
    __name__,
    base_url="https://cad.onshape.com/api/",
    authorization_url="https://oauth.onshape.com/oauth/authorize",
    token_url="https://oauth.onshape.com/oauth/token",
)
onshape.from_config["client_id"] = "ONSHAPE_CLIENT_ID"
onshape.from_config["client_secret"] = "ONSHAPE_CLIENT_SECRET"
def make_figshare_blueprint(
    client_id=None,
    client_secret=None,
    scope=None,
    redirect_url=None,
    redirect_to=None,
    login_url=None,
    authorized_url=None,
    rerequest_declined_permissions=False,
    session_class=None,
    storage=None,
):
    """
    Make a blueprint for authenticating with Facebook using OAuth 2. This requires
    a client ID and client secret from Facebook. You should either pass them to
    this constructor, or make sure that your Flask application config defines
    them, using the variables :envvar:`FIGSHARE_OAUTH_CLIENT_ID` and
    :envvar:`FIGSHARE_OAUTH_CLIENT_SECRET`.

    Args:
        client_id (str): The client ID for your application on Figshare.
        client_secret (str): The client secret for your application on Figshare
        scope (str, optional): comma-separated list of scopes for the OAuth token
        redirect_url (str): the URL to redirect to after the authentication
            dance is complete
        redirect_to (str): if ``redirect_url`` is not defined, the name of the
            view to redirect to after the authentication dance is complete.
            The actual URL will be determined by :func:`flask.url_for`
        login_url (str, optional): the URL path for the ``login`` view.
            Defaults to ``/figshare``
        authorized_url (str, optional): the URL path for the ``authorized`` view.
            Defaults to ``/figshare/authorized``.
        rerequest_declined_permissions (bool, optional): should the blueprint ask again for declined permissions.
            Defaults to ``False``
        session_class (class, optional): The class to use for creating a
            Requests session. Defaults to
            :class:`~flask_dance.consumer.requests.OAuth2Session`.
        storage: A token storage class, or an instance of a token storage
                class, to use for this blueprint. Defaults to
                :class:`~flask_dance.consumer.storage.session.SessionStorage`.

    :rtype: :class:`~flask_dance.consumer.OAuth2ConsumerBlueprint`
    :returns: A :ref:`blueprint <flask:blueprints>` to attach to your Flask app.
    """
    authorization_url_params = {}
    if rerequest_declined_permissions:
        authorization_url_params["auth_type"] = "rerequest"
    figshare_bp = OAuth2ConsumerBlueprint(
        "figshare",
        __name__,
        client_id=client_id,
        client_secret=client_secret,
        scope=scope,
        base_url="https://api.figshare.com/v2",
        authorization_url='https://figshare.com/account/applications/authorize',
        authorization_url_params=authorization_url_params,
        token_url='https://api.figshare.com/v2/token',
        redirect_url=redirect_url,
        redirect_to=redirect_to,
        login_url=login_url,
        authorized_url=authorized_url,
        session_class=session_class,
        storage=storage,
    )
    figshare_bp.from_config["client_id"] = "FIGSHARE_OAUTH_CLIENT_ID"
    figshare_bp.from_config["client_secret"] = "FIGSHARE_OAUTH_CLIENT_SECRET"

    @figshare_bp.before_app_request
    def set_applocal_session():
        ctx = stack.top
        ctx.figshare_oauth = figshare_bp.session

    return figshare_bp
Beispiel #14
0
def create_app(oidc_blueprint=None):
    app = Flask(__name__)
    app.wsgi_app = ProxyFix(app.wsgi_app,
                            x_for=1,
                            x_proto=1,
                            x_host=1,
                            x_port=1,
                            x_prefix=1)
    app.secret_key = "8210f566-4981-11ea-92d1-f079596e599b"
    app.config.from_json('config.json')
    settings = Settings(app.config)
    if 'CREDS_KEY' in os.environ:
        key = os.environ['CREDS_KEY']
    else:
        key = None
    CSRFProtect(app)
    cred = Credentials(settings.db_url, key)
    infra = Infrastructures(settings.db_url)
    im = InfrastructureManager(settings.imUrl)

    # To Reload internally the site cache
    scheduler = APScheduler()
    scheduler.api_enabled = False
    scheduler.init_app(app)
    scheduler.start()

    toscaTemplates = utils.loadToscaTemplates(settings.toscaDir)
    toscaInfo = utils.extractToscaInfo(settings.toscaDir,
                                       settings.toscaParamsDir, toscaTemplates)

    app.jinja_env.filters['tojson_pretty'] = utils.to_pretty_json
    app.logger.debug("TOSCA INFO: " + json.dumps(toscaInfo))

    loglevel = app.config.get("LOG_LEVEL") if app.config.get(
        "LOG_LEVEL") else "INFO"

    numeric_level = getattr(logging, loglevel.upper(), None)
    if not isinstance(numeric_level, int):
        raise ValueError('Invalid log level: %s' % loglevel)

    logging.basicConfig(level=numeric_level)

    oidc_base_url = app.config['OIDC_BASE_URL']
    oidc_token_url = oidc_base_url + '/token'
    oidc_refresh_url = oidc_base_url + '/token'
    oidc_authorization_url = oidc_base_url + '/authorize'

    if not oidc_blueprint:
        oidc_blueprint = OAuth2ConsumerBlueprint(
            "oidc",
            __name__,
            client_id=app.config['OIDC_CLIENT_ID'],
            client_secret=app.config['OIDC_CLIENT_SECRET'],
            scope=app.config['OIDC_SCOPES'],
            base_url=oidc_base_url,
            token_url=oidc_token_url,
            auto_refresh_url=oidc_refresh_url,
            authorization_url=oidc_authorization_url,
            redirect_to='home')
    app.register_blueprint(oidc_blueprint, url_prefix="/login")

    @app.before_request
    def before_request_checks():
        if 'external_links' not in session:
            session['external_links'] = settings.external_links
        g.analytics_tag = settings.analytics_tag
        g.settings = settings

    def authorized_with_valid_token(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):

            if settings.debug_oidc_token:
                oidc_blueprint.session.token = {
                    'access_token': settings.debug_oidc_token
                }
            else:
                try:
                    if not oidc_blueprint.session.authorized or 'username' not in session:
                        return redirect(url_for('login'))

                    if oidc_blueprint.session.token['expires_in'] < 20:
                        app.logger.debug("Force refresh token")
                        oidc_blueprint.session.get('/userinfo')
                except (InvalidTokenError, TokenExpiredError):
                    flash("Token expired.", 'warning')
                    return redirect(url_for('login'))

            return f(*args, **kwargs)

        return decorated_function

    @app.route('/settings')
    @authorized_with_valid_token
    def show_settings():
        imUrl = "%s (v. %s)" % (settings.imUrl, im.get_version())
        return render_template('settings.html',
                               oidc_url=settings.oidcUrl,
                               im_url=imUrl)

    @app.route('/login')
    def login():
        session.clear()
        return render_template('home.html', oidc_name=settings.oidcName)

    @app.route('/')
    def home():
        if settings.debug_oidc_token:
            session["vos"] = None
            session['userid'] = "userid"
            session['username'] = "******"
            session['gravatar'] = ""
            return render_template('portfolio.html', templates=toscaInfo)
        else:
            if not oidc_blueprint.session.authorized:
                return redirect(url_for('login'))

            try:
                account_info = oidc_blueprint.session.get(
                    urlparse(settings.oidcUrl)[2] + "/userinfo")
            except (InvalidTokenError, TokenExpiredError):
                flash("Token expired.", 'warning')
                return redirect(url_for('login'))

            if account_info.ok:
                account_info_json = account_info.json()

                session["vos"] = None
                if 'eduperson_entitlement' in account_info_json:
                    session["vos"] = utils.getUserVOs(
                        account_info_json['eduperson_entitlement'])

                if settings.oidcGroups:
                    user_groups = []
                    if 'groups' in account_info_json:
                        user_groups = account_info_json['groups']
                    elif 'eduperson_entitlement' in account_info_json:
                        user_groups = account_info_json[
                            'eduperson_entitlement']
                    if not set(settings.oidcGroups).issubset(user_groups):
                        app.logger.debug(
                            "No match on group membership. User group membership: "
                            + json.dumps(user_groups))
                        message = Markup(
                            'You need to be a member of the following groups: {0}. <br>'
                            ' Please, visit <a href="{1}">{1}</a> and apply for the requested '
                            'membership.'.format(
                                json.dumps(settings.oidcGroups),
                                settings.oidcUrl))
                        raise Forbidden(description=message)

                session['userid'] = account_info_json['sub']
                if 'name' in account_info_json:
                    session['username'] = account_info_json['name']
                else:
                    session['username'] = ""
                    if 'given_name' in account_info_json:
                        session['username'] = account_info_json['given_name']
                    if 'family_name' in account_info_json:
                        session['username'] += " " + account_info_json[
                            'family_name']
                    if session['username'] == "":
                        session['username'] = account_info_json['sub']
                if 'email' in account_info_json:
                    session['gravatar'] = utils.avatar(
                        account_info_json['email'], 26)
                else:
                    session['gravatar'] = utils.avatar(
                        account_info_json['sub'], 26)

                return render_template('portfolio.html', templates=toscaInfo)
            else:
                flash("Error getting User info: \n" + account_info.text,
                      'error')
                return render_template('home.html',
                                       oidc_name=settings.oidcName)

    @app.route('/vminfo')
    @authorized_with_valid_token
    def showvminfo():
        access_token = oidc_blueprint.session.token['access_token']
        vmid = request.args['vmId']
        infid = request.args['infId']

        auth_data = utils.getUserAuthData(access_token, cred,
                                          session["userid"])
        try:
            response = im.get_vm_info(infid, vmid, auth_data)
        except Exception as ex:
            flash("Error: %s." % ex, 'error')

        vminfo = {}
        state = ""
        nets = ""
        disks = ""
        deployment = ""
        if not response.ok:
            flash("Error retrieving VM info: \n" + response.text, 'error')
        else:
            app.logger.debug("VM Info: %s" % response.text)
            radl_json = response.json()["radl"]
            outports = utils.get_out_ports(radl_json)
            vminfo = utils.format_json_radl(radl_json)
            if "cpu.arch" in vminfo:
                del vminfo["cpu.arch"]
            if "state" in vminfo:
                state = vminfo["state"]
                del vminfo["state"]
            if "provider.type" in vminfo:
                deployment = vminfo["provider.type"]
                del vminfo["provider.type"]
            if "provider.host" in vminfo:
                if "provider.port" in vminfo:
                    deployment += ": %s:%s" % (vminfo["provider.host"],
                                               vminfo["provider.port"])
                    del vminfo["provider.port"]
                else:
                    deployment += ": " + vminfo["provider.host"]
                del vminfo["provider.host"]
            if "disk.0.os.name" in vminfo:
                del vminfo["disk.0.os.name"]

            cont = 0
            while "net_interface.%s.connection" % cont in vminfo:
                if "net_interface.%s.ip" % cont in vminfo:
                    if cont > 0:
                        nets += Markup('<br/>')
                    nets += Markup('<i class="fa fa-network-wired"></i>')
                    nets += Markup(
                        ' <span class="badge badge-secondary">%s</span>' %
                        cont)
                    nets += ": %s" % vminfo["net_interface.%s.ip" % cont]
                    del vminfo["net_interface.%s.ip" % cont]
                    if "net_interface.%s.dns_name" % cont in vminfo:
                        nets += " (%s)" % vminfo["net_interface.%s.dns_name" %
                                                 cont]
                        del vminfo["net_interface.%s.dns_name" % cont]

                cont += 1

            cont = 0
            while "net_interface.%s.connection" % cont in vminfo:
                del vminfo["net_interface.%s.connection" % cont]
                cont += 1

            for elem in vminfo:
                if elem.endswith("size") and isinstance(vminfo[elem], int):
                    vminfo[elem] = "%d GB" % (vminfo[elem] / 1073741824)

            cont = 0
            while "disk.%s.size" % cont in vminfo or "disk.%s.image.url" % cont in vminfo:
                if cont > 0:
                    disks += Markup('<br/>')
                disks += Markup(
                    '<i class="fa fa-database"></i> <span class="badge badge-secondary">'
                    '%s</span><br/>' % cont)

                prop_map = {
                    "size": "Size",
                    "image.url": "URL",
                    "device": "Device",
                    "mount_path": "Mount Path",
                    "fstype": "F.S. type",
                    "os.flavour": "O.S. Flavor",
                    "os.version": "O.S. Version"
                }
                for name, label in prop_map.items():
                    prop = "disk.%s.%s" % (cont, name)
                    if prop in vminfo:
                        disks += Markup('&nbsp;&nbsp;')
                        disks += "- %s: %s" % (label, vminfo[prop])
                        disks += Markup('<br/>')
                        del vminfo[prop]

                cont += 1

            str_outports = ""
            for port in outports:
                str_outports += Markup(
                    '<i class="fas fa-project-diagram"></i> <span class="badge '
                    'badge-secondary">%s</span>' % port.get_remote_port())
                if not port.is_range():
                    if port.get_remote_port() != port.get_local_port():
                        str_outports += Markup(
                            ' <i class="fas fa-long-arrow-alt-right">'
                            '</i> <span class="badge badge-secondary">%s</span>'
                            % port.get_local_port())
                else:
                    str_outports += Markup(
                        ' : </i> <span class="badge badge-secondary">%s</span>'
                        % port.get_local_port())
                str_outports += Markup('<br/>')

        return render_template('vminfo.html',
                               infid=infid,
                               vmid=vmid,
                               vminfo=vminfo,
                               outports=str_outports,
                               state=state,
                               nets=nets,
                               deployment=deployment,
                               disks=disks)

    @app.route('/managevm/<op>/<infid>/<vmid>', methods=['POST'])
    @authorized_with_valid_token
    def managevm(op=None, infid=None, vmid=None):
        access_token = oidc_blueprint.session.token['access_token']

        auth_data = utils.getUserAuthData(access_token, cred,
                                          session["userid"])
        try:
            if op == "reconfigure":
                response = im.reconfigure_inf(infid, auth_data, [vmid])
            if op == "resize":
                form_data = request.form.to_dict()
                cpu = int(form_data['cpu'])
                memory = int(form_data['memory'])
                system_name = form_data['system_name']

                radl = "system %s (cpu.count >= %d and memory.size >= %dg)" % (
                    system_name, cpu, memory)
                response = im.resize_vm(infid, vmid, radl, auth_data)
            else:
                response = im.manage_vm(op, infid, vmid, auth_data)
        except Exception as ex:
            flash("Error: %s." % ex, 'error')
            return redirect(url_for('showinfrastructures'))

        if response.ok:
            flash("Operation '%s' successfully made on VM ID: %s" % (op, vmid),
                  'info')
        else:
            flash(
                "Error making %s op on VM %s: \n%s" %
                (op, vmid, response.text), 'error')

        if op == "terminate":
            return redirect(url_for('showinfrastructures'))
        else:
            return redirect(url_for('showvminfo', infId=infid, vmId=vmid))

    @app.route('/infrastructures')
    @authorized_with_valid_token
    def showinfrastructures():
        access_token = oidc_blueprint.session.token['access_token']

        reload_infid = None
        if 'reload' in request.args:
            reload_infid = request.args['reload']

        auth_data = "type = InfrastructureManager; token = %s" % access_token
        inf_list = []
        try:
            inf_list = im.get_inf_list(auth_data)
        except Exception as ex:
            flash("Error: %s." % ex, 'error')

        infrastructures = {}
        for inf_id in inf_list:
            infrastructures[inf_id] = {}
            try:
                infra_data = infra.get_infra(inf_id)
            except Exception:
                infra_data = {}
            infrastructures[inf_id] = {'name': '', 'state': {}}
            if 'name' in infra_data:
                infrastructures[inf_id]['name'] = infra_data["name"]
            if 'state' in infra_data:
                infrastructures[inf_id]['state'] = infra_data["state"]

        return render_template('infrastructures.html',
                               infrastructures=infrastructures,
                               reload=reload_infid)

    @app.route('/infrastructures/state')
    @authorized_with_valid_token
    def infrastructure_state():
        access_token = oidc_blueprint.session.token['access_token']
        infid = request.args['infid']
        if not infid:
            return {"state": "error", "vm_states": {}}

        auth_data = utils.getUserAuthData(access_token, cred,
                                          session["userid"])
        try:
            state = im.get_inf_state(infid, auth_data)
            try:
                infra.write_infra(infid, {"state": state})
            except Exception as ex:
                app.logger.error("Error saving infrastructure state: %s" % ex)
            return state
        except Exception:
            return {"state": "error", "vm_states": {}}

    @app.route('/template/<infid>')
    @authorized_with_valid_token
    def template(infid=None):
        access_token = oidc_blueprint.session.token['access_token']
        auth_data = utils.getUserAuthData(access_token, cred,
                                          session["userid"])
        template = ""
        try:
            response = im.get_inf_property(infid, 'tosca', auth_data)
            if not response.ok:
                raise Exception(response.text)
            template = response.text
        except Exception as ex:
            flash("Error getting template: \n%s" % ex, "error")

        return render_template('deptemplate.html', template=template)

    def add_colors(log):
        """Add color in error messages in logs."""
        res = ""
        lines = log.split('\n')
        for n, line in enumerate(lines):
            if "ERROR executing task" in line or (
                    "fatal: " in line and "...ignoring" not in lines[n + 1]):
                res += Markup(
                    '<span class="bg-danger text-white">%s</span><br>' % line)
            else:
                res += Markup("%s<br>" % line)
        return res

    @app.route('/log/<infid>')
    @authorized_with_valid_token
    def inflog(infid=None):
        access_token = oidc_blueprint.session.token['access_token']
        auth_data = utils.getUserAuthData(access_token, cred,
                                          session["userid"])
        log = "Not found"
        try:
            response = im.get_inf_property(infid, 'contmsg', auth_data)
            if not response.ok:
                raise Exception(response.text)
            log = add_colors(response.text)
        except Exception as ex:
            flash("Error: %s." % ex, 'error')

        return render_template('inflog.html', log=log)

    @app.route('/vmlog/<infid>/<vmid>')
    @authorized_with_valid_token
    def vmlog(infid=None, vmid=None):

        access_token = oidc_blueprint.session.token['access_token']
        auth_data = utils.getUserAuthData(access_token, cred,
                                          session["userid"])
        log = "Not found"
        try:
            response = im.get_vm_contmsg(infid, vmid, auth_data)
            if not response.ok:
                raise Exception(response.text)
            log = add_colors(response.text)
        except Exception as ex:
            flash("Error: %s." % ex, 'error')

        return render_template('inflog.html', log=log, vmid=vmid)

    @app.route('/outputs/<infid>')
    @authorized_with_valid_token
    def infoutputs(infid=None):

        access_token = oidc_blueprint.session.token['access_token']
        auth_data = utils.getUserAuthData(access_token, cred,
                                          session["userid"])
        outputs = {}
        try:
            response = im.get_inf_property(infid, 'outputs', auth_data)
            if not response.ok:
                raise Exception(response.text)

            outputs = response.json()["outputs"]
            for elem in outputs:
                if isinstance(outputs[elem],
                              str) and (outputs[elem].startswith('http://') or
                                        outputs[elem].startswith('https://')):
                    outputs[elem] = Markup(
                        "<a href='%s' target='_blank'>%s</a>" %
                        (outputs[elem], outputs[elem]))
        except Exception as ex:
            flash("Error: %s." % ex, 'error')

        return render_template('outputs.html', infid=infid, outputs=outputs)

    @app.route('/configure')
    @authorized_with_valid_token
    def configure():

        selected_tosca = request.args['selected_tosca']

        app.logger.debug("Template: " + json.dumps(toscaInfo[selected_tosca]))

        creds = cred.get_creds(session['userid'], 1)

        return render_template('createdep.html',
                               template=toscaInfo[selected_tosca],
                               selectedTemplate=selected_tosca,
                               creds=creds)

    @app.route('/vos')
    def getvos():
        res = ""
        vos = utils.getStaticVOs()
        vos.extend(appdb.get_vo_list())
        vos = list(set(vos))
        if "vos" in session and session["vos"]:
            vos = [vo for vo in vos if vo in session["vos"]]
        for vo in vos:
            res += '<option name="selectedVO" value=%s>%s</option>' % (vo, vo)
        return res

    @app.route('/sites/<vo>')
    def getsites(vo=None):
        res = ""
        static_sites = utils.getStaticSites(vo)
        for site_name, site in static_sites.items():
            res += '<option name="selectedSite" value=%s>%s</option>' % (
                site['url'], site_name)

        appdb_sites = appdb.get_sites(vo)
        for site_name, site in appdb_sites.items():
            # avoid site duplication
            if site_name not in static_sites:
                if site["state"]:
                    site["state"] = " (WARNING: %s state!)" % site["state"]
                res += '<option name="selectedSite" value=%s>%s%s</option>' % (
                    site['url'], site_name, site["state"])

        return res

    @app.route('/images/<cred_id>')
    @authorized_with_valid_token
    def getimages(cred_id=None):
        res = ""
        local = request.args.get('local', None)

        if local:
            access_token = oidc_blueprint.session.token['access_token']
            auth_data = utils.getUserAuthData(access_token, cred,
                                              session["userid"], cred_id)
            try:
                response = im.get_cloud_images(cred_id, auth_data)
                if not response.ok:
                    raise Exception(response.text)
                for image in response.json()["images"]:
                    res += '<option name="selectedSiteImage" value=%s>%s</option>' % (
                        image['uri'], image['name'])
            except Exception as ex:
                res += '<option name="selectedSiteImage" value=%s>%s</option>' % (
                    ex, ex)

        else:
            site, _, vo = utils.get_site_info(cred_id, cred, session["userid"])
            for image_name, image_id in appdb.get_images(site['id'], vo):
                res += '<option name="selectedImage" value=%s>%s</option>' % (
                    image_id, image_name)
        return res

    @app.route('/usage/<cred_id>')
    @authorized_with_valid_token
    def getusage(cred_id=None):
        access_token = oidc_blueprint.session.token['access_token']
        auth_data = utils.getUserAuthData(access_token, cred,
                                          session["userid"], cred_id)
        try:
            response = im.get_cloud_quotas(cred_id, auth_data)
            if not response.ok:
                raise Exception(response.text)
            return json.dumps(response.json()["quotas"])
        except Exception as ex:
            return "Error loading site quotas: %s!" % str(ex), 400

    def add_image_to_template(template, image):
        # Add the image to all compute nodes

        for node in list(
                template['topology_template']['node_templates'].values()):
            if node["type"] == "tosca.nodes.indigo.Compute":
                node["capabilities"]["os"]["properties"]["image"] = image

        app.logger.debug(yaml.dump(template, default_flow_style=False))

        return template

    def add_auth_to_template(template, auth_data):
        # Add the auth_data ElasticCluster node

        for node in list(
                template['topology_template']['node_templates'].values()):
            if node["type"] == "tosca.nodes.ec3.ElasticCluster":
                if "properties" not in node:
                    node["properties"] = {}
                node["properties"]["im_auth"] = auth_data

        app.logger.debug(yaml.dump(template, default_flow_style=False))

        return template

    def add_record_name_to_template(template, replace_name):
        # Add a random name in the DNS record name

        for node in list(
                template['topology_template']['node_templates'].values()):
            if node["type"] == "tosca.nodes.ec3.DNSRegistry":
                node["properties"]["record_name"] = node["properties"][
                    "record_name"].replace("*", replace_name)

        return template

    def set_inputs_to_template(template, inputs):
        # Add the image to all compute nodes

        for name, value in template['topology_template']['inputs'].items():
            if name in inputs:
                if value["type"] == "integer":
                    value["default"] = int(inputs[name])
                elif value["type"] == "float":
                    value["default"] = float(inputs[name])
                elif value["type"] == "boolean":
                    if inputs[name].lower() in ['yes', 'true', '1']:
                        value["default"] = True
                    else:
                        value["default"] = False
                # Special case for ports, convert a comma separated list of ints
                # to a PortSpec map
                elif value["type"] == "map" and name == "ports":
                    ports = inputs[name].split(",")
                    ports_value = {}
                    for port in ports:
                        # Should we also open UDP?
                        ports_value["port_%s" % port] = {
                            "protocol": "tcp",
                            "source": int(port)
                        }
                    value["default"] = ports_value
                else:
                    value["default"] = inputs[name]

        app.logger.debug(yaml.dump(template, default_flow_style=False))
        return template

    @app.route('/submit', methods=['POST'])
    @authorized_with_valid_token
    def createdep():

        form_data = request.form.to_dict()

        app.logger.debug("Form data: " + json.dumps(request.form.to_dict()))

        cred_id = form_data['extra_opts.selectedCred']
        cred_data = cred.get_cred(cred_id, session["userid"])
        access_token = oidc_blueprint.session.token['access_token']

        image = None
        if cred_data['type'] in [
                'fedcloud', 'OpenStack', 'OpenNebula', 'Linode', 'Orange',
                'GCE'
        ]:
            if form_data['extra_opts.selectedImage'] != "":
                site, _, vo = utils.get_site_info(cred_id, cred,
                                                  session["userid"])
                image = "appdb://%s/%s?%s" % (
                    site['name'], form_data['extra_opts.selectedImage'], vo)
            elif form_data['extra_opts.selectedSiteImage'] != "":
                image = form_data['extra_opts.selectedSiteImage']
        else:
            image_id = form_data['extra_opts.imageID']
            protocol_map = {
                'EC2': 'aws',
                'Kubernetes': 'docker',
                'Azure': 'azr'
            }
            image = "%s://%s" % (protocol_map.get(cred_data['type']), image_id)

        if not image:
            flash("No correct image specified.", "error")
            return redirect(url_for('showinfrastructures'))

        auth_data = utils.getUserAuthData(access_token, cred,
                                          session["userid"], cred_id)

        with io.open(settings.toscaDir +
                     request.args.get('template')) as stream:
            template = yaml.full_load(stream)
            template = add_image_to_template(template, image)

        template = add_image_to_template(template, image)

        template = add_auth_to_template(template, auth_data)

        # Specially added for OSCAR clusters
        template = add_record_name_to_template(template,
                                               utils.generate_random_name())

        inputs = {
            k: v
            for (k, v) in form_data.items() if not k.startswith("extra_opts.")
        }

        app.logger.debug("Parameters: " + json.dumps(inputs))

        template = set_inputs_to_template(template, inputs)

        payload = yaml.dump(template,
                            default_flow_style=False,
                            sort_keys=False)

        try:
            response = im.create_inf(payload, auth_data)
            if not response.ok:
                raise Exception(response.text)

            try:
                inf_id = os.path.basename(response.text)
                infra.write_infra(
                    inf_id, {
                        "name": form_data['infra_name'],
                        "state": {
                            "state": "pending",
                            "vm_states": {}
                        }
                    })
            except Exception as ex:
                flash("Error storing Infrastructure name: %s" % str(ex),
                      "warning")

        except Exception as ex:
            flash("Error creating infrastrucrure: \n%s." % ex, 'error')

        return redirect(url_for('showinfrastructures'))

    @app.route('/manage_creds')
    @authorized_with_valid_token
    def manage_creds():
        creds = {}

        try:
            creds = cred.get_creds(session["userid"])

        except Exception as e:
            flash("Error retrieving credentials: \n" + str(e), 'warning')

        return render_template('service_creds.html', creds=creds)

    @app.route('/write_creds', methods=['GET', 'POST'])
    @authorized_with_valid_token
    def write_creds():
        cred_id = request.args.get('cred_id', "")
        cred_type = request.args.get('cred_type', "")
        app.logger.debug("service_id={}".format(cred_id))

        if request.method == 'GET':
            res = {}
            try:
                if cred_id:
                    res = cred.get_cred(cred_id, session["userid"])
                    cred_type = res['type']
            except Exception as ex:
                flash("Error reading credentials %s!" % ex, 'error')

            return render_template('modal_creds.html',
                                   creds=res,
                                   cred_id=cred_id,
                                   cred_type=cred_type)
        else:
            app.logger.debug("Form data: " +
                             json.dumps(request.form.to_dict()))

            creds = request.form.to_dict()
            if 'cred_id' in creds:
                cred_id = creds['cred_id']
                del creds['cred_id']
            if 'password' in request.files:
                if request.files['password'].filename != "":
                    creds['password'] = request.files['password'].read(
                    ).decode()
            try:
                if 'password' in creds and creds['password'] in [None, '']:
                    del creds['password']
                if 'csrf_token' in creds:
                    del creds['csrf_token']
                cred.write_creds(creds["id"], session["userid"], creds, cred_id
                                 in [None, ''])
                flash("Credentials successfully written!", 'info')
            except db.IntegrityError:
                flash("Error writing credentials: Duplicated Credential ID!",
                      'error')
            except Exception as ex:
                flash("Error writing credentials: %s!" % ex, 'error')

            return redirect(url_for('manage_creds'))

    @app.route('/delete_creds')
    @authorized_with_valid_token
    def delete_creds():

        cred_id = request.args.get('cred_id', "")
        try:
            cred.delete_cred(cred_id, session["userid"])
            flash("Credentials successfully deleted!", 'info')
        except Exception as ex:
            flash("Error deleting credentials %s!" % ex, 'error')

        return redirect(url_for('manage_creds'))

    @app.route('/enable_creds')
    @authorized_with_valid_token
    def enable_creds():
        cred_id = request.args.get('cred_id', "")
        enable = request.args.get('enable', 0)
        try:
            cred.enable_cred(cred_id, session["userid"], enable)
        except Exception as ex:
            flash("Error updating credentials %s!" % ex, 'error')

        return redirect(url_for('manage_creds'))

    @app.route('/addresourcesform/<infid>')
    @authorized_with_valid_token
    def addresourcesform(infid=None):

        access_token = oidc_blueprint.session.token['access_token']

        auth_data = utils.getUserAuthData(access_token, cred,
                                          session["userid"])
        try:
            response = im.get_inf_property(infid, 'radl', auth_data)
            if not response.ok:
                raise Exception(response.text)

            systems = []
            try:
                radl = radl_parse.parse_radl(response.text)
                systems = radl.systems
            except Exception as ex:
                flash("Error parsing RADL: \n%s" % str(ex), 'error')

            return render_template('addresource.html',
                                   infid=infid,
                                   systems=systems)
        except Exception as ex:
            flash("Error getting RADL: \n%s" % ex, 'error')
            return redirect(url_for('showinfrastructures'))

    @app.route('/addresources/<infid>', methods=['POST'])
    @authorized_with_valid_token
    def addresources(infid=None):

        access_token = oidc_blueprint.session.token['access_token']
        form_data = request.form.to_dict()

        auth_data = utils.getUserAuthData(access_token, cred,
                                          session["userid"])
        try:
            response = im.get_inf_property(infid, 'radl', auth_data)
        except Exception as ex:
            flash("Error: %s." % ex, 'error')

        if response.ok:
            radl = None
            try:
                radl = radl_parse.parse_radl(response.text)
                radl.deploys = []
                for system in radl.systems:
                    sys_dep = deploy(system.name, 0)
                    if "%s_num" % system.name in form_data:
                        vm_num = int(form_data["%s_num" % system.name])
                        if vm_num > 0:
                            sys_dep.vm_number = vm_num
                    radl.deploys.append(sys_dep)
            except Exception as ex:
                flash(
                    "Error parsing RADL: \n%s\n%s" % (str(ex), response.text),
                    'error')

            if radl:
                try:
                    response = im.addresource_inf(infid, str(radl), auth_data)
                    if not response.ok:
                        raise Exception(response.text)
                    num = len(response.json()["uri-list"])
                    flash("%d nodes added successfully" % num, 'info')
                except Exception as ex:
                    flash("Error adding nodes: \n%s\n%s" % (ex, response.text),
                          'error')

            return redirect(url_for('showinfrastructures'))
        else:
            flash("Error getting RADL: \n%s" % (response.text), 'error')
            return redirect(url_for('showinfrastructures'))

    @app.route('/manage_inf/<infid>/<op>', methods=['POST'])
    @authorized_with_valid_token
    def manage_inf(infid=None, op=None):
        access_token = oidc_blueprint.session.token['access_token']
        auth_data = utils.getUserAuthData(access_token, cred,
                                          session["userid"])
        reload = None

        try:
            if op in ["start", "stop"]:
                response = im.manage_inf(op, infid, auth_data)
                if not response.ok:
                    raise Exception(response.text)
                flash(
                    "Operation '%s' successfully made on Infrastructure ID: %s"
                    % (op, infid), 'info')
                reload = infid
            elif op == "delete":
                form_data = request.form.to_dict()
                force = False
                if 'force' in form_data and form_data['force'] != "0":
                    force = True
                # Specially added for OSCAR clusters
                success, msg = utils.delete_dns_record(infid, im, auth_data)
                if not success:
                    app.logger.error('Error deleting DNS record: %s', (msg))
                response = im.delete_inf(infid, force, auth_data)
                if not response.ok:
                    raise Exception(response.text)
                flash("Infrastructure '%s' successfuly deleted." % infid,
                      "info")
                try:
                    infra_data = infra.get_infra(infid)
                    infra_data["state"]["state"] = "deleting"
                    infra.write_infra(infid, infra_data)
                    scheduler.add_job('delete_infra_%s' % infid,
                                      delete_infra,
                                      trigger='interval',
                                      seconds=60,
                                      args=(infid, ))
                except Exception as dex:
                    app.logger.error(
                        'Error setting infra state to deleting.: %s', (dex))
            elif op == "reconfigure":
                response = im.reconfigure_inf(infid, auth_data)
                if not response.ok:
                    raise Exception(response.text)
                flash("Reconfiguration process successfuly started.", "info")
        except Exception as ex:
            flash("Error in '%s' operation: %s." % (op, ex), 'error')

        return redirect(url_for('showinfrastructures', reload=reload))

    @app.route('/logout')
    def logout():
        session.clear()
        oidc_blueprint.session.get("/logout")
        return redirect(url_for('login'))

    @app.errorhandler(403)
    def forbidden(error):
        return render_template('error_pages/403.html',
                               message=error.description)

    @app.errorhandler(404)
    def page_not_found(error):
        app.logger.error('Page not found: %s', (request.path))
        return render_template('error_pages/404.html'), 404

    @app.errorhandler(500)
    def internal_server_error(error):
        app.logger.error('Server Error: %s', (error))
        return render_template(
            'error_pages/500.html',
            support_email=app.config.get('SUPPORT_EMAIL')), 500

    # Reload internally the site cache
    @scheduler.task('interval', id='reload_sites', seconds=5)
    def reload_sites():
        scheduler.modify_job('reload_sites',
                             trigger='interval',
                             seconds=settings.appdb_cache_timeout - 30)
        with app.app_context():
            app.logger.debug('Reload Site List.')
            g.settings = settings
            utils.getCachedSiteList(True)

    def delete_infra(infid):
        infra.delete_infra(infid)
        scheduler.delete_job('delete_infra_%s' % infid)

    return app
Beispiel #15
0
def make_google_blueprint(client_id=None,
                          client_secret=None,
                          scope=None,
                          offline=False,
                          reprompt_consent=False,
                          redirect_url=None,
                          redirect_to=None,
                          login_url=None,
                          authorized_url=None,
                          session_class=None,
                          backend=None):
    """
    Make a blueprint for authenticating with Google using OAuth 2. This requires
    a client ID and client secret from Google. You should either pass them to
    this constructor, or make sure that your Flask application config defines
    them, using the variables GOOGLE_OAUTH_CLIENT_ID and GOOGLE_OAUTH_CLIENT_SECRET.

    Args:
        client_id (str): The client ID for your application on Google
        client_secret (str): The client secret for your application on Google
        scope (str, optional): comma-separated list of scopes for the OAuth token.
            Defaults to the "https://www.googleapis.com/auth/userinfo.profile" scope.
        offline (bool): Whether to request `offline access
            <https://developers.google.com/accounts/docs/OAuth2WebServer#offline>`_
            for the OAuth token. Defaults to False
        reprompt_consent (bool): If True, force Google to re-prompt the user
            for their consent, even if the user has already given their
            consent. Defaults to False
        redirect_url (str): the URL to redirect to after the authentication
            dance is complete
        redirect_to (str): if ``redirect_url`` is not defined, the name of the
            view to redirect to after the authentication dance is complete.
            The actual URL will be determined by :func:`flask.url_for`
        login_url (str, optional): the URL path for the ``login`` view.
            Defaults to ``/google``
        authorized_url (str, optional): the URL path for the ``authorized`` view.
            Defaults to ``/google/authorized``.
        session_class (class, optional): The class to use for creating a
            Requests session. Defaults to
            :class:`~flask_dance.consumer.requests.OAuth2Session`.
        backend: A storage backend class, or an instance of a storage
                backend class, to use for this blueprint. Defaults to
                :class:`~flask_dance.consumer.backend.session.SessionBackend`.

    :rtype: :class:`~flask_dance.consumer.OAuth2ConsumerBlueprint`
    :returns: A :ref:`blueprint <flask:blueprints>` to attach to your Flask app.
    """
    scope = scope or ["https://www.googleapis.com/auth/userinfo.profile"]
    authorization_url_params = {}
    if offline:
        authorization_url_params["access_type"] = "offline"
    if reprompt_consent:
        authorization_url_params["approval_prompt"] = "force"
    google_bp = OAuth2ConsumerBlueprint(
        "google",
        __name__,
        client_id=client_id,
        client_secret=client_secret,
        scope=scope,
        base_url="https://www.googleapis.com/",
        authorization_url="https://accounts.google.com/o/oauth2/auth",
        token_url="https://accounts.google.com/o/oauth2/token",
        auto_refresh_url="https://accounts.google.com/o/oauth2/token",
        redirect_url=redirect_url,
        redirect_to=redirect_to,
        login_url=login_url,
        authorized_url=authorized_url,
        authorization_url_params=authorization_url_params,
        session_class=session_class,
        backend=backend,
    )
    google_bp.from_config["client_id"] = "GOOGLE_OAUTH_CLIENT_ID"
    google_bp.from_config["client_secret"] = "GOOGLE_OAUTH_CLIENT_SECRET"

    @google_bp.before_app_request
    def set_applocal_session():
        ctx = stack.top
        ctx.google_oauth = google_bp.session

    return google_bp
import os

from flask import redirect, url_for
from flask_dance.consumer import OAuth2ConsumerBlueprint
from flask_login import current_user, login_required

from .app import app
from .models import Event, ANONYMOUS_EMAIL, User

splitwise_blueprint = OAuth2ConsumerBlueprint(
    "splitwise",
    __name__,
    client_id=os.environ.get("SPLITWISE_KEY"),
    client_secret=os.environ.get("SPLITWISE_SECRET"),
    base_url="https://secure.splitwise.com/",
    token_url="https://secure.splitwise.com/oauth/token",
    authorization_url="https://secure.splitwise.com/oauth/authorize",
)
app.register_blueprint(splitwise_blueprint)

splitwise = splitwise_blueprint.session


@app.route("/splitwise/allow")
@login_required
def allow_splitwise():
    if not splitwise.authorized:
        return redirect(url_for("splitwise.login"))
    resp = splitwise.get("/api/v3.0/get_current_user")
    data = resp.json()
    splitwise_id = str(data["user"]["id"])
Beispiel #17
0
from utils.launch_tasks import start_task

API_VERSION = config.API_VERSION
CURRENT_DATE = datetime.strftime(datetime.now(), '%Y%m%d')

os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'

app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1)
app.secret_key = config.OAUTH2['SECRET_KEY']

oauth_blueprint = OAuth2ConsumerBlueprint(
    "oauth",
    __name__,
    client_id=config.OAUTH2['CLIENT_ID'],
    client_secret=config.OAUTH2['SECRET_KEY'],
    base_url=config.OAUTH2['BASE_URL'],
    token_url=config.OAUTH2['TOKEN_URL'],
    authorization_url=config.OAUTH2['AUTHORIZATION_URL'],
    redirect_url='/',
    scope='default')

app.register_blueprint(oauth_blueprint)


def get_user() -> dict:
    auth = session.get('oauth_oauth_token')

    if auth:
        return auth.get('user')
    return None
Beispiel #18
0
def make_authentiq_blueprint(
    client_id=None,
    client_secret=None,
    scope="openid profile",
    redirect_url=None,
    redirect_to=None,
    login_url=None,
    authorized_url=None,
    session_class=None,
    backend=None,
    storage=None,
    hostname="connect.authentiq.io",
):
    """
    Make a blueprint for authenticating with authentiq using OAuth 2. This requires
    a client ID and client secret from authentiq. You should either pass them to
    this constructor, or make sure that your Flask application config defines
    them, using the variables AUTHENTIQ_OAUTH_CLIENT_ID and
    AUTHENTIQ_OAUTH_CLIENT_SECRET.

    Args:
        client_id (str): The client ID for your application on Authentiq.
        client_secret (str): The client secret for your application on Authentiq.
        scope (str, optional): comma-separated list of scopes for the OAuth token.
        redirect_url (str): the URL to redirect to after the authentication
            dance is complete.
        redirect_to (str): if ``redirect_url`` is not defined, the name of the
            view to redirect to after the authentication dance is complete.
            The actual URL will be determined by :func:`flask.url_for`.
        login_url (str, optional): the URL path for the ``login`` view.
            Defaults to ``/authentiq``.
        authorized_url (str, optional): the URL path for the ``authorized`` view.
            Defaults to ``/authentiq/authorized``.
        session_class (class, optional): The class to use for creating a
            Requests session. Defaults to
            :class:`~flask_dance.consumer.requests.OAuth2Session`.
        storage: A token storage class, or an instance of a token storage
                class, to use for this blueprint. Defaults to
                :class:`~flask_dance.consumer.storage.session.SessionStorage`.
        hostname (str, optional): If using a private instance of authentiq CE/EE,
            specify the hostname, default is ``connect.authentiq.io``

    :rtype: :class:`~flask_dance.consumer.OAuth2ConsumerBlueprint`
    :returns: A :ref:`blueprint <flask:blueprints>` to attach to your Flask app.
    """
    authentiq_bp = OAuth2ConsumerBlueprint(
        "authentiq",
        __name__,
        client_id=client_id,
        client_secret=client_secret,
        scope=scope,
        base_url="https://{hostname}/".format(hostname=hostname),
        authorization_url="https://{hostname}/authorize".format(hostname=hostname),
        token_url="https://{hostname}/token".format(hostname=hostname),
        redirect_url=redirect_url,
        redirect_to=redirect_to,
        login_url=login_url,
        authorized_url=authorized_url,
        session_class=session_class,
        backend=backend,
        storage=storage,
    )
    authentiq_bp.from_config["client_id"] = "AUTHENTIQ_OAUTH_CLIENT_ID"
    authentiq_bp.from_config["client_secret"] = "AUTHENTIQ_OAUTH_CLIENT_SECRET"

    @authentiq_bp.before_app_request
    def set_applocal_session():
        ctx = stack.top
        ctx.authentiq_oauth = authentiq_bp.session

    return authentiq_bp
Beispiel #19
0
logging.basicConfig(level=logging.DEBUG)

app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app)
app.secret_key="30bb7cf2-1fef-4d26-83f0-8096b6dcc7a3"
app.config.from_json('config.json')

iam_base_url=app.config['IAM_BASE_URL']
iam_token_url=iam_base_url + '/token'
iam_refresh_url=iam_base_url + '/token'
iam_authorization_url=iam_base_url + '/authorize'

iam_blueprint = OAuth2ConsumerBlueprint(
    "iam", __name__,
    client_id=app.config['IAM_CLIENT_ID'],
    client_secret=app.config['IAM_CLIENT_SECRET'],
    scope='openid email profile offline_access',
    base_url=iam_base_url,
    token_url=iam_token_url,
    auto_refresh_url=iam_refresh_url,
    authorization_url=iam_authorization_url,
    redirect_to='home'
)
app.register_blueprint(iam_blueprint, url_prefix="/login")

from app import routes, errors

if __name__ == "__main__":
    app.run(host='0.0.0.0')

Beispiel #20
0
def make_digitalocean_blueprint(
    client_id=None,
    client_secret=None,
    scope=None,
    redirect_url=None,
    redirect_to=None,
    login_url=None,
    authorized_url=None,
    session_class=None,
    storage=None,
):
    """
    Make a blueprint for authenticating with Digital Ocean using OAuth 2.
    This requires a client ID and client secret from Digital Ocean.
    You should either pass them to this constructor, or make sure that your
    Flask application config defines them, using the variables
    :envvar:`DIGITALOCEAN_OAUTH_CLIENT_ID` and
    :envvar:`DIGITALOCEAN_OAUTH_CLIENT_SECRET`.

    Args:
        client_id (str): Client ID for your application on Digital Ocean
        client_secret (str): Client secret for your Digital Ocean application
        scope (str, optional): comma-separated list of scopes for the OAuth
            token.
        redirect_url (str): the URL to redirect to after the authentication
            dance is complete
        redirect_to (str): if ``redirect_url`` is not defined, the name of the
            view to redirect to after the authentication dance is complete.
            The actual URL will be determined by :func:`flask.url_for`
        login_url (str, optional): the URL path for the ``login`` view.
            Defaults to ``/digitalocean``
        authorized_url (str, optional): the URL path for the ``authorized`` view.
            Defaults to ``/digitalocean/authorized``.
        session_class (class, optional): The class to use for creating a
            Requests session. Defaults to
            :class:`~flask_dance.consumer.requests.OAuth2Session`.
        storage: A token storage class, or an instance of a token storage
                class, to use for this blueprint. Defaults to
                :class:`~flask_dance.consumer.storage.session.SessionStorage`.

    :rtype: :class:`~flask_dance.consumer.OAuth2ConsumerBlueprint`
    :returns: A :ref:`blueprint <flask:blueprints>` to attach to your Flask app.
    """
    digitalocean_bp = OAuth2ConsumerBlueprint(
        "digitalocean",
        __name__,
        client_id=client_id,
        client_secret=client_secret,
        scope=scope.replace(",", " ") if scope else None,
        base_url="https://cloud.digitalocean.com/v1/oauth",
        authorization_url="https://cloud.digitalocean.com/v1/oauth/authorize",
        token_url="https://cloud.digitalocean.com/v1/oauth/token",
        redirect_url=redirect_url,
        redirect_to=redirect_to,
        login_url=login_url,
        authorized_url=authorized_url,
        session_class=session_class,
        storage=storage,
    )
    digitalocean_bp.from_config["client_id"] = "DIGITALOCEAN_OAUTH_CLIENT_ID"
    digitalocean_bp.from_config[
        "client_secret"] = "DIGITALOCEAN_OAUTH_CLIENT_SECRET"

    @digitalocean_bp.before_app_request
    def set_applocal_session():
        ctx = stack.top
        ctx.digitalocean_oauth = digitalocean_bp.session

    return digitalocean_bp
Beispiel #21
0
def make_google_blueprint(
    client_id=None,
    client_secret=None,
    *,
    scope=None,
    offline=False,
    reprompt_consent=False,
    reprompt_select_account=False,
    redirect_url=None,
    redirect_to=None,
    login_url=None,
    authorized_url=None,
    session_class=None,
    storage=None,
    hosted_domain=None,
    rule_kwargs=None,
):
    """
    Make a blueprint for authenticating with Google using OAuth 2. This requires
    a client ID and client secret from Google. You should either pass them to
    this constructor, or make sure that your Flask application config defines
    them, using the variables :envvar:`GOOGLE_OAUTH_CLIENT_ID` and
    :envvar:`GOOGLE_OAUTH_CLIENT_SECRET`.

    Args:
        client_id (str): The client ID for your application on Google
        client_secret (str): The client secret for your application on Google
        scope (str, optional): comma-separated list of scopes for the OAuth token.
            Defaults to the "https://www.googleapis.com/auth/userinfo.profile" scope.
        offline (bool): Whether to request `offline access
            <https://developers.google.com/accounts/docs/OAuth2WebServer#offline>`_
            for the OAuth token. Defaults to False
        reprompt_consent (bool): If True, force Google to re-prompt the user
            for their consent, even if the user has already given their
            consent. Defaults to False
        reprompt_select_account (bool): If True, force Google to re-prompt the select account page,
            even if there is a single logged-in user. Defaults to False
        redirect_url (str): the URL to redirect to after the authentication
            dance is complete
        redirect_to (str): if ``redirect_url`` is not defined, the name of the
            view to redirect to after the authentication dance is complete.
            The actual URL will be determined by :func:`flask.url_for`
        login_url (str, optional): the URL path for the ``login`` view.
            Defaults to ``/google``
        authorized_url (str, optional): the URL path for the ``authorized`` view.
            Defaults to ``/google/authorized``.
        session_class (class, optional): The class to use for creating a
            Requests session. Defaults to
            :class:`~flask_dance.consumer.requests.OAuth2Session`.
        storage: A token storage class, or an instance of a token storage
                class, to use for this blueprint. Defaults to
                :class:`~flask_dance.consumer.storage.session.SessionStorage`.
        hosted_domain (str, optional): The domain of the G Suite user. Used to indicate that the account selection UI
            should be optimized for accounts at this domain. Note that this only provides UI optimization, and requires
            response validation (see warning).
        rule_kwargs (dict, optional): Additional arguments that should be passed when adding
            the login and authorized routes. Defaults to ``None``.

    .. _google_hosted_domain_warning:
    .. warning::
       The ``hosted_domain`` argument **only provides UI optimization**. Don't rely on this argument to control
       who can access your application. You must verify that the ``hd`` claim of the response ID token matches the
       ``hosted_domain`` argument passed to ``make_google_blueprint``.

    :rtype: :class:`~flask_dance.consumer.OAuth2ConsumerBlueprint`
    :returns: A :doc:`blueprint <flask:blueprints>` to attach to your Flask app.
    """
    scope = scope or ["https://www.googleapis.com/auth/userinfo.profile"]
    authorization_url_params = {}
    prompt_params = []
    auto_refresh_url = None
    if offline:
        authorization_url_params["access_type"] = "offline"
        auto_refresh_url = "https://accounts.google.com/o/oauth2/token"
    if reprompt_consent:
        prompt_params.append("consent")
    if reprompt_select_account:
        prompt_params.append("select_account")
    if prompt_params:
        prompt_params = " ".join(prompt_params)
        authorization_url_params["prompt"] = prompt_params
    if hosted_domain:
        authorization_url_params["hd"] = hosted_domain
    google_bp = OAuth2ConsumerBlueprint(
        "google",
        __name__,
        client_id=client_id,
        client_secret=client_secret,
        scope=scope,
        base_url="https://www.googleapis.com/",
        authorization_url="https://accounts.google.com/o/oauth2/auth",
        token_url="https://accounts.google.com/o/oauth2/token",
        auto_refresh_url=auto_refresh_url,
        redirect_url=redirect_url,
        redirect_to=redirect_to,
        login_url=login_url,
        authorized_url=authorized_url,
        authorization_url_params=authorization_url_params,
        session_class=session_class,
        storage=storage,
        rule_kwargs=rule_kwargs,
    )
    google_bp.from_config["client_id"] = "GOOGLE_OAUTH_CLIENT_ID"
    google_bp.from_config["client_secret"] = "GOOGLE_OAUTH_CLIENT_SECRET"

    @google_bp.before_app_request
    def set_applocal_session():
        ctx = stack.top
        ctx.google_oauth = google_bp.session

    return google_bp
Beispiel #22
0
def make_heroku_blueprint(
    client_id=None,
    client_secret=None,
    *,
    scope=None,
    api_version="3",
    redirect_url=None,
    redirect_to=None,
    login_url=None,
    authorized_url=None,
    session_class=None,
    storage=None,
    rule_kwargs=None,
):
    """
    Make a blueprint for authenticating with Heroku using OAuth 2. This requires
    a client ID and client secret from Heroku. You should either pass them to
    this constructor, or make sure that your Flask application config defines
    them, using the variables :envvar:`HEROKU_OAUTH_CLIENT_ID` and
    :envvar:`HEROKU_OAUTH_CLIENT_SECRET`.

    Args:
        client_id (str): The client ID for your application on Heroku.
        client_secret (str): The client secret for your application on Heroku
        scope (str, optional): comma-separated list of scopes for the OAuth token
        api_version (str): The version number of the Heroku API you want to use.
            Defaults to version 3.
        redirect_url (str): the URL to redirect to after the authentication
            dance is complete
        redirect_to (str): if ``redirect_url`` is not defined, the name of the
            view to redirect to after the authentication dance is complete.
            The actual URL will be determined by :func:`flask.url_for`
        login_url (str, optional): the URL path for the ``login`` view.
            Defaults to ``/heroku``
        authorized_url (str, optional): the URL path for the ``authorized`` view.
            Defaults to ``/heroku/authorized``.
        session_class (class, optional): The class to use for creating a
            Requests session. Defaults to
            :class:`~flask_dance.contrib.HerokuOAuth2Session`.
        storage: A token storage class, or an instance of a token storage
                class, to use for this blueprint. Defaults to
                :class:`~flask_dance.consumer.storage.session.SessionStorage`.
        rule_kwargs (dict, optional): Additional arguments that should be passed when adding
            the login and authorized routes. Defaults to ``None``.

    :rtype: :class:`~flask_dance.consumer.OAuth2ConsumerBlueprint`
    :returns: A :doc:`blueprint <flask:blueprints>` to attach to your Flask app.
    """
    heroku_bp = OAuth2ConsumerBlueprint(
        "heroku",
        __name__,
        client_id=client_id,
        client_secret=client_secret,
        scope=scope,
        api_version=api_version,
        base_url="https://api.heroku.com/",
        authorization_url="https://id.heroku.com/oauth/authorize",
        token_url="https://id.heroku.com/oauth/token",
        redirect_url=redirect_url,
        redirect_to=redirect_to,
        login_url=login_url,
        authorized_url=authorized_url,
        session_class=session_class or HerokuOAuth2Session,
        storage=storage,
        rule_kwargs=rule_kwargs,
    )
    heroku_bp.from_config["client_id"] = "HEROKU_OAUTH_CLIENT_ID"
    heroku_bp.from_config["client_secret"] = "HEROKU_OAUTH_CLIENT_SECRET"

    @heroku_bp.before_app_request
    def set_applocal_session():
        g.flask_dance_heroku = heroku_bp.session

    return heroku_bp
Beispiel #23
0
def make_orcid_blueprint(
    client_id=None,
    client_secret=None,
    scope=None,
    offline=False,
    redirect_url=None,
    redirect_to=None,
    login_url=None,
    authorized_url=None,
    session_class=None,
    storage=None
):
    """
    This function actually creates a specific orchid blueprint for use with Flask Dance
    Args:
      client_id: Override the client id provided in config
      client_secret: Ovveride the client secret provided in the config
      scope: list of scopes for the oauth
      offline: is this online or offline
      redirect_url: Ovveride the redirect_url from Flask-Login
      redirect_to: OVveride the redirect_to from Flask-Login
      login_url: OVerrid the Login_url from Flask-login
      authorized_url: Override the authorized_url from Flask-Dance
      session_class: provide a custom OAuth session
      storage: storage for the token
    Result:
      Flask Blueprint for app
    """
    scope = scope or ["/authenticate", "/read-limited"]
    session_class = session_class or JsonOath2Session

    _base_url = "https://orcid.org/oauth"
    _token_url = "https://orcid.org/oauth/token"
    _authorization_url = "https://orcid.org/oauth/authorize"

    if os.environ.get("USE_ORCID_OAUTH_SANDBOX"):
        _base_url = "https://api.sandbox.orcid.org/v2.0"
        _token_url = "https://api.sandbox.orcid.org/oauth/token"
        _authorization_url = "https://sandbox.orcid.org/oauth/authorize"

    orcid_bp = OAuth2ConsumerBlueprint(
        "orcid",
        __name__,
        client_id=client_id,
        client_secret=client_secret,
        scope=scope,
        base_url=_base_url,
        token_url=_token_url,
        authorization_url=_authorization_url,
        redirect_url=redirect_url,
        redirect_to=redirect_to,
        login_url=login_url,
        authorized_url=authorized_url,
        session_class=session_class,
        storage=storage
    )

    orcid_bp.from_config["client_id"] = "ORCID_OAUTH_CLIENT_ID"
    orcid_bp.from_config["client_secret"] = "ORCID_OAUTH_CLIENT_SECRET"

    @orcid_bp.before_app_request
    def set_applocal_session():
        """
          sets the orchid session in the current context
        """
        ctx = stack.top
        ctx.orchid_oauth = orcid_bp.session
    return orcid_bp
Beispiel #24
0
from flask import Flask, render_template_string
from flask_dance.consumer import OAuth2ConsumerBlueprint
logging.basicConfig(level=logging.DEBUG)

token_url = "https://app.boson.me/oauth2/token"
client_id = os.getenv('client-id')
client_secret = os.getenv('client-secret')

boson = OAuth2ConsumerBlueprint(
    "boson",
    __name__,
    client_id=client_id,
    client_secret=client_secret,
    base_url="https://app.boson.me",
    token_url=token_url,
    authorization_url="https://app.boson.me/oauth2/authorize",
    scope=['require:phone'],
    auto_refresh_url=token_url,
    auto_refresh_kwargs={
        'client_id': client_id,
        'client_secret': client_secret,
    })

app = Flask(__name__)
app.secret_key = hexlify(os.urandom(24))
app.register_blueprint(boson, url_prefix="/login")


@app.route("/")
def index():
    if not boson.session.authorized:
Beispiel #25
0
def make_discord_blueprint(
    client_id=None,
    client_secret=None,
    scope=None,
    redirect_url=None,
    redirect_to=None,
    login_url=None,
    authorized_url=None,
    session_class=None,
    backend=None,
):
    """
    Make a blueprint for authenticating with Discord using OAuth 2. This requires
    a client ID and client secret from Discord. You should either pass them to
    this constructor, or make sure that your Flask application config defines
    them, using the variables DISCORD_OAUTH_CLIENT_ID and DISCORD_OAUTH_CLIENT_SECRET.

    Args:
        client_id (str): The client ID for your application on Discord.
        client_secret (str): The client secret for your application on Discord
        scope (list, optional): list of scopes (str) for the OAuth token
        redirect_url (str): the URL to redirect to after the authentication
            dance is complete
        redirect_to (str): if ``redirect_url`` is not defined, the name of the
            view to redirect to after the authentication dance is complete.
            The actual URL will be determined by :func:`flask.url_for`
        login_url (str, optional): the URL path for the ``login`` view.
            Defaults to ``/discord``
        authorized_url (str, optional): the URL path for the ``authorized`` view.
            Defaults to ``/discord/authorized``.
        session_class (class, optional): The class to use for creating a
            Requests session. Defaults to
            :class:`~flask_dance.consumer.requests.OAuth2Session`.
        backend: A storage backend class, or an instance of a storage
                backend class, to use for this blueprint. Defaults to
                :class:`~flask_dance.consumer.backend.session.SessionBackend`.

    :rtype: :class:`~flask_dance.consumer.OAuth2ConsumerBlueprint`
    :returns: A :ref:`blueprint <flask:blueprints>` to attach to your Flask app.
    """
    scope = scope or ["identify"]
    discord_bp = OAuth2ConsumerBlueprint(
        "discord",
        __name__,
        client_id=client_id,
        client_secret=client_secret,
        scope=scope,
        base_url="https://discordapp.com/",
        token_url="https://discordapp.com/api/oauth2/token",
        authorization_url="https://discordapp.com/api/oauth2/authorize",
        redirect_url=redirect_url,
        redirect_to=redirect_to,
        login_url=login_url,
        authorized_url=authorized_url,
        session_class=session_class,
        backend=backend,
    )
    discord_bp.from_config["client_id"] = "DISCORD_OAUTH_CLIENT_ID"
    discord_bp.from_config["client_secret"] = "DISCORD_OAUTH_CLIENT_SECRET"

    @discord_bp.before_app_request
    def set_applocal_session():
        ctx = stack.top
        ctx.discord_oauth = discord_bp.session

    return discord_bp
Beispiel #26
0

@login_manager.user_loader
def userloader(user_id):
    curr = User.query.get(user_id)
    if curr is None:
        user_info = hqauth.session.get(config.USER_INFO).json()
        curr = process_userinfo(user_info)
        db.session.add(curr)
        db.session.commit()
    return curr


@login_manager.unauthorized_handler
def unauthorized():
    flash('Please login', 'warning')
    return redirect(url_for('home.homepage'))


hqauth = OAuth2ConsumerBlueprint('oauth',
                                 __name__,
                                 base_url=config.BASE_URL,
                                 token_url=config.ACCESS_TOKEN_URL,
                                 authorization_url=config.AUTHORIZE_URL,
                                 client_id=config.CLIENT_ID,
                                 client_secret=config.CLIENT_SECRET,
                                 scope=config.OAUTH_SCOPE,
                                 redirect_to='oauth.connect')

from . import views
Beispiel #27
0
def make_dropbox_blueprint(
    app_key=None,
    app_secret=None,
    scope=None,
    force_reapprove=False,
    disable_signup=False,
    require_role=None,
    redirect_url=None,
    redirect_to=None,
    login_url=None,
    authorized_url=None,
    session_class=None,
    storage=None,
):
    """
    Make a blueprint for authenticating with Dropbox using OAuth 2. This requires
    a client ID and client secret from Dropbox. You should either pass them to
    this constructor, or make sure that your Flask application config defines
    them, using the variables :envvar:`DROPBOX_OAUTH_CLIENT_ID` and
    :envvar:`DROPBOX_OAUTH_CLIENT_SECRET`.

    For more information about the ``force_reapprove``, ``disable_signup``,
    and ``require_role`` arguments, `check the Dropbox API documentation
    <https://www.dropbox.com/developers/documentation/http/overview>`_.

    Args:
        app_key (str): The client ID for your application on Dropbox.
        app_secret (str): The client secret for your application on Dropbox
        scope (str, optional): Comma-separated list of scopes for the OAuth token
        force_reapprove (bool): Force the user to approve the app again
            if they've already done so.
        disable_signup (bool): Prevent users from seeing a sign-up link
            on the authorization page.
        require_role (str): Pass the string ``work`` to require a Dropbox
            for Business account, or the string ``personal`` to require a
            personal account.
        redirect_url (str): the URL to redirect to after the authentication
            dance is complete
        redirect_to (str): if ``redirect_url`` is not defined, the name of the
            view to redirect to after the authentication dance is complete.
            The actual URL will be determined by :func:`flask.url_for`
        login_url (str, optional): the URL path for the ``login`` view.
            Defaults to ``/dropbox``
        authorized_url (str, optional): the URL path for the ``authorized`` view.
            Defaults to ``/dropbox/authorized``.
        session_class (class, optional): The class to use for creating a
            Requests session. Defaults to
            :class:`~flask_dance.consumer.requests.OAuth2Session`.
        storage: A token storage class, or an instance of a token storage
                class, to use for this blueprint. Defaults to
                :class:`~flask_dance.consumer.storage.session.SessionStorage`.

    :rtype: :class:`~flask_dance.consumer.OAuth2ConsumerBlueprint`
    :returns: A :ref:`blueprint <flask:blueprints>` to attach to your Flask app.
    """
    authorization_url_params = {}
    if force_reapprove:
        authorization_url_params["force_reapprove"] = "true"
    if disable_signup:
        authorization_url_params["disable_signup"] = "true"
    if require_role:
        authorization_url_params["require_role"] = require_role

    dropbox_bp = OAuth2ConsumerBlueprint(
        "dropbox",
        __name__,
        client_id=app_key,
        client_secret=app_secret,
        scope=scope,
        base_url="https://api.dropbox.com/2/",
        authorization_url="https://www.dropbox.com/oauth2/authorize",
        token_url="https://api.dropbox.com/oauth2/token",
        redirect_url=redirect_url,
        redirect_to=redirect_to,
        login_url=login_url,
        authorized_url=authorized_url,
        authorization_url_params=authorization_url_params,
        session_class=session_class,
        storage=storage,
    )
    dropbox_bp.from_config["client_id"] = "DROPBOX_OAUTH_CLIENT_ID"
    dropbox_bp.from_config["client_secret"] = "DROPBOX_OAUTH_CLIENT_SECRET"

    @dropbox_bp.before_app_request
    def set_applocal_session():
        ctx = stack.top
        ctx.dropbox_oauth = dropbox_bp.session

    return dropbox_bp
Beispiel #28
0
def make_strava_blueprint(
    client_id=None,
    client_secret=None,
    *,
    scope="read",
    redirect_url=None,
    redirect_to=None,
    login_url=None,
    authorized_url=None,
    session_class=None,
    storage=None,
    user_agent=None,
    rule_kwargs=None,
):
    """
    Make a blueprint for authenticating with Strava using OAuth 2. This requires
    a client ID and client secret from Strava. You should either pass them to
    this constructor, or make sure that your Flask application config defines
    them, using the variables :envvar:`STRAVA_OAUTH_CLIENT_ID` and
    :envvar:`STRAVA_OAUTH_CLIENT_SECRET`.

    Args:
        client_id (str): The client ID for your application on Strava.
        client_secret (str): The client secret for your application on Strava
        scope (str, optional): space-separated list of scopes for the OAuth token
            Defaults to ``identity``
        redirect_url (str): the URL to redirect to after the authentication
            dance is complete
        redirect_to (str): if ``redirect_url`` is not defined, the name of the
            view to redirect to after the authentication dance is complete.
            The actual URL will be determined by :func:`flask.url_for`
        login_url (str, optional): the URL path for the ``login`` view.
            Defaults to ``/strava``
        authorized_url (str, optional): the URL path for the ``authorized`` view.
            Defaults to ``/strava/authorized``.
        session_class (class, optional): The class to use for creating a
            Requests session. Defaults to
            :class:`~flask_dance.contrib.strava.StravaOAuth2Session`.
        storage: A token storage class, or an instance of a token storage
            class, to use for this blueprint. Defaults to
            :class:`~flask_dance.consumer.storage.session.SessionStorage`.
        user_agent (str, optional): User agent for the requests to Strava API.
            Defaults to ``Flask-Dance/{{version}}``.
        rule_kwargs (dict, optional): Additional arguments that should be passed when adding
            the login and authorized routes. Defaults to ``None``.

    :rtype: :class:`~flask_dance.consumer.OAuth2ConsumerBlueprint`
    :returns: A :doc:`blueprint <flask:blueprints>` to attach to your Flask app.
    """

    strava_bp = OAuth2ConsumerBlueprint(
        "strava",
        __name__,
        client_id=client_id,
        client_secret=client_secret,
        scope=scope,
        base_url="https://www.strava.com/api/v3",
        authorization_url="https://www.strava.com/api/v3/oauth/authorize",
        token_url="https://www.strava.com/api/v3/oauth/token",
        auto_refresh_url="https://www.strava.com/api/v3/oauth/token",
        redirect_url=redirect_url,
        redirect_to=redirect_to,
        login_url=login_url,
        authorized_url=authorized_url,
        session_class=session_class or StravaOAuth2Session,
        storage=storage,
        rule_kwargs=rule_kwargs,
    )

    strava_bp.from_config["client_id"] = "STRAVA_OAUTH_CLIENT_ID"
    strava_bp.from_config["client_secret"] = "STRAVA_OAUTH_CLIENT_SECRET"

    strava_bp.user_agent = user_agent

    @strava_bp.before_app_request
    def set_applocal_session():
        ctx = stack.top
        ctx.strava_oauth = strava_bp.session

    return strava_bp
Beispiel #29
0
def test_signal_sender_oauth_authorized(request):
    app, bp = make_app()
    bp2 = OAuth2ConsumerBlueprint("test2", __name__,
        client_id="client_id",
        client_secret="client_secret",
        scope="admin",
        state="random-string",
        base_url="https://example.com",
        authorization_url="https://example.com/oauth/authorize",
        token_url="https://example.com/oauth/access_token",
        redirect_to="index",
    )
    app.register_blueprint(bp2, url_prefix="/login")

    calls = []
    def callback(*args, **kwargs):
        calls.append((args, kwargs))

    oauth_authorized.connect(callback, sender=bp)
    request.addfinalizer(lambda: oauth_authorized.disconnect(callback, sender=bp))
    fake_token = {"access_token": "test-token"}
    fake_token2 = {"access_token": "test-token2"}

    with app.test_client() as client:
        with client.session_transaction() as sess:
            sess["test-service_oauth_state"] = "random-string"

        bp.session.fetch_token = mock.Mock(return_value=fake_token)
        bp2.session.fetch_token = mock.Mock(return_value=fake_token2)

        resp = client.get(
            "/login/test2/authorized?code=secret-code&state=random-string",
        )

    assert len(calls) == 0

    with app.test_client() as client:
        with client.session_transaction() as sess:
            sess["test-service_oauth_state"] = "random-string"

        bp.session.fetch_token = mock.Mock(return_value="test-token")
        bp2.session.fetch_token = mock.Mock(return_value="test2-token")

        resp = client.get(
            "/login/test-service/authorized?code=secret-code&state=random-string",
        )

    assert len(calls) == 1
    assert calls[0][0] == (bp,)
    assert calls[0][1] == {"token": "test-token"}

    with app.test_client() as client:
        with client.session_transaction() as sess:
            sess["test-service_oauth_state"] = "random-string"

        bp.session.fetch_token = mock.Mock(return_value=fake_token)
        bp2.session.fetch_token = mock.Mock(return_value=fake_token2)

        resp = client.get(
            "/login/test2/authorized?code=secret-code&state=random-string",
        )

    assert len(calls) == 1  # unchanged
Beispiel #30
0
def make_nylas_blueprint(
    client_id=None,
    client_secret=None,
    scope="email",
    redirect_url=None,
    redirect_to=None,
    login_url=None,
    authorized_url=None,
    session_class=None,
    storage=None,
):
    """
    Make a blueprint for authenticating with Nylas using OAuth 2. This requires
    an API ID and API secret from Nylas. You should either pass them to
    this constructor, or make sure that your Flask application config defines
    them, using the variables :envvar:`NYLAS_OAUTH_CLIENT_KEY` and
    :envvar:`NYLAS_OAUTH_CLIENT_SECRET`.

    Args:
        client_id (str): The client ID for your developer account on Nylas.
        client_secret (str): The client secret for your developer account
            on Nylas.
        scope (str, optional): comma-separated list of scopes for the OAuth
            token. Defaults to "email".
        redirect_url (str): the URL to redirect to after the authentication
            dance is complete
        redirect_to (str): if ``redirect_url`` is not defined, the name of the
            view to redirect to after the authentication dance is complete.
            The actual URL will be determined by :func:`flask.url_for`
        login_url (str, optional): the URL path for the ``login`` view.
            Defaults to ``/nylas``
        authorized_url (str, optional): the URL path for the ``authorized`` view.
            Defaults to ``/nylas/authorized``.
        session_class (class, optional): The class to use for creating a
            Requests session. Defaults to
            :class:`~flask_dance.consumer.requests.OAuth2Session`.
        storage: A token storage class, or an instance of a token storage
                class, to use for this blueprint. Defaults to
                :class:`~flask_dance.consumer.storage.session.SessionStorage`.

    :rtype: :class:`~flask_dance.consumer.OAuth2ConsumerBlueprint`
    :returns: A :ref:`blueprint <flask:blueprints>` to attach to your Flask app.
    """
    nylas_bp = OAuth2ConsumerBlueprint(
        "nylas",
        __name__,
        client_id=client_id,
        client_secret=client_secret,
        scope=scope,
        base_url="https://api.nylas.com/",
        authorization_url="https://api.nylas.com/oauth/authorize",
        token_url="https://api.nylas.com/oauth/token",
        redirect_url=redirect_url,
        redirect_to=redirect_to,
        login_url=login_url,
        authorized_url=authorized_url,
        session_class=session_class,
        storage=storage,
    )
    nylas_bp.from_config["client_id"] = "NYLAS_OAUTH_CLIENT_ID"
    nylas_bp.from_config["client_secret"] = "NYLAS_OAUTH_CLIENT_SECRET"

    @nylas_bp.before_app_request
    def set_applocal_session():
        ctx = stack.top
        ctx.nylas_oauth = nylas_bp.session

    return nylas_bp