Ejemplo n.º 1
0
def test_get_oauth_access_token(app_req_ctx):
    """Test the acquisition of OAuth access token."""
    with app_req_ctx("/oauth/token",
                     method="POST",
                     data=dict(grant_type="client_credentials",
                               client_id="CLIENT_ID",
                               client_secret="CLIENT_SECRET")) as ctx:
        rv = ctx.app.full_dispatch_request()
        assert rv.status_code == 200
        data = json.loads(rv.data)
        client = Client.get(client_id="CLIENT_ID")
        token = Token.get(client=client)
        assert data["access_token"] == token.access_token
        assert data["expires_in"] == ctx.app.config[
            "OAUTH2_PROVIDER_TOKEN_EXPIRES_IN"]
        assert data["token_type"] == token.token_type
        # prevously created access token should be removed
        assert not Token.select().where(Token.access_token == "TEST").exists()

    with app_req_ctx("/oauth/token",
                     method="POST",
                     data=dict(grant_type="client_credentials",
                               client_id="NOT-EXISTING-CLIENT_ID",
                               client_secret="CLIENT_SECRET")) as ctx:
        # login_user(user, remember=True)
        rv = ctx.app.full_dispatch_request()
        assert rv.status_code == 401
        data = json.loads(rv.data)
        assert data["error"] == "invalid_client"

    with app_req_ctx("/oauth/token",
                     method="POST",
                     data=dict(grant_type="client_credentials",
                               client_id="CLIENT_ID",
                               client_secret="INCORRECT")) as ctx:
        # login_user(user, remember=True)
        rv = ctx.app.full_dispatch_request()
        assert rv.status_code == 401
        data = json.loads(rv.data)
        assert data["error"] == "invalid_client"

    with app_req_ctx("/oauth/token",
                     method="POST",
                     data=dict(grant_type="INCORRECT",
                               client_id="NOT-EXISTING-CLIENT_ID",
                               client_secret="CLIENT_SECRET")) as ctx:
        # login_user(user, remember=True)
        rv = ctx.app.full_dispatch_request()
        assert rv.status_code == 400
        data = json.loads(rv.data)
        assert data["error"] == "unsupported_grant_type"
Ejemplo n.º 2
0
def test_users_api(client):
    """Test user API."""
    c = Client.get(client_id="TEST0-ID")
    resp = client.post(
        "/oauth/token",
        content_type="application/x-www-form-urlencoded",
        data=
        f"grant_type=client_credentials&client_id={c.client_id}&client_secret={c.client_secret}"
    )
    data = json.loads(resp.data)
    access_token = data["access_token"]
    resp = client.get("/api/v1.0/users?page=1&page_size=2000",
                      headers=dict(authorization=f"Bearer {access_token}"),
                      content_type="application/json")

    data = json.loads(resp.data)
    assert list(data[0].keys()) == [
        "confirmed", "email", "eppn", "name", "orcid", "updated-at"
    ]
    assert not any(u["email"] == "*****@*****.**" for u in data)

    resp = client.get(
        "/api/v1.0/users?page=1&page_size=2000&from_date=2000-12-01&to_date=1999-01-01",
        headers=dict(authorization=f"Bearer {access_token}"),
        content_type="application/json")
    data = json.loads(resp.data)
    assert len(data) == 0

    resp = client.get("/api/v1.0/users/[email protected]",
                      headers=dict(authorization=f"Bearer {access_token}"),
                      content_type="application/json")
    assert resp.status_code == 404
    data = json.loads(resp.data)

    resp = client.get("/api/v1.0/users/[email protected]",
                      headers=dict(authorization=f"Bearer {access_token}"),
                      content_type="application/json")
    assert resp.status_code == 200
    data = json.loads(resp.data)
    assert data["email"] == "*****@*****.**"
