Esempio n. 1
0
    def test_exchange_when_code_is_rejected(self):
        oauth_service = Signonotron2(None, None, None, "")
        oauth_service.signon = Mock()
        response = Response()
        response.status_code = 401
        oauth_service.signon.get_raw_access_token.return_value = response

        assert_that(oauth_service.exchange("code to reject"), is_(None))
Esempio n. 2
0
    def test_authorize_returns_a_redirect_to_signon_service(self):
        oauth_service = Signonotron2(None, None, None, "")
        oauth_service.signon = Mock()
        oauth_service.signon.get_authorize_url.return_value = ""

        response = oauth_service.authorize()

        assert_that(response, has_status(302))
Esempio n. 3
0
    def test_exchange_when_code_is_accepted(self, process_token_request):
        oauth_service = Signonotron2(None, None, None, "")
        oauth_service.signon = Mock()
        response = Response()
        response.status_code = 200
        oauth_service.signon.get_raw_access_token.return_value = response
        process_token_request.return_value = tuple(["access toucan"])

        assert_that(oauth_service.exchange("code to accept"),
                    is_("access toucan"))
Esempio n. 4
0
    def test_user_details_if_access_token_is_rejected(self):
        oauth_service = Signonotron2(None, None, None, "")
        oauth_service.signon = Mock()
        session_object = Mock()
        response = Response()
        response._content = ""
        response.status_code = 401
        session_object.get.return_value = response
        oauth_service.signon.get_session.return_value = session_object

        user_details = oauth_service.user_details("token is rejected")

        assert_that(user_details, is_((None, None)))
Esempio n. 5
0
    def test_returns_none_and_logs_error_if_cannot_parse_token(self):
        mock_logger = Mock()
        signonotron2.log = mock_logger
        oauth_service = Signonotron2(None, None, None, "")
        oauth_service.signon = Mock()
        response = Response()
        response._content = '{"foo":"bar"}'
        response.status_code = 200
        oauth_service.signon.get_raw_access_token.return_value = response

        access_token = oauth_service.exchange("top secret code")
        assert_that(access_token, is_(None))
        assert_that(mock_logger.warn.call_args[0][0],
                    starts_with('Could not parse token from response'))
Esempio n. 6
0
    def test_user_details_if_access_token_is_accepted(self):
        oauth_service = Signonotron2(None, None, None, "")
        oauth_service.signon = Mock()
        session_object = Mock()
        response = Response()
        user_details_json = \
            { "user": {"name": "Gareth The Wizard", "permissions": "signin"}}
        response._content = json.dumps(user_details_json)
        response.status_code = 200
        session_object.get.return_value = response
        oauth_service.signon.get_session.return_value = session_object

        user_details = oauth_service.user_details("token is accepted")

        assert_that(user_details, is_((user_details_json, True)))
