Esempio n. 1
0
    def render_GET(self, request):
        session = {}
        oidconsumer = consumer.Consumer(session, None)
        request = oidconsumer.begin(self.provider)
        request.addExtension(sreg.SRegRequest(
            required=['nickname', 'fullname', 'email', 'timezone']))
        request.addExtension(teams.TeamsRequest(requested=self.groups))
        request.addExtension(cla.CLARequest(
            requested=[cla.CLA_URI_FEDORA_DONE]))

        trust_root = self.root_url
        return_to = self.root_url + '_openid_handle/'

        if request.shouldSendRedirect():
            redirect_url = request.redirectURL(trust_root, return_to, False)
            request.redirect(redirect_url)
        else:
            return request.htmlMarkup(
                trust_root, return_to,
                form_tag_attrs={'id': 'openid_message'}, immediate=False)

        try:
            request.finish()
        except RuntimeError:
            # this occurs when the client has already disconnected; ignore
            # it (see #2027)
            log.msg("http client disconnected before results were sent")
Esempio n. 2
0
    def login(self, return_url=None, cancel_url=None, groups=None):
        """Tries to log in a user.

        Sets the user information on :attr:`flask.g.fas_user`.
        Will set 0 to :attr:`flask.g.fas_session_id, for compatibility
        with flask_fas.

        :kwarg username: Not used, but accepted for compatibility with the
            flask_fas module
        :kwarg password: Not used, but accepted for compatibility with the
            flask_fas module
        :kwarg return_url: The URL to forward the user to after login
        :kwarg groups: A string or a list of group the user should belong
            to to be authentified.
        :returns: True if the user was succesfully authenticated.
        :raises: Might raise an redirect to the OpenID endpoint
        """
        if groups is None:
            groups = ['_FAS_ALL_GROUPS_']

        if return_url is None:
            return_url = flask.request.args.get('next', flask.request.url)
        session = {}
        oidconsumer = consumer.Consumer(session, None)
        try:
            request = oidconsumer.begin(self.app.config['FAS_OPENID_ENDPOINT'])
        except consumer.DiscoveryFailure:
            # VERY strange, as this means it could not discover an OpenID
            # endpoint at FAS_OPENID_ENDPOINT
            return 'discoveryfailure'
        if request is None:
            # Also very strange, as this means the discovered OpenID
            # endpoint is no OpenID endpoint
            return 'no-request'

        if isinstance(groups, basestring):
            groups = [groups]

        request.addExtension(
            sreg.SRegRequest(
                required=['nickname', 'fullname', 'email', 'timezone']))
        request.addExtension(pape.Request([]))
        request.addExtension(teams.TeamsRequest(requested=groups))
        request.addExtension(
            cla.CLARequest(requested=[cla.CLA_URI_FEDORA_DONE]))

        trust_root = self.normalize_url(flask.request.url_root)
        return_to = trust_root + '_flask_fas_openid_handler/'

        flask.session['FLASK_FAS_OPENID_RETURN_URL'] = return_url
        flask.session['FLASK_FAS_OPENID_CANCEL_URL'] = cancel_url
        if request.shouldSendRedirect():
            redirect_url = request.redirectURL(trust_root, return_to, False)
            return flask.redirect(redirect_url)
        else:
            return request.htmlMarkup(trust_root,
                                      return_to,
                                      form_tag_attrs={'id': 'openid_message'},
                                      immediate=False)