Ejemplo n.º 3
0
def test_get_oauth_access_token(client):
    """Test the acquisition of OAuth access token."""
    resp = client.post("/oauth/token",
                       data=dict(grant_type="client_credentials",
                                 client_id="CLIENT_ID",
                                 client_secret="CLIENT_SECRET"))
    assert resp.status_code == 200
    c = Client.get(client_id="CLIENT_ID")
    token = Token.get(client=c)
    assert resp.json["access_token"] == token.access_token
    assert resp.json["expires_in"] == client.application.config[
        "OAUTH2_PROVIDER_TOKEN_EXPIRES_IN"]
    assert resp.json["token_type"] == token.token_type
    # prevously created access token should be removed
    assert not Token.select().where(Token.access_token == "TEST").exists()

    resp = client.post("/oauth/token",
                       data=dict(grant_type="client_credentials",
                                 client_id="NOT-EXISTING-CLIENT_ID",
                                 client_secret="CLIENT_SECRET"))
    # login_user(user, remember=True)
    assert resp.status_code == 401
    assert resp.json["error"] == "invalid_client"

    resp = client.post("/oauth/token",
                       data=dict(grant_type="client_credentials",
                                 client_id="CLIENT_ID",
                                 client_secret="INCORRECT"))
    # login_user(user, remember=True)
    assert resp.status_code == 401
    assert resp.json["error"] == "invalid_client"

    resp = client.post("/oauth/token",
                       data=dict(grant_type="INCORRECT",
                                 client_id="NOT-EXISTING-CLIENT_ID",
                                 client_secret="CLIENT_SECRET"))
    # login_user(user, remember=True)
    assert resp.status_code == 400
    assert resp.json["error"] == "unsupported_grant_type"
Ejemplo n.º 4
0
def test_webhook_registration(client):
    """Test webhook registration."""
    test_client = client
    user = User.get(email="*****@*****.**")
    test_client.login(user)
    org = user.organisation
    orcid_id = "0000-0000-0000-00X3"
    client = Client.get(org=org)

    resp = test_client.post(
        "/oauth/token",
        data=dict(
            grant_type="client_credentials",
            client_id=client.client_id,
            client_secret=client.client_secret,
            scope="/webhook",
        ),
    )

    assert resp.status_code == 200
    data = json.loads(resp.data)
    client = Client.get(client_id="CLIENT_ID")
    token = Token.select().where(Token.user == user, Token._scopes == "/webhook").first()
    assert data["access_token"] == token.access_token
    assert data["expires_in"] == test_client.application.config["OAUTH2_PROVIDER_TOKEN_EXPIRES_IN"]
    assert data["token_type"] == token.token_type
    # prevously created access token should be removed

    resp = test_client.put(
        "/api/v1/INCORRECT/webhook/http%3A%2F%2FCALL-BACK",
        headers=dict(authorization=f"Bearer {token.access_token}"),
    )
    assert resp.status_code == 415
    assert json.loads(resp.data)["error"] == "Missing or invalid ORCID iD."

    resp = test_client.put(
        "/api/v1/0000-0001-8228-7153/webhook/http%3A%2F%2FCALL-BACK",
        headers=dict(authorization=f"Bearer {token.access_token}"),
    )
    assert resp.status_code == 404
    assert json.loads(resp.data)["error"] == "Invalid ORCID iD."

    resp = test_client.put(
        f"/api/v1/{orcid_id}/webhook/INCORRECT-WEBHOOK-URL",
        headers=dict(authorization=f"Bearer {token.access_token}"),
    )
    assert resp.status_code == 415
    assert json.loads(resp.data) == {
        "error": "Invalid call-back URL",
        "message": "Invalid call-back URL: INCORRECT-WEBHOOK-URL",
    }

    with patch("orcid_hub.utils.requests.post") as mockpost, patch(
        "orcid_hub.utils.requests.put"
    ) as mockput:
        # Access toke request resp:
        mockresp = MagicMock(status_code=201)
        mockresp.json.return_value = {
            "access_token": "ACCESS-TOKEN-123",
            "token_type": "bearer",
            "refresh_token": "REFRESH-TOKEN-123",
            "expires_in": 99999,
            "scope": "/webhook",
            "orcid": None,
        }
        mockpost.return_value = mockresp
        # Webhook registration response:
        mockresp = MagicMock(status_code=201, data=b"")
        mockresp.headers = {
            "Server": "TEST123",
            "Connection": "keep-alive",
            "Pragma": "no-cache",
            "Expires": "0",
        }
        mockput.return_value = mockresp
        resp = test_client.put(
            f"/api/v1/{orcid_id}/webhook/http%3A%2F%2FCALL-BACK",
            headers=dict(authorization=f"Bearer {token.access_token}"),
        )

        assert resp.status_code == 201
        args, kwargs = mockpost.call_args
        assert args[0] == "https://sandbox.orcid.org/oauth/token"
        assert kwargs["data"] == {
            "client_id": "APP-12345678",
            "client_secret": "CLIENT-SECRET",
            "scope": "/webhook",
            "grant_type": "client_credentials",
        }
        assert kwargs["headers"] == {"Accept": "application/json"}

        args, kwargs = mockput.call_args
        assert (
            args[0]
            == "https://api.sandbox.orcid.org/0000-0000-0000-00X3/webhook/http%3A%2F%2FCALL-BACK"
        )
        assert kwargs["headers"] == {
            "Accept": "application/json",
            "Authorization": "Bearer ACCESS-TOKEN-123",
            "Content-Length": "0",
        }

        q = OrcidToken.select().where(OrcidToken.org == org, OrcidToken.scopes == "/webhook")
        assert q.count() == 1
        orcid_token = q.first()
        assert orcid_token.access_token == "ACCESS-TOKEN-123"
        assert orcid_token.refresh_token == "REFRESH-TOKEN-123"
        assert orcid_token.expires_in == 99999
        assert orcid_token.scopes == "/webhook"

    with patch("orcid_hub.utils.requests.delete") as mockdelete:
        # Webhook deletion response:
        mockresp = MagicMock(status_code=204, data=b"")
        mockresp.headers = {
            "Seresper": "TEST123",
            "Connection": "keep-alive",
            "Location": "TEST-LOCATION",
            "Pragma": "no-cache",
            "Expires": "0",
        }
        mockdelete.return_value = mockresp
        resp = test_client.delete(
            f"/api/v1/{orcid_id}/webhook/http%3A%2F%2FCALL-BACK",
            headers=dict(authorization=f"Bearer {token.access_token}"),
        )
        assert resp.status_code == 204
        assert urlparse(resp.location).path == f"/api/v1/{orcid_id}/webhook/http://TEST-LOCATION"

        args, kwargs = mockput.call_args
        assert (
            args[0]
            == "https://api.sandbox.orcid.org/0000-0000-0000-00X3/webhook/http%3A%2F%2FCALL-BACK"
        )
        assert kwargs["headers"] == {
            "Accept": "application/json",
            "Authorization": "Bearer ACCESS-TOKEN-123",
            "Content-Length": "0",
        }

        q = OrcidToken.select().where(OrcidToken.org == org, OrcidToken.scopes == "/webhook")
        assert q.count() == 1
        token = q.first()
        assert token.access_token == "ACCESS-TOKEN-123"
        assert token.refresh_token == "REFRESH-TOKEN-123"
        assert token.expires_in == 99999
        assert token.scopes == "/webhook"