Esempio n. 7
0
def setup(app, db):
    USER_SCOPE = app.config['USER_SCOPE']
    ADMIN_UI_HOST = app.config["BACKDROP_ADMIN_UI_HOST"]
    MAX_UPLOAD_SIZE = 1000000

    app.oauth_service = Signonotron2(
        client_id=app.config['OAUTH_CLIENT_ID'],
        client_secret=app.config['OAUTH_CLIENT_SECRET'],
        base_url=app.config['OAUTH_BASE_URL'],
        backdrop_admin_ui_host=ADMIN_UI_HOST)

    @app.after_request
    def prevent_clickjacking(response):
        response.headers["X-Frame-Options"] = "SAMEORIGIN"
        return response

    def protected(f):
        @wraps(f)
        def verify_user_logged_in(*args, **kwargs):
            if not "user" in session:
                return redirect(url_for(ADMIN_UI_HOST, 'oauth_sign_in'))
            return f(*args, **kwargs)

        return verify_user_logged_in

    @app.route(USER_SCOPE)
    @cache_control.set("private, must-revalidate")
    def user_route():
        """
        This representation is private to the logged-in user
        (with their own buckets)
        """
        if use_single_sign_on(app):
            buckets_available = app.permissions.buckets_in_session(session)
            return render_template("index.html",
                                   buckets_available=buckets_available)
        else:
            return "Backdrop is running."

    @app.route(USER_SCOPE + "/sign_in")
    @cache_control.nocache
    def oauth_sign_in():
        """
        This returns a redirect to the OAuth provider, so we shouldn't
        allow this response to be cached.
        """
        return app.oauth_service.authorize()

    @app.route(USER_SCOPE + "/sign_out")
    @cache_control.set("private, must-revalidate")
    def oauth_sign_out():
        session.clear()
        flash("You have been signed out of Backdrop", category="success")
        return render_template("signon/signout.html",
                               oauth_base_url=app.config['OAUTH_BASE_URL'])

    @app.route(USER_SCOPE + "/authorized")
    @cache_control.nocache
    def oauth_authorized():
        """
        The result of this is a redirect, which shouldn't be cached in
        case their permissions get changed, etc.
        """
        auth_code = request.args.get('code')
        if not auth_code:
            abort(400)
        access_token = app.oauth_service.exchange(auth_code)

        user_details, can_see_backdrop = \
            app.oauth_service.user_details(access_token)
        if can_see_backdrop is None:
            flash("Could not authenticate with single sign on.",
                  category="error")
            return redirect(url_for(ADMIN_UI_HOST, "not_authorized"))
        if can_see_backdrop is False:
            flash("You are signed in to your GOV.UK account, "
                  "but you don't have permissions to use this application.")
            return redirect(url_for(ADMIN_UI_HOST, "not_authorized"))
        _create_session_user(user_details["user"]["name"],
                             user_details["user"]["email"])
        flash("You were successfully signed in", category="success")
        return redirect(url_for(ADMIN_UI_HOST, "user_route"))

    @app.route(USER_SCOPE + "/not_authorized")
    @cache_control.nocache
    def not_authorized():
        return render_template("signon/not_authorized.html")

    @app.route(USER_SCOPE + "/protected", methods=['GET'])
    @protected
    def upload_buckets():
        return "hello"

    if allow_test_signin(app):

        @app.route(USER_SCOPE + "/sign_in/test", methods=['GET'])
        def test_signin():
            _create_session_user(request.args.get('user'),
                                 request.args.get('email'))
            return "logged in as %s" % session.get('user'), 200

    def _create_session_user(name, email):
        session.update({"user": {"name": name, "email": email}})

    @app.route('/<bucket:bucket_name>/upload', methods=['GET', 'POST'])
    @protected
    @cache_control.set("private, must-revalidate")
    def upload(bucket_name):
        current_user_email = session.get("user").get("email")
        if not app.permissions.allowed(current_user_email, bucket_name):
            return abort(404)

        upload_format = _upload_format_for(bucket_name)
        upload_filters = _upload_filters_for(bucket_name)

        if request.method == 'GET':
            return render_template("upload_%s.html" % upload_format,
                                   bucket_name=bucket_name)

        parser = create_parser(upload_format, upload_filters)

        return _store_data(bucket_name, parser)

    def _store_data(bucket_name, parser):
        file_stream = request.files["file"].stream
        if not request.files["file"].filename:
            return _invalid_upload("file is required")
        try:
            if request.content_length > MAX_UPLOAD_SIZE:
                return _invalid_upload("file too large")
            try:
                data = parser(file_stream)

                auto_id_keys = _auto_id_keys_for(bucket_name)
                bucket = Bucket(db, bucket_name, generate_id_from=auto_id_keys)
                bucket.parse_and_store(data)

                return render_template("upload_ok.html")
            except (ParseError, ValidationError) as e:
                return _invalid_upload(e.message)
        finally:
            file_stream.close()

    def _upload_format_for(bucket_name):
        return app.config.get("BUCKET_UPLOAD_FORMAT", {})\
                         .get(bucket_name, "csv")

    def _upload_filters_for(bucket_name):
        return app.config.get("BUCKET_UPLOAD_FILTERS", {})\
                         .get(bucket_name, [first_sheet_filter])

    def _auto_id_keys_for(bucket_name):
        return app.config.get("BUCKET_AUTO_ID_KEYS", {}).get(bucket_name)

    def _invalid_upload(msg):
        app.logger.error("Upload error: %s" % msg)
        return render_template("upload_error.html", message=msg), 400