Esempio n. 3
0
def process_incoming_request(context, request, incoming_openid_url):
    settings = request.registry.settings
    log.info('OpenID URL supplied by user: %s' % incoming_openid_url)
    openid_consumer = consumer.Consumer(request.session, None)
    try:
        openid_request = openid_consumer.begin(incoming_openid_url)
        ax_required = get_ax_required_from_settings(settings)
        ax_optional = get_ax_optional_from_settings(settings)
        log.info('ax_required: %s' % ax_required)
        log.info('ax_optional: %s' % ax_optional)
        if len(ax_required.values()) or len(ax_optional.values()):
            fetch_request = ax.FetchRequest()
            for value in ax_required.values():
                fetch_request.add(ax.AttrInfo(value, required=True))
            for value in ax_optional.values():
                fetch_request.add(ax.AttrInfo(value, required=False))
            openid_request.addExtension(fetch_request)

        sreg_required = get_sreg_required_from_settings(settings)
        sreg_optional = get_sreg_optional_from_settings(settings)
        log.info('sreg_required: %s' % sreg_required)
        log.info('sreg_optional: %s' % sreg_optional)
        if len(sreg_required) or len(sreg_optional):
            sreq = sreg.SRegRequest(required=sreg_required,
                                    optional=sreg_optional)
            openid_request.addExtension(sreq)

        # Default is magic which requests all groups from FAS-OpenID >= 0.2.0
        groups = request.registry.settings.get('openid.groups',
                                               '_FAS_ALL_GROUPS_')
        if isinstance(groups, six.string_types):
            groups = groups.split()
        openid_request.addExtension(teams.TeamsRequest(requested=groups))
        openid_request.addExtension(
            cla.CLARequest(requested=[cla.CLA_URI_FEDORA_DONE]))
    except consumer.DiscoveryFailure as exc:
        # eventually no openid server could be found
        return error_to_login_form(request, 'Error in discovery: %s' % exc[0])
    except KeyError as exc:
        # TODO: when does that happen, why does plone.openid use "pass" here?
        return error_to_login_form(request, 'Error in discovery: %s' % exc[0])
    # not sure this can still happen but we are making sure.
    # should actually been handled by the DiscoveryFailure exception above
    if openid_request is None:
        return error_to_login_form(
            request, 'No OpenID services found for %s' % incoming_openid_url)
    #Not sure what the point of setting this to anything else is
    realm_name = settings.get('openid.realm_name', request.host_url)
    return_url = request.path_url
    redirect_url = openid_request.redirectURL(realm_name, return_url)
    log.info('Realm Name: %s' % realm_name)
    log.info('Return URL from provider will be: %s' % return_url)
    log.info('Redirecting to: %s' % redirect_url)
    return HTTPFound(location=redirect_url)
def handle_initial_request(request):

    groups = ['sysadmin-releng', 'sysadmin-main']
    session = {}
    oidconsumer = consumer.Consumer(session, None)
    try:
        req = oidconsumer.begin('https://id.fedoraproject.org')
    except consumer.DiscoveryFailure:
        # VERY strange, as this means it could not discover an OpenID
        # endpoint at FAS_OPENID_ENDPOINT
        return 'discoveryfailure'
    if req is None:
        # Also very strange, as this means the discovered OpenID
        # endpoint is no OpenID endpoint
        return 'no-req'

    req.addExtension(sreg.SRegRequest(
        required=['nickname', 'fullname', 'email', 'timezone']))
    req.addExtension(pape.Request([]))
    req.addExtension(teams.TeamsRequest(requested=groups))
    req.addExtension(cla.CLARequest(
        requested=[cla.CLA_URI_FEDORA_DONE]))


    # Use the django HTTPRequest for this
    trust_root = request.build_absolute_uri('/')
    return_to = request.build_absolute_uri() + "?type=fas-openid"

    # Success or fail, redirect to the base.  ¯\_(ツ)_/¯
    return_url = cancel_url = request.build_absolute_uri('/')
    request.session['FAS_OPENID_RETURN_URL'] = return_url
    request.session['FAS_OPENID_CANCEL_URL'] = cancel_url

    # the django rest framework requires that we use the json route here
    return dict(form=req.htmlMarkup(trust_root, return_to,
        form_tag_attrs={'id': 'openid_message'}, immediate=False))