Ejemplo n.º 5
0
def test_org_webhook_api(client, mocker):
    """Test Organisation webhooks."""
    mocker.patch.object(
        utils.requests,
        "post",
        lambda *args, **kwargs: Mock(
            status_code=201,
            json=lambda: dict(
                access_token="ABC123", refresh_token="REFRESH_ME", expires_in=123456789
            ),
        ),
    )

    mockput = mocker.patch.object(utils.requests, "put")
    mockdelete = mocker.patch.object(utils.requests, "delete")

    org = client.data["org"]
    admin = org.tech_contact

    send_email = mocker.patch("orcid_hub.utils.send_email")

    api_client = Client.get(org=org)

    resp = client.post(
        "/oauth/token",
        data=dict(
            grant_type="client_credentials",
            client_id=api_client.client_id,
            client_secret=api_client.client_secret,
            scope="/webhook",
        ),
    )

    assert resp.status_code == 200
    data = json.loads(resp.data)
    api_client = Client.get(client_id="CLIENT_ID")
    token = Token.select().where(Token.user == admin, Token._scopes == "/webhook").first()

    assert data["access_token"] == token.access_token
    assert data["expires_in"] == client.application.config["OAUTH2_PROVIDER_TOKEN_EXPIRES_IN"]
    assert data["token_type"] == token.token_type

    client.access_token = token.access_token

    resp = client.put("/api/v1/webhook/INCORRECT-WEBHOOK-URL")
    assert resp.status_code == 415
    assert json.loads(resp.data) == {
        "error": "Invalid call-back URL",
        "message": "Invalid call-back URL: INCORRECT-WEBHOOK-URL",
    }

    # Webhook registration response:
    mockresp = MagicMock(status_code=201, data=b"")
    mockresp.headers = {
        "Server": "TEST123",
        "Connection": "keep-alive",
        "Pragma": "no-cache",
        "Expires": "0",
    }
    mockput.return_value = mockresp

    # Webhook deletion response:
    mockresp = MagicMock(status_code=204, data=b"")
    mockresp.headers = {
        "Seresper": "TEST123",
        "Connection": "keep-alive",
        "Location": "TEST-LOCATION",
        "Pragma": "no-cache",
        "Expires": "0",
    }
    mockdelete.return_value = mockresp

    resp = client.put("/api/v1/webhook/http%3A%2F%2FCALL-BACK")
    assert resp.status_code == 200

    resp = client.put(
        "/api/v1/webhook/http%3A%2F%2FCALL-BACK",
        data=dict(enabled=True, url="https://CALL-BACK.edu/callback"),
    )
    assert resp.status_code == 201

    server_name = client.application.config["SERVER_NAME"]
    mockput.assert_has_calls(
        [
            call(
                "https://api.sandbox.orcid.org/1001-0001-0001-0001/webhook/"
                f"https%3A%2F%2F{server_name}%2Fservices%2F21%2Fupdated",
                headers={
                    "Accept": "application/json",
                    "Authorization": "Bearer ABC123",
                    "Content-Length": "0",
                },
            ),
            call(
                "https://api.sandbox.orcid.org/0000-0000-0000-00X3/webhook/"
                f"https%3A%2F%2F{server_name}%2Fservices%2F22%2Fupdated",
                headers={
                    "Accept": "application/json",
                    "Authorization": "Bearer ABC123",
                    "Content-Length": "0",
                },
            ),
            call(
                "https://api.sandbox.orcid.org/0000-0000-0000-11X2/webhook/"
                f"https%3A%2F%2F{server_name}%2Fservices%2F30%2Fupdated",
                headers={
                    "Accept": "application/json",
                    "Authorization": "Bearer ABC123",
                    "Content-Length": "0",
                },
            ),
        ]
    )

    q = OrcidToken.select().where(OrcidToken.org == org, OrcidToken.scopes == "/webhook")
    assert q.exists()
    assert q.count() == 1
    orcid_token = q.first()
    assert orcid_token.access_token == "ABC123"
    assert orcid_token.refresh_token == "REFRESH_ME"
    assert orcid_token.expires_in == 123456789
    assert orcid_token.scopes == "/webhook"

    # deactivate:

    resp = client.delete("/api/v1/webhook/http%3A%2F%2FCALL-BACK")
    assert resp.status_code == 200
    assert "job-id" in resp.json

    # activate with all options:
    mockput.reset_mock()
    resp = client.put(
        "/api/v1/webhook",
        data={
            "enabled": True,
            "append-orcid": True,
            "apikey": "APIKEY123",
            "email-notifications-enabled": True,
            "notification-email": "*****@*****.**",
        },
    )
    server_name = client.application.config["SERVER_NAME"]
    mockput.assert_has_calls(
        [
            call(
                "https://api.sandbox.orcid.org/1001-0001-0001-0001/webhook/"
                f"https%3A%2F%2F{server_name}%2Fservices%2F21%2Fupdated",
                headers={
                    "Accept": "application/json",
                    "Authorization": "Bearer ABC123",
                    "Content-Length": "0",
                },
            ),
            call(
                "https://api.sandbox.orcid.org/0000-0000-0000-00X3/webhook/"
                f"https%3A%2F%2F{server_name}%2Fservices%2F22%2Fupdated",
                headers={
                    "Accept": "application/json",
                    "Authorization": "Bearer ABC123",
                    "Content-Length": "0",
                },
            ),
            call(
                "https://api.sandbox.orcid.org/0000-0000-0000-11X2/webhook/"
                f"https%3A%2F%2F{server_name}%2Fservices%2F30%2Fupdated",
                headers={
                    "Accept": "application/json",
                    "Authorization": "Bearer ABC123",
                    "Content-Length": "0",
                },
            ),
        ]
    )

    # Link other org to the users
    org2 = Organisation.select().where(Organisation.id != org.id).first()
    UserOrg.insert_many([dict(user_id=u.id, org_id=org2.id) for u in org.users]).execute()
    org2.webhook_enabled = True
    org2.save()
    resp = client.delete("/api/v1/webhook")

    mockput.reset_mock()
    resp = client.put(
        "/api/v1/webhook",
        data={
            "enabled": False,
            "url": "https://CALL-BACK.edu/callback",
            "append-orcid": False,
            "email-notifications-enabled": True,
            "notification-email": "*****@*****.**",
        },
    )
    mockput.assert_not_called()

    # Test update summary:
    User.update(
        orcid_updated_at=datetime.date.today().replace(day=1) - datetime.timedelta(days=15)
    ).execute()
    send_email.reset_mock()
    utils.send_orcid_update_summary()
    send_email.assert_called_once()
    client.logout()
