Example #1
0
def test_signal_oauth_error_authorized(request):
    responses.add(
        responses.POST,
        "https://example.com/oauth/access_token",
        body="Invalid request token.",
        status=401,
    )
    app, bp = make_app()

    calls = []

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

    oauth_error.connect(callback)
    request.addfinalizer(lambda: oauth_error.disconnect(callback))

    with app.test_client() as client:
        resp = client.get(
            "/login/test-service/authorized?"
            "oauth_token=faketoken&"
            "oauth_token_secret=fakesecret&"
            "oauth_verifier=fakeverifier",
            base_url="https://a.b.c",
        )

    assert len(calls) == 1
    assert calls[0][0] == (bp,)
    assert (
        calls[0][1]["message"]
        == "Token request failed with code 401, response was 'Invalid request token.'."
    )
    assert resp.status_code == 302
Example #2
0
def test_signal_oauth_error(request):
    app, bp = make_app()

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

    oauth_error.connect(callback)
    request.addfinalizer(lambda: oauth_error.disconnect(callback))

    with app.test_client() as client:
        resp = client.get(
            "/login/test-service/authorized?"
            "error=unauthorized_client&"
            "error_description=Invalid+redirect+URI&"
            "error_uri=https%3a%2f%2fexample.com%2fdocs%2fhelp",
            base_url="https://a.b.c",
        )

    assert len(calls) == 1
    assert calls[0][0] == (bp,)
    assert calls[0][1] == {
        "error": "unauthorized_client",
        "error_description": "Invalid redirect URI",
        "error_uri": "https://example.com/docs/help",
    }
    assert resp.status_code == 302
Example #3
0
def test_signal_oauth_error_login(request):
    responses.add(
        responses.POST,
        "https://example.com/oauth/request_token",
        body="oauth_problem=nonce_used",
        status=401,
    )
    app, bp = make_app()

    calls = []

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

    oauth_error.connect(callback)
    request.addfinalizer(lambda: oauth_error.disconnect(callback))

    with app.test_client() as client:
        resp = client.get("/login/test-service", base_url="https://a.b.c")

    assert len(calls) == 1
    assert calls[0][0] == (bp,)
    assert (
        calls[0][1]["message"]
        == "Token request failed with code 401, response was 'oauth_problem=nonce_used'."
    )
    assert resp.status_code == 302
    location = resp.headers["Location"]
    assert location == "https://a.b.c/"
Example #4
0
def test_signal_oauth_error(request):
    app, bp = make_app()

    calls = []

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

    oauth_error.connect(callback)
    request.addfinalizer(lambda: oauth_error.disconnect(callback))

    with app.test_client() as client:
        resp = client.get(
            "/login/test-service/authorized?"
            "error=unauthorized_client&"
            "error_description=Invalid+redirect+URI&"
            "error_uri=https%3a%2f%2fexample.com%2fdocs%2fhelp",
            base_url="https://a.b.c",
        )

    assert len(calls) == 1
    assert calls[0][0] == (bp, )
    assert calls[0][1] == {
        "error": "unauthorized_client",
        "error_description": "Invalid redirect URI",
        "error_uri": "https://example.com/docs/help",
    }
    assert resp.status_code == 302
Example #5
0
def test_signal_oauth_notoken_authorized(request):
    app, bp = make_app()

    calls = []

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

    oauth_error.connect(callback)
    request.addfinalizer(lambda: oauth_error.disconnect(callback))

    with app.test_client() as client:
        resp = client.get(
            "/login/test-service/authorized?"
            "denied=faketoken",
            base_url="https://a.b.c",
        )

    assert len(calls) == 1
    assert calls[0][0] == (bp, )
    assert "Response does not contain a token" in calls[0][1]["message"]
    assert calls[0][1]["response"] == {'denied': 'faketoken'}
    assert resp.status_code == 302
    location = resp.headers["Location"]
    assert location == "https://a.b.c/"
Example #6
0
def test_sqla_flask_login_misconfigured(app, db, blueprint, request):
    login_manager = LoginManager(app)

    class User(db.Model, UserMixin):
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(80))

    class OAuth(OAuthConsumerMixin, db.Model):
        user_id = db.Column(db.Integer, db.ForeignKey(User.id))
        user = db.relationship(User)

    blueprint.storage = SQLAlchemyStorage(OAuth, db.session, user=current_user)

    db.create_all()

    def done():
        db.session.remove()
        db.drop_all()

    request.addfinalizer(done)

    # configure login manager
    @login_manager.user_loader
    def load_user(userid):
        return User.query.get(userid)

    calls = []

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

    oauth_error.connect(callback)
    request.addfinalizer(lambda: oauth_error.disconnect(callback))

    with app.test_client() as client:
        # reset the session before the request
        with client.session_transaction() as sess:
            sess["test-service_oauth_state"] = "random-string"
        # make the request
        resp = client.get(
            "/login/test-service/authorized?code=secret-code&state=random-string",
            base_url="https://a.b.c",
        )
        # check that we redirected the client
        assert resp.status_code == 302
        assert resp.headers["Location"] in ("https://a.b.c/oauth_done",
                                            "/oauth_done")

    assert len(calls) == 1
    assert calls[0][0] == (blueprint, )
    error = calls[0][1]["error"]
    assert isinstance(error, ValueError)
    assert str(error) == "Cannot set OAuth token without an associated user"