Esempio n. 5
0
    def login(self,
              username=None,
              password=None,
              return_url=None,
              cancel_url=None,
              groups=['_FAS_ALL_GROUPS_']):
        """
        Copied from the FAS Flask OpenID Auth Plugin with modifications to be
        compatible with a separate frontend application.
        """

        if return_url is None:
            if 'next' in flask.request.args.values():
                return_url = flask.request.args.values['next']
            else:
                return_url = flask.request.url_root

        return_to_same_app = self._check_safe_root(return_url)

        session = {}
        oidconsumer = consumer.Consumer(session, None)
        try:
            request = oidconsumer.begin(self.app.config['FAS_OPENID_ENDPOINT'])
        except consumer.DiscoveryFailure as exc:
            # VERY strange, as this means it could not discover an OpenID
            # endpoint at FAS_OPENID_ENDPOINT
            log.warn(exc)
            return 'discoveryfailure'
        if request is None:
            # Also very strange, as this means the discovered OpenID
            # endpoint is no OpenID endpoint
            return 'no-request'

        if isinstance(groups, six.string_types):
            groups = [groups]

        request.addExtension(
            sreg.SRegRequest(
                required=['nickname', 'fullname', 'email', 'timezone']))
        request.addExtension(pape.Request([]))
        request.addExtension(teams.TeamsRequest(requested=groups))
        request.addExtension(
            cla.CLARequest(requested=[cla.CLA_URI_FEDORA_DONE]))

        ax_req = ax.FetchRequest()
        ax_req.add(
            ax.AttrInfo(
                type_uri='http://fedoauth.org/openid/schema/GPG/keyid'))
        ax_req.add(
            ax.AttrInfo(type_uri='http://fedoauth.org/openid/schema/SSH/key',
                        count='unlimited'))
        request.addExtension(ax_req)

        trust_root = self.normalize_url(flask.request.url_root)
        return_to = trust_root + '_flask_fas_openid_handler/'
        flask.session['FLASK_FAS_OPENID_RETURN_URL'] = return_url
        flask.session['FLASK_FAS_OPENID_CANCEL_URL'] = cancel_url
        flask.session.modified = True

        if request_wants_json():
            output = request.getMessage(trust_root,
                                        return_to=return_to).toPostArgs()
            output['server_url'] = request.endpoint.server_url
            return flask.jsonify(output)
        elif request.shouldSendRedirect():
            redirect_url = request.redirectURL(trust_root, return_to, False)
            return flask.redirect(redirect_url)
        elif not return_to_same_app:
            return_to = os.environ['CLIENT_URL'] + '/_flask_fas_openid_handler/'
            redirect_url = request.redirectURL(os.environ['CLIENT_URL'],
                                               return_to, False)
            return redirect_url
        else:
            return request.htmlMarkup(trust_root,
                                      return_to,
                                      form_tag_attrs={'id': 'openid_message'},
                                      immediate=False)