Ejemplo n.º 6
0
def test_webhook_registration(app_req_ctx):
    """Test webhook registration."""
    user = User.get(email="*****@*****.**")
    org = user.organisation
    orcid_id = "0000-0000-0000-00X3"
    client = Client.get(org=org)
    with app_req_ctx("/oauth/token",
                     method="POST",
                     data=dict(grant_type="client_credentials",
                               client_id=client.client_id,
                               client_secret=client.client_secret,
                               scope="/webhook")) as ctx:
        login_user(user)
        rv = ctx.app.full_dispatch_request()
        assert rv.status_code == 200
        data = json.loads(rv.data)
        token = Token.get(user=user, _scopes="/webhook")
        client = Client.get(client_id="CLIENT_ID")
        token = Token.get(client=client)
        assert data["access_token"] == token.access_token
        assert data["expires_in"] == ctx.app.config[
            "OAUTH2_PROVIDER_TOKEN_EXPIRES_IN"]
        assert data["token_type"] == token.token_type
        # prevously created access token should be removed

    with app_req_ctx(
            f"/api/v1.0/{orcid_id}/webhook/http%3A%2F%2FCALL-BACK",
            method="PUT",
            headers=dict(authorization=f"Bearer {token.access_token}")
    ) as ctx, patch("orcid_hub.utils.requests.post") as mockpost, patch(
            "orcid_hub.utils.requests.put") as mockput:
        # Access toke request resp:
        mockresp = MagicMock(status_code=201)
        mockresp.json.return_value = {
            "access_token": "ACCESS-TOKEN-123",
            "token_type": "bearer",
            "refresh_token": "REFRESH-TOKEN-123",
            "expires_in": 99999,
            "scope": "/webhook",
            "orcid": None
        }
        mockpost.return_value = mockresp
        # Webhook registration response:
        mockresp = MagicMock(status_code=201, data=b'')
        # mockresp.raw.stream = lambda *args, **kwargs: iter([b"""{"data": "TEST"}"""])
        mockresp.raw.headers = {
            "Server": "TEST123",
            "Connection": "keep-alive",
            "Location": "LOCATION",
            "Pragma": "no-cache",
            "Expires": "0",
        }
        mockput.return_value = mockresp
        resp = ctx.app.full_dispatch_request()
        assert resp.status_code == 201
        args, kwargs = mockpost.call_args
        assert args[0] == "https://sandbox.orcid.org/oauth/token"
        assert kwargs["data"] == {
            "client_id": "APP-12345678",
            "client_secret": "CLIENT-SECRET",
            "scope": "/webhook",
            "grant_type": "client_credentials"
        }
        assert kwargs["headers"] == {"Accept": "application/json"}

        args, kwargs = mockput.call_args
        assert args[
            0] == "https://api.sandbox.orcid.org/0000-0000-0000-00X3/webhook/http%3A%2F%2FCALL-BACK"
        assert kwargs["headers"] == {
            "Accept": "application/json",
            "Authorization": "Bearer ACCESS-TOKEN-123",
            "Content-Length": "0"
        }

        q = OrcidToken.select().where(OrcidToken.org == org,
                                      OrcidToken.scope == "/webhook")
        assert q.count() == 1
        orcid_token = q.first()
        assert orcid_token.access_token == "ACCESS-TOKEN-123"
        assert orcid_token.refresh_token == "REFRESH-TOKEN-123"
        assert orcid_token.expires_in == 99999
        assert orcid_token.scope == "/webhook"

    with app_req_ctx(
            f"/api/v1.0/{orcid_id}/webhook/http%3A%2F%2FCALL-BACK",
            method="DELETE",
            headers=dict(authorization=f"Bearer {token.access_token}")
    ) as ctx, patch("orcid_hub.utils.requests.delete") as mockdelete:
        # Webhook deletion response:
        mockresp = MagicMock(status_code=204, data=b'')
        # mockresp.raw.stream = lambda *args, **kwargs: iter([b"""{"data": "TEST"}"""])
        mockresp.raw.headers = {
            "Server": "TEST123",
            "Connection": "keep-alive",
            "Location": "LOCATION",
            "Pragma": "no-cache",
            "Expires": "0",
        }
        mockdelete.return_value = mockresp
        resp = ctx.app.full_dispatch_request()
        assert resp.status_code == 204

        args, kwargs = mockput.call_args
        assert args[
            0] == "https://api.sandbox.orcid.org/0000-0000-0000-00X3/webhook/http%3A%2F%2FCALL-BACK"
        assert kwargs["headers"] == {
            "Accept": "application/json",
            "Authorization": "Bearer ACCESS-TOKEN-123",
            "Content-Length": "0"
        }

        q = OrcidToken.select().where(OrcidToken.org == org,
                                      OrcidToken.scope == "/webhook")
        assert q.count() == 1
        token = q.first()
        assert token.access_token == "ACCESS-TOKEN-123"
        assert token.refresh_token == "REFRESH-TOKEN-123"
        assert token.expires_in == 99999
        assert token.scope == "/webhook"