Example #7
0
def test_sqla_flask_login_misconfigured(app, db, blueprint, request):
    login_manager = LoginManager(app)

    class User(db.Model, UserMixin):
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(80))

    class OAuth(OAuthConsumerMixin, db.Model):
        user_id = db.Column(db.Integer, db.ForeignKey(User.id))
        user = db.relationship(User)

    blueprint.storage = SQLAlchemyStorage(OAuth, db.session, user=current_user)

    db.create_all()

    def done():
        db.session.remove()
        db.drop_all()

    request.addfinalizer(done)

    # configure login manager
    @login_manager.user_loader
    def load_user(userid):
        return User.query.get(userid)

    calls = []

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

    oauth_error.connect(callback)
    request.addfinalizer(lambda: oauth_error.disconnect(callback))

    with app.test_client() as client:
        # reset the session before the request
        with client.session_transaction() as sess:
            sess["test-service_oauth_state"] = "random-string"
        # make the request
        resp = client.get(
            "/login/test-service/authorized?code=secret-code&state=random-string",
            base_url="https://a.b.c",
        )
        # check that we redirected the client
        assert resp.status_code == 302
        assert resp.headers["Location"] == "https://a.b.c/oauth_done"

    assert len(calls) == 1
    assert calls[0][0] == (blueprint,)
    error = calls[0][1]["error"]
    assert isinstance(error, ValueError)
    assert str(error) == "Cannot set OAuth token without an associated user"
    def __init__(self, name, import_name, db_session, user_model, token_model,
                 final_redirect_view):
        """
        :param db_session: SQLAlchemy session object
        :param user_model: User model class;
            this should be a flask_login.UserMixin or similar
        :param token_model: Token model class;
            this should be a hydra_oauth2.HydraTokenMixin or similar
        :param final_redirect_view: the endpoint to which to redirect the user
            after login/logout has been completed
        """
        super().__init__(
            name,
            import_name,
            login_url='/login',
            authorized_url='/authorized',
            redirect_to=final_redirect_view,
            storage=SQLAlchemyStorage(token_model,
                                      db_session,
                                      user=current_user),

            # hack to disable SSL certificate verification in a dev environment:
            # this is a sneaky way to make flask-dance set the 'verify' kwarg for
            # requests calls made when fetching tokens; it's not the intended use
            # of token_url_params, but hey-ho
            token_url_params={'verify': get_env() != 'development'},
        )

        self.db_session = db_session
        self.user_model = user_model
        self.token_model = token_model

        self.hydra_public_url = None
        self.userinfo_url = None
        self.logout_url = None

        self.from_config['hydra_public_url'] = 'HYDRA_PUBLIC_URL'
        self.from_config['client_id'] = 'OAUTH2_CLIENT_ID'
        self.from_config['client_secret'] = 'OAUTH2_CLIENT_SECRET'
        self.from_config['scope'] = 'OAUTH2_SCOPES'
        self.from_config['audience'] = 'OAUTH2_AUDIENCE'

        self.add_url_rule('/signup', view_func=self.signup)
        self.add_url_rule('/logout', view_func=self.logout)
        self.add_url_rule('/logged_out', view_func=self.logged_out)

        oauth_authorized.connect(self.hydra_logged_in, sender=self)
        oauth_error.connect(self.hydra_error, sender=self)

        self.create_or_update_local_user = None
def test_signal_oauth_notoken_authorized(request):
    app, bp = make_app()

    calls = []

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

    oauth_error.connect(callback)
    request.addfinalizer(lambda: oauth_error.disconnect(callback))

    with app.test_client() as client:
        resp = client.get(
            "/login/test-service/authorized?" "denied=faketoken",
            base_url="https://a.b.c",
        )

    assert len(calls) == 1
    assert calls[0][0] == (bp,)
    assert "Response does not contain a token" in calls[0][1]["message"]
    assert calls[0][1]["response"] == {"denied": "faketoken"}
    assert resp.status_code == 302
    location = resp.headers["Location"]
    assert location == "https://a.b.c/"