Esempio n. 6
0
    def login(self,
              username=None,
              password=None,
              return_url=None,
              cancel_url=None,
              groups=['_FAS_ALL_GROUPS_']):
        """Tries to log in a user.

        Sets the user information on :attr:`flask.g.fas_user`.
        Will set 0 to :attr:`flask.g.fas_session_id, for compatibility
        with flask_fas.

        :kwarg username: Not used, but accepted for compatibility with the
            flask_fas module
        :kwarg password: Not used, but accepted for compatibility with the
            flask_fas module
        :kwarg return_url: The URL to forward the user to after login
        :kwarg groups: A string or a list of group the user should belong
            to to be authentified.
        :returns: True if the user was succesfully authenticated.
        :raises: Might raise an redirect to the OpenID endpoint
        """
        if return_url is None:
            if 'next' in flask.request.args.values():
                return_url = flask.request.args.values['next']
            else:
                return_url = flask.request.url_root
        # This makes sure that we only allow stuff where
        # ?next= value is in a safe root (the application
        # root)
        return_url = (self._check_safe_root(return_url)
                      or flask.request.url_root)
        session = {}
        oidconsumer = consumer.Consumer(session, None)
        try:
            request = oidconsumer.begin(self.app.config['FAS_OPENID_ENDPOINT'])
        except consumer.DiscoveryFailure as exc:
            # VERY strange, as this means it could not discover an OpenID
            # endpoint at FAS_OPENID_ENDPOINT
            log.warn(exc)
            return 'discoveryfailure'
        if request is None:
            # Also very strange, as this means the discovered OpenID
            # endpoint is no OpenID endpoint
            return 'no-request'

        if isinstance(groups, six.string_types):
            groups = [groups]
        # Some applications pass the group list as a set. Convert to a list in
        # case we need to append to it (see below).
        if isinstance(groups, set):
            groups = list(groups)
        # In the new AAA system, we know a user has signed the FPCA by looking
        # a group membership. We must therefore always request the
        # corresponding group.
        if "_FAS_ALL_GROUPS_" not in groups:
            groups.append("signed_fpca")

        request.addExtension(
            sreg.SRegRequest(
                required=['nickname', 'fullname', 'email', 'timezone']))
        request.addExtension(pape.Request([]))
        request.addExtension(teams.TeamsRequest(requested=groups))
        request.addExtension(
            cla.CLARequest(requested=[cla.CLA_URI_FEDORA_DONE]))

        ax_req = ax.FetchRequest()
        ax_req.add(
            ax.AttrInfo(
                type_uri='http://fedoauth.org/openid/schema/GPG/keyid'))
        ax_req.add(
            ax.AttrInfo(type_uri='http://fedoauth.org/openid/schema/SSH/key',
                        count='unlimited'))
        request.addExtension(ax_req)

        trust_root = self.normalize_url(flask.request.url_root)
        return_to = trust_root + '_flask_fas_openid_handler/'

        flask.session['FLASK_FAS_OPENID_RETURN_URL'] = return_url
        flask.session['FLASK_FAS_OPENID_CANCEL_URL'] = cancel_url

        if request_wants_json():
            output = request.getMessage(trust_root,
                                        return_to=return_to).toPostArgs()
            output['server_url'] = request.endpoint.server_url
            return flask.jsonify(output)
        elif request.shouldSendRedirect():
            redirect_url = request.redirectURL(trust_root, return_to, False)
            return flask.redirect(redirect_url)
        else:
            return request.htmlMarkup(trust_root,
                                      return_to,
                                      form_tag_attrs={'id': 'openid_message'},
                                      immediate=False)