Esempio n. 8
0
def setup(app, db):
    USER_SCOPE = app.config['USER_SCOPE']
    ADMIN_UI_HOST = app.config["BACKDROP_ADMIN_UI_HOST"]
    MAX_UPLOAD_SIZE = 100000

    app.oauth_service = Signonotron2(
        client_id=app.config['OAUTH_CLIENT_ID'],
        client_secret=app.config['OAUTH_CLIENT_SECRET'],
        base_url=app.config['OAUTH_BASE_URL'],
        backdrop_admin_ui_host=ADMIN_UI_HOST)

    def protected(f):
        @wraps(f)
        def verify_user_logged_in(*args, **kwargs):
            if not "user" in session:
                return redirect(url_for(ADMIN_UI_HOST, 'oauth_sign_in'))
            return f(*args, **kwargs)

        return verify_user_logged_in

    @app.route(USER_SCOPE)
    def user_route():
        if use_single_sign_on(app):
            return render_template("index.html")
        else:
            return "Backdrop is running."

    @app.route(USER_SCOPE + "/sign_in")
    def oauth_sign_in():
        return app.oauth_service.authorize()

    @app.route(USER_SCOPE + "/sign_out")
    def oauth_sign_out():
        session.clear()
        flash("You have been signed out of Backdrop", category="success")
        return render_template("signon/signout.html",
                               oauth_base_url=app.config['OAUTH_BASE_URL'])

    @app.route(USER_SCOPE + "/authorized")
    def oauth_authorized():
        auth_code = request.args.get('code')
        if not auth_code:
            abort(400)
        access_token = app.oauth_service.exchange(auth_code)

        user_details, can_see_backdrop = \
            app.oauth_service.user_details(access_token)
        if can_see_backdrop is None:
            flash("Could not authenticate with single sign on.",
                  category="error")
            return redirect(url_for(ADMIN_UI_HOST, "not_authorized"))
        if can_see_backdrop is False:
            flash("You are signed in to your GOV.UK account, "
                  "but you don't have permissions to use this application.")
            return redirect(url_for(ADMIN_UI_HOST, "not_authorized"))
        _create_session_user(user_details["user"]["name"],
                             user_details["user"]["email"])
        flash("You were successfully signed in", category="success")
        return redirect(url_for(ADMIN_UI_HOST, "user_route"))

    @app.route(USER_SCOPE + "/not_authorized")
    def not_authorized():
        return render_template("signon/not_authorized.html")

    @app.route(USER_SCOPE + "/protected", methods=['GET'])
    @protected
    def upload_buckets():
        return "hello"

    if allow_test_signin(app):

        @app.route(USER_SCOPE + "/sign_in/test", methods=['GET'])
        def test_signin():
            _create_session_user(request.args.get('user'),
                                 request.args.get('email'))
            return "logged in as %s" % session.get('user'), 200

    def _create_session_user(name, email):
        session.update({"user": {"name": name, "email": email}})

    @app.route('/<bucket_name>/upload', methods=['GET', 'POST'])
    @protected
    def upload(bucket_name):
        if not bucket_is_valid(bucket_name):
            return _invalid_upload("Bucket name is invalid")

        current_user_email = session.get("user").get("email")
        if not app.permissions.allowed(current_user_email, bucket_name):
            return abort(404)

        if request.method == 'GET':
            return render_template("upload_csv.html")

        return _store_csv_data(bucket_name)

    def _store_csv_data(bucket_name):
        file_stream = request.files["file"].stream
        try:
            if request.content_length > MAX_UPLOAD_SIZE:
                return _invalid_upload("file too large")
            try:
                parse_and_store(db, parse_csv(file_stream), bucket_name,
                                app.logger)

                return render_template("upload_ok.html")
            except (ParseError, ValidationError) as e:
                return _invalid_upload(e.message)
        finally:
            file_stream.close()

    def _invalid_upload(msg):
        return render_template("upload_error.html", message=msg), 400
Esempio n. 9
0
    def test_returns_no_user_details_if_access_token_is_none(self):
        oauth_service = Signonotron2(None, None, None, "")

        user_details = oauth_service.user_details(None)

        assert_that(user_details, is_((None, None)))