diff --git a/files/hotfix/python-fedora/proxyclient.py b/files/hotfix/python-fedora/proxyclient.py
deleted file mode 100644
index 1c36d67903..0000000000
--- a/files/hotfix/python-fedora/proxyclient.py
+++ /dev/null
@@ -1,496 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright (C) 2009-2013 Red Hat, Inc.
-# This file is part of python-fedora
-#
-# python-fedora is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# python-fedora is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with python-fedora; if not, see
-#
-'''Implement a class that sets up simple communication to a Fedora Service.
-
-.. moduleauthor:: Luke Macken
-.. moduleauthor:: Toshio Kuratomi
-'''
-
-import Cookie
-import copy
-import urllib
-import httplib
-import logging
-# For handling an exception that's coming from requests:
-import ssl
-import time
-import warnings
-
-try:
- from urlparse import urljoin
- from urlparse import urlparse
-except ImportError:
- # Python3 support
- from urllib.parse import urljoin
- from urllib.parse import urlparse
-
-try:
- from hashlib import sha1 as sha_constructor
-except ImportError:
- from sha import new as sha_constructor
-
-from bunch import bunchify
-from kitchen.text.converters import to_bytes
-import requests
-# For handling an exception that's coming from requests:
-import urllib3
-
-from fedora import __version__, b_
-from fedora.client import AppError, AuthError, ServerError
-
-log = logging.getLogger(__name__)
-
-
-class ProxyClient(object):
- # pylint: disable-msg=R0903
- '''
- A client to a Fedora Service. This class is optimized to proxy multiple
- users to a service. ProxyClient is designed to be threadsafe so that
- code can instantiate one instance of the class and use it for multiple
- requests for different users from different threads.
-
- If you want something that can manage one user's connection to a Fedora
- Service, then look into using BaseClient instead.
-
- This class has several attributes. These may be changed after
- instantiation however, please note that this class is intended to be
- threadsafe. Changing these values when another thread may affect more
- than just the thread that you are making the change in. (For instance,
- changing the debug option could cause other threads to start logging debug
- messages in the middle of a method.)
-
- .. attribute:: base_url
-
- Initial portion of the url to contact the server. It is highly
- recommended not to change this value unless you know that no other
- threads are accessing this :class:`ProxyClient` instance.
-
- .. attribute:: useragent
-
- Changes the useragent string that is reported to the web server.
-
- .. attribute:: session_name
-
- Name of the cookie that holds the authentication value.
-
- .. attribute:: session_as_cookie
-
- If :data:`True`, then the session information is saved locally as
- a cookie. This is here for backwards compatibility. New code should
- set this to :data:`False` when constructing the :class:`ProxyClient`.
-
- .. attribute:: debug
-
- If :data:`True`, then more verbose logging is performed to aid in
- debugging issues.
-
- .. attribute:: insecure
-
- If :data:`True` then the connection to the server is not checked to be
- sure that any SSL certificate information is valid. That means that
- a remote host can lie about who it is. Useful for development but
- should not be used in production code.
-
- .. attribute:: retries
-
- Setting this to a positive integer will retry failed requests to the
- web server this many times. Setting to a negative integer will retry
- forever.
-
- .. attribute:: timeout
- A float describing the timeout of the connection. The timeout only
- affects the connection process itself, not the downloading of the
- response body. Defaults to 120 seconds.
-
- .. versionchanged:: 0.3.33
- Added the timeout attribute
- '''
- log = log
-
- def __init__(self, base_url, useragent=None, session_name='tg-visit',
- session_as_cookie=True, debug=False, insecure=False, retries=None,
- timeout=None):
- '''Create a client configured for a particular service.
-
- :arg base_url: Base of every URL used to contact the server
-
- :kwarg useragent: useragent string to use. If not given, default to
- "Fedora ProxyClient/VERSION"
- :kwarg session_name: name of the cookie to use with session handling
- :kwarg session_as_cookie: If set to True, return the session as a
- SimpleCookie. If False, return a session_id. This flag allows us
- to maintain compatibility for the 0.3 branch. In 0.4, code will
- have to deal with session_id's instead of cookies.
- :kwarg debug: If True, log debug information
- :kwarg insecure: If True, do not check server certificates against
- their CA's. This means that man-in-the-middle attacks are
- possible against the `BaseClient`. You might turn this option on
- for testing against a local version of a server with a self-signed
- certificate but it should be off in production.
- :kwarg retries: if we get an unknown or possibly transient error from
- the server, retry this many times. Setting this to a negative
- number makes it try forever. Defaults to zero, no retries.
- :kwarg timeout: A float describing the timeout of the connection. The
- timeout only affects the connection process itself, not the downloading
- of the response body. Defaults to 120 seconds.
-
- .. versionchanged:: 0.3.33
- Added the timeout kwarg
- '''
- # Setup our logger
- self._log_handler = logging.StreamHandler()
- self.debug = debug
- format = logging.Formatter("%(message)s")
- self._log_handler.setFormatter(format)
- self.log.addHandler(self._log_handler)
-
- # When we are instantiated, go ahead and silence the python-requests
- # log. It is kind of noisy in our app server logs.
- if not debug:
- requests_log = logging.getLogger("requests")
- requests_log.setLevel(logging.WARN)
-
- self.log.debug(b_('proxyclient.__init__:entered'))
- if base_url[-1] != '/':
- base_url = base_url +'/'
- self.base_url = base_url
- self.domain = urlparse(self.base_url).netloc
- self.useragent = useragent or 'Fedora ProxyClient/%(version)s' % {
- 'version': __version__}
- self.session_name = session_name
- self.session_as_cookie = session_as_cookie
- if session_as_cookie:
- warnings.warn(b_('Returning cookies from send_request() is'
- ' deprecated and will be removed in 0.4. Please port your'
- ' code to use a session_id instead by calling the ProxyClient'
- ' constructor with session_as_cookie=False'),
- DeprecationWarning, stacklevel=2)
- self.insecure = insecure
-
- # Have to do retries and timeout default values this way as BaseClient
- # sends None for these values if not overridden by the user.
- if retries is None:
- self.retries = 0
- else:
- self.retries = retries
- if timeout is None:
- self.timeout = 120.0
- else:
- self.timeout = timeout
- self.log.debug(b_('proxyclient.__init__:exited'))
-
- def __get_debug(self):
- '''Return whether we have debug logging turned on.
-
- :Returns: True if debugging is on, False otherwise.
- '''
- if self._log_handler.level <= logging.DEBUG:
- return True
- return False
-
- def __set_debug(self, debug=False):
- '''Change debug level.
-
- :kwarg debug: A true value to turn debugging on, false value to turn it
- off.
- '''
- if debug:
- self.log.setLevel(logging.DEBUG)
- self._log_handler.setLevel(logging.DEBUG)
- else:
- self.log.setLevel(logging.ERROR)
- self._log_handler.setLevel(logging.INFO)
-
- debug = property(__get_debug, __set_debug, doc='''
- When True, we log extra debugging statements. When False, we only log
- errors.
- ''')
-
- def send_request(self, method, req_params=None, auth_params=None,
- file_params=None, retries=None, timeout=None):
- '''Make an HTTP request to a server method.
-
- The given method is called with any parameters set in ``req_params``.
- If auth is True, then the request is made with an authenticated session
- cookie. Note that path parameters should be set by adding onto the
- method, not via ``req_params``.
-
- :arg method: Method to call on the server. It's a url fragment that
- comes after the base_url set in __init__(). Note that any
- parameters set as extra path information should be listed here,
- not in ``req_params``.
- :kwarg req_params: dict containing extra parameters to send to the
- server
- :kwarg auth_params: dict containing one or more means of authenticating
- to the server. Valid entries in this dict are:
-
- :cookie: **Deprecated** Use ``session_id`` instead. If both
- ``cookie`` and ``session_id`` are set, only ``session_id`` will
- be used. A ``Cookie.SimpleCookie`` to send as a session cookie
- to the server
- :session_id: Session id to put in a cookie to construct an identity
- for the server
- :username: Username to send to the server
- :password: Password to use with username to send to the server
- :httpauth: If set to ``basic`` then use HTTP Basic Authentication
- to send the username and password to the server. This may be
- extended in the future to support other httpauth types than
- ``basic``.
-
- Note that cookie can be sent alone but if one of username or
- password is set the other must as well. Code can set all of these
- if it wants and all of them will be sent to the server. Be careful
- of sending cookies that do not match with the username in this
- case as the server can decide what to do in this case.
- :kwarg file_params: dict of files where the key is the name of the
- file field used in the remote method and the value is the local
- path of the file to be uploaded. If you want to pass multiple
- files to a single file field, pass the paths as a list of paths.
- :kwarg retries: if we get an unknown or possibly transient error from
- the server, retry this many times. Setting this to a negative
- number makes it try forever. Default to use the :attr:`retries`
- value set on the instance or in :meth:`__init__`.
- :kwarg timeout: A float describing the timeout of the connection. The
- timeout only affects the connection process itself, not the
- downloading of the response body. Defaults to the :attr:`timeout`
- value set on the instance or in :meth:`__init__`.
- :returns: If ProxyClient is created with session_as_cookie=True (the
- default), a tuple of session cookie and data from the server.
- If ProxyClient was created with session_as_cookie=False, a tuple
- of session_id and data instead.
- :rtype: tuple of session information and data from server
-
- .. versionchanged:: 0.3.17
- No longer send tg_format=json parameter. We rely solely on the
- Accept: application/json header now.
- .. versionchanged:: 0.3.21
- * Return data as a Bunch instead of a DictContainer
- * Add file_params to allow uploading files
- .. versionchanged:: 0.3.33
- Added the timeout kwarg
- '''
- self.log.debug(b_('proxyclient.send_request: entered'))
-
- # parameter mangling
- file_params = file_params or {}
-
- # Check whether we need to authenticate for this request
- session_id = None
- username = None
- password = None
- if auth_params:
- if 'session_id' in auth_params:
- session_id = auth_params['session_id']
- elif 'cookie' in auth_params:
- warnings.warn(b_('Giving a cookie to send_request() to'
- ' authenticate is deprecated and will be removed in 0.4.'
- ' Please port your code to use session_id instead.'),
- DeprecationWarning, stacklevel=2)
- session_id = auth_params['cookie'].output(attrs=[],
- header='').strip()
- if 'username' in auth_params and 'password' in auth_params:
- username = auth_params['username']
- password = auth_params['password']
- elif 'username' in auth_params or 'password' in auth_params:
- raise AuthError(b_('username and password must both be set in'
- ' auth_params'))
- if not (session_id or username):
- raise AuthError(b_('No known authentication methods'
- ' specified: set "cookie" in auth_params or set both'
- ' username and password in auth_params'))
-
- # urljoin is slightly different than os.path.join(). Make sure method
- # will work with it.
- method = method.lstrip('/')
- # And join to make our url.
- url = urljoin(self.base_url, urllib.quote(method))
-
- data = None # decoded JSON via json.load()
-
- # Set standard headers
- headers = {
- 'User-agent': self.useragent,
- 'Accept': 'application/json',
- }
-
- # Files to upload
- for field_name, local_file_name in file_params:
- file_params[field_name] = open(local_file_name, 'rb')
-
- cookies = requests.cookies.RequestsCookieJar()
- # If we have a session_id, send it
- if session_id:
- # Anytime the session_id exists, send it so that visit tracking
- # works. Will also authenticate us if there's a need. Note that
- # there's no need to set other cookie attributes because this is a
- # cookie generated client-side.
- cookies.set(self.session_name, session_id)
-
- complete_params = req_params or {}
- if session_id:
- # Add the csrf protection token
- token = sha_constructor(session_id)
- complete_params.update({'_csrf_token': token.hexdigest()})
-
- auth = None
- if username and password:
- if auth_params.get('httpauth', '').lower() == 'basic':
- # HTTP Basic auth login
- auth = (username, password)
- else:
- # TG login
- # Adding this to the request data prevents it from being logged by
- # apache.
- complete_params.update({
- 'user_name': to_bytes(username),
- 'password': to_bytes(password),
- 'login': 'Login',
- })
-
- # If debug, give people our debug info
- self.log.debug(b_('Creating request %(url)s') %
- {'url': to_bytes(url)})
- self.log.debug(b_('Headers: %(header)s') %
- {'header': to_bytes(headers, nonstring='simplerepr')})
- if self.debug and complete_params:
- debug_data = copy.deepcopy(complete_params)
-
- if 'password' in debug_data:
- debug_data['password'] = 'xxxxxxx'
-
- self.log.debug(b_('Data: %r') % debug_data)
-
- if retries is None:
- retries = self.retries
-
- if timeout is None:
- timeout = self.timeout
-
- num_tries = 0
- while True:
- try:
- response = requests.post(
- url,
- data=complete_params,
- cookies=cookies,
- headers=headers,
- auth=auth,
- verify=not self.insecure,
- timeout=timeout,
- )
- except (requests.Timeout, requests.exceptions.SSLError) as e:
- if isinstance(e, requests.exceptions.SSLError):
- # And now we know how not to code a library exception
- # hierarchy... We're expecting that requests is raising
- # the following stupidity:
- # requests.exceptions.SSLError(
- # urllib3.exceptions.SSLError(
- # ssl.SSLError('The read operation timed out')))
- # If we weren't interested in reraising the exception with
- # full tracdeback we could use a try: except instead of
- # this gross conditional. But we need to code defensively
- # because we don't want to raise an unrelated exception
- # here and if requests/urllib3 can do this sort of
- # nonsense, they may change the nonsense in the future
- if not (e.args and isinstance(e.args[0],
- urllib3.exceptions.SSLError)
- and e.args[0].args
- and isinstance(e.args[0].args[0], ssl.SSLError)
- and e.args[0].args[0].args
- and 'timed out' in e.args[0].args[0].args[0]):
- # We're only interested in timeouts here
- raise
- self.log.debug(b_('Request timed out'))
- if retries < 0 or num_tries < retries:
- num_tries += 1
- self.log.debug(b_('Attempt #%(try)s failed') % {'try': num_tries})
- time.sleep(0.5)
- continue
- # Fail and raise an error
- # Raising our own exception protects the user from the
- # implementation detail of requests vs pycurl vs urllib
- raise ServerError(url, -1, 'Request timed out after %s seconds' % timeout)
-
- # When the python-requests module gets a response, it attempts to
- # guess the encoding using chardet (or a fork)
- # That process can take an extraordinarily long time for long
- # response.text strings.. upwards of 30 minutes for FAS queries to
- # /accounts/user/list JSON api! Therefore, we cut that codepath
- # off at the pass by assuming that the response is 'utf-8'. We can
- # make that assumption because we're only interfacing with servers
- # that we run (and we know that they all return responses
- # encoded 'utf-8').
- response.encoding = 'utf-8'
-
- # Check for auth failures
- # Note: old TG apps returned 403 Forbidden on authentication failures.
- # Updated apps return 401 Unauthorized
- # We need to accept both until all apps are updated to return 401.
- http_status = response.status_code
- if http_status in (401, 403):
- # Wrong username or password
- self.log.debug(b_('Authentication failed logging in'))
- raise AuthError(b_('Unable to log into server. Invalid'
- ' authentication tokens. Send new username and password'))
- elif http_status >= 400:
- if retries < 0 or num_tries < retries:
- # Retry the request
- num_tries += 1
- self.log.debug(b_('Attempt #%(try)s failed') % {'try': num_tries})
- time.sleep(0.5)
- continue
- # Fail and raise an error
- try:
- msg = httplib.responses[http_status]
- except (KeyError, AttributeError):
- msg = b_('Unknown HTTP Server Response')
- raise ServerError(url, http_status, msg)
- # Successfully returned data
- break
-
- # In case the server returned a new session cookie to us
- new_session = response.cookies.get(self.session_name, '')
-
- try:
- data = response.json
- # Compatibility with newer python-requests
- if callable(data):
- data = data()
- except ValueError, e:
- # The response wasn't JSON data
- raise ServerError(url, http_status, b_('Error returned from'
- ' json module while processing %(url)s: %(err)s') %
- {'url': to_bytes(url), 'err': to_bytes(e)})
-
- if 'exc' in data:
- name = data.pop('exc')
- message = data.pop('tg_flash')
- raise AppError(name=name, message=message, extras=data)
-
- # If we need to return a cookie for deprecated code, convert it here
- if self.session_as_cookie:
- cookie = Cookie.SimpleCookie()
- cookie[self.session_name] = new_session
- new_session = cookie
-
- self.log.debug(b_('proxyclient.send_request: exited'))
- data = bunchify(data)
- return new_session, data
-
-__all__ = (ProxyClient,)
diff --git a/roles/fedocal/templates/flask_fas_openid.py b/roles/fedocal/templates/flask_fas_openid.py
deleted file mode 100644
index b951fb5883..0000000000
--- a/roles/fedocal/templates/flask_fas_openid.py
+++ /dev/null
@@ -1,220 +0,0 @@
-# -*- coding: utf-8 -*-
-# Flask-FAS-OpenID - A Flask extension for authorizing users with FAS-OpenID
-#
-# Primary maintainer: Patrick Uiterwijk
-#
-# Copyright (c) 2013, Patrick Uiterwijk
-# This file is part of python-fedora
-#
-# python-fedora is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# python-fedora is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with python-fedora; if not, see
-
-'''
-FAS-OpenID authentication plugin for the flask web framework
-
-.. moduleauthor:: Patrick Uiterwijk
-
-..versionadded:: 0.3.33
-'''
-from functools import wraps
-
-from bunch import Bunch
-import flask
-try:
- from flask import _app_ctx_stack as stack
-except ImportError:
- from flask import _request_ctx_stack as stack
-
-import openid
-from openid.consumer import consumer
-from openid.fetchers import setDefaultFetcher, Urllib2Fetcher
-from openid.extensions import pape, sreg
-from openid_cla import cla
-from openid_teams import teams
-
-from fedora import __version__
-
-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)
-
- def logout(self):
- '''Logout the user associated with this session
- '''
- flask.session['FLASK_FAS_OPENID_USER'] = None
- flask.g.fas_session_id = None
- flask.g.fas_user = None
- flask.session.modified = True
-
- def normalize_url(self, url):
- ''' Replace the scheme prefix of a url with our preferred scheme.
- '''
- scheme = self.app.config['PREFERRED_URL_SCHEME']
- scheme_index = url.index('://')
- return scheme + url[scheme_index:]
-
-
-# This is a decorator we can use with any HTTP method (except login, obviously)
-# to require a login.
-# If the user is not logged in, it will redirect them to the login form.
-# http://flask.pocoo.org/docs/patterns/viewdecorators/#login-required-decorator
-def fas_login_required(function):
- """ Flask decorator to ensure that the user is logged in against FAS.
- To use this decorator you need to have a function named 'auth_login'.
- Without that function the redirect if the user is not logged in will not
- work.
- """
- @wraps(function)
- def decorated_function(*args, **kwargs):
- if flask.g.fas_user is None:
- return flask.redirect(flask.url_for('auth_login',
- next=flask.request.url))
- return function(*args, **kwargs)
- return decorated_function
-
-
-def cla_plus_one_required(function):
- """ Flask decorator to retrict access to CLA+1.
- To use this decorator you need to have a function named 'auth_login'.
- Without that function the redirect if the user is not logged in will not
- work.
- """
- @wraps(function)
- def decorated_function(*args, **kwargs):
- if flask.g.fas_user is None or not flask.g.fas_user.cla_done or len(flask.g.fas_user.groups) < 1: # FAS-OpenID does not return cla_ groups
- return flask.redirect(flask.url_for('auth_login',
- next=flask.request.url))
- else:
- return function(*args, **kwargs)
- return decorated_function
diff --git a/roles/nuancier/templates/flask_fas_openid.py b/roles/nuancier/templates/flask_fas_openid.py
deleted file mode 100644
index b951fb5883..0000000000
--- a/roles/nuancier/templates/flask_fas_openid.py
+++ /dev/null
@@ -1,220 +0,0 @@
-# -*- coding: utf-8 -*-
-# Flask-FAS-OpenID - A Flask extension for authorizing users with FAS-OpenID
-#
-# Primary maintainer: Patrick Uiterwijk
-#
-# Copyright (c) 2013, Patrick Uiterwijk
-# This file is part of python-fedora
-#
-# python-fedora is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# python-fedora is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with python-fedora; if not, see
-
-'''
-FAS-OpenID authentication plugin for the flask web framework
-
-.. moduleauthor:: Patrick Uiterwijk
-
-..versionadded:: 0.3.33
-'''
-from functools import wraps
-
-from bunch import Bunch
-import flask
-try:
- from flask import _app_ctx_stack as stack
-except ImportError:
- from flask import _request_ctx_stack as stack
-
-import openid
-from openid.consumer import consumer
-from openid.fetchers import setDefaultFetcher, Urllib2Fetcher
-from openid.extensions import pape, sreg
-from openid_cla import cla
-from openid_teams import teams
-
-from fedora import __version__
-
-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)
-
- def logout(self):
- '''Logout the user associated with this session
- '''
- flask.session['FLASK_FAS_OPENID_USER'] = None
- flask.g.fas_session_id = None
- flask.g.fas_user = None
- flask.session.modified = True
-
- def normalize_url(self, url):
- ''' Replace the scheme prefix of a url with our preferred scheme.
- '''
- scheme = self.app.config['PREFERRED_URL_SCHEME']
- scheme_index = url.index('://')
- return scheme + url[scheme_index:]
-
-
-# This is a decorator we can use with any HTTP method (except login, obviously)
-# to require a login.
-# If the user is not logged in, it will redirect them to the login form.
-# http://flask.pocoo.org/docs/patterns/viewdecorators/#login-required-decorator
-def fas_login_required(function):
- """ Flask decorator to ensure that the user is logged in against FAS.
- To use this decorator you need to have a function named 'auth_login'.
- Without that function the redirect if the user is not logged in will not
- work.
- """
- @wraps(function)
- def decorated_function(*args, **kwargs):
- if flask.g.fas_user is None:
- return flask.redirect(flask.url_for('auth_login',
- next=flask.request.url))
- return function(*args, **kwargs)
- return decorated_function
-
-
-def cla_plus_one_required(function):
- """ Flask decorator to retrict access to CLA+1.
- To use this decorator you need to have a function named 'auth_login'.
- Without that function the redirect if the user is not logged in will not
- work.
- """
- @wraps(function)
- def decorated_function(*args, **kwargs):
- if flask.g.fas_user is None or not flask.g.fas_user.cla_done or len(flask.g.fas_user.groups) < 1: # FAS-OpenID does not return cla_ groups
- return flask.redirect(flask.url_for('auth_login',
- next=flask.request.url))
- else:
- return function(*args, **kwargs)
- return decorated_function