class FAS(object):
    def __init__(self, app=None):
        self.app = app
        if self.app is not None:
            self._init_app(app)

    def _init_app(self, app):
        app.config.setdefault('FAS_OPENID_ENDPOINT',
                              'http://id.fedoraproject.org/')
        app.config.setdefault('FAS_OPENID_CHECK_CERT', True)

        if not self.app.config['FAS_OPENID_CHECK_CERT']:
            setDefaultFetcher(Urllib2Fetcher())

        @app.route('/_flask_fas_openid_handler/', methods=['GET', 'POST'])
        def flask_fas_openid_handler():
            return self._handle_openid_request()

        app.before_request(self._check_session)

    def _handle_openid_request(self):
        return_url = flask.session['FLASK_FAS_OPENID_RETURN_URL']
        cancel_url = flask.session['FLASK_FAS_OPENID_CANCEL_URL']
        base_url = self.normalize_url(flask.request.base_url)
        oidconsumer = consumer.Consumer(flask.session, None)
        info = oidconsumer.complete(flask.request.values, base_url)
        display_identifier = info.getDisplayIdentifier()

        if info.status == consumer.FAILURE and display_identifier:
            return 'FAILURE. display_identifier: %s' % display_identifier
        elif info.status == consumer.CANCEL:
            if cancel_url:
                return flask.redirect(cancel_url)
            return 'OpenID request was cancelled'
        elif info.status == consumer.SUCCESS:
            sreg_resp = sreg.SRegResponse.fromSuccessResponse(info)
            pape_resp = pape.Response.fromSuccessResponse(info)
            teams_resp = teams.TeamsResponse.fromSuccessResponse(info)
            cla_resp = cla.CLAResponse.fromSuccessResponse(info)
            user = {
                'fullname': '',
                'username': '',
                'email': '',
                'timezone': '',
                'cla_done': False,
                'groups': []
            }
            if not sreg_resp:
                # If we have no basic info, be gone with them!
                return flask.redirect(cancel_url)
            user['username'] = sreg_resp.get('nickname')
            user['fullname'] = sreg_resp.get('fullname')
            user['email'] = sreg_resp.get('email')
            user['timezone'] = sreg_resp.get('timezone')
            if cla_resp:
                user['cla_done'] = cla.CLA_URI_FEDORA_DONE in cla_resp.clas
            if teams_resp:
                user['groups'] = frozenset(
                    teams_resp.teams
                )  # The groups do not contain the cla_ groups
            flask.session['FLASK_FAS_OPENID_USER'] = user
            flask.session.modified = True
            return flask.redirect(return_url)
        else:
            return 'Strange state: %s' % info.status

    def _check_session(self):
        if not 'FLASK_FAS_OPENID_USER' in flask.session or flask.session[
                'FLASK_FAS_OPENID_USER'] is None:
            flask.g.fas_user = None
        else:
            user = flask.session['FLASK_FAS_OPENID_USER']
            # Add approved_memberships to provide backwards compatibility
            # New applications should only use g.fas_user.groups
            user['approved_memberships'] = []
            for group in user['groups']:
                membership = dict()
                membership['name'] = group
                user['approved_memberships'].append(Bunch.fromDict(membership))
            flask.g.fas_user = Bunch.fromDict(user)
        flask.g.fas_session_id = 0

    def login(self,
              username=None,
              password=None,
              return_url=None,
              cancel_url=None,
              groups=['_FAS_ALL_GROUPS_']):
        """Tries to log in a user.

        Sets the user information on :attr:`flask.g.fas_user`.
        Will set 0 to :attr:`flask.g.fas_session_id, for compatibility
        with flask_fas.

        :arg username: Not used, but accepted for compatibility with the
           flask_fas module
        :arg password: Not used, but accepted for compatibility with the
           flask_fas module
        :arg return_url: The URL to forward the user to after login
        :arg groups: A string or a list of group the user should belong to
           to be authentified.
        :returns: True if the user was succesfully authenticated.
        :raises: Might raise an redirect to the OpenID endpoint
        """
        if return_url is None:
            if 'next' in flask.request.args.values():
                return_url = flask.request.args.values['next']
            else:
                return_url = flask.request.url
        oidconsumer = consumer.Consumer(flask.session, None)
        try:
            request = oidconsumer.begin(self.app.config['FAS_OPENID_ENDPOINT'])
        except consumer.DiscoveryFailure, exc:
            # VERY strange, as this means it could not discover an OpenID endpoint at FAS_OPENID_ENDPOINT
            return 'discoveryfailure'
        if request is None:
            # Also very strange, as this means the discovered OpenID endpoint is no OpenID endpoint
            return 'no-request'

        if isinstance(groups, basestring):
            groups = [groups]

        request.addExtension(
            sreg.SRegRequest(
                required=['nickname', 'fullname', 'email', 'timezone']))
        request.addExtension(pape.Request([]))
        request.addExtension(teams.TeamsRequest(requested=groups))
        request.addExtension(
            cla.CLARequest(requested=[cla.CLA_URI_FEDORA_DONE]))

        trust_root = self.normalize_url(flask.request.url_root)
        return_to = trust_root + '_flask_fas_openid_handler/'

        flask.session['FLASK_FAS_OPENID_RETURN_URL'] = return_url
        flask.session['FLASK_FAS_OPENID_CANCEL_URL'] = cancel_url
        if request.shouldSendRedirect():
            redirect_url = request.redirectURL(trust_root, return_to, False)
            return flask.redirect(redirect_url)
        else:
            return request.htmlMarkup(trust_root,
                                      return_to,
                                      form_tag_attrs={'id': 'openid_message'},
                                      immediate=False)