def test_test_change_to_next_account_no_account_left(self): """ User tem duas accounts e já está usando a segunda, quando pedir a próxima retornamos a primeira account """ with application.app_context(), application.test_client() as client: jwt_token = self.generate_jwt_token_for_user( self.user, self.account_infra) response = client.post( "/hollow/account/next", headers={ "Authorization": "JWT {}".format(jwt_token.decode("utf8")) }, ) self.assertEqual(200, response.status_code) response_data = json.loads(response.data) self.assertEqual(self.user.email, response_data["user"]["email"]) self.assertEqual(self.user.name, response_data["user"]["name"]) self.assertEqual(self.account_dev.id, response_data["current_account"]["id"]) self.assertEqual(self.account_dev.name, response_data["current_account"]["name"]) jwt_response_header = response_data["jwt_token"] self.assertTrue(jwt_response_header) returned_token = jwt.decode(jwt_response_header, key=SECRET_KEY) self.assertEqual(self.user.email, returned_token["user"]["email"]) self.assertEqual(self.user.name, returned_token["user"]["name"]) self.assertEqual(self.account_dev.id, returned_token["current_account"]["id"]) self.assertEqual(self.account_dev.name, returned_token["current_account"]["name"])
def test_it_creates_a_response_using_a_dict_of_headers(self, fixture): """ O atributo headers de um objeto `request.models.Response` é utilizado para gerar o response do hollowman. Por ser do tipo `CaseInsentiveDict`, quebra a implementação do flask e faz com que seja necessário o typecast para `dict`. """ test_client = application.test_client() with application.app_context(): auth_header = self.make_auth_header(self.normal_user, self.account) with RequestsMock() as rsps: rsps.add( method="GET", url=conf.MARATHON_ADDRESSES[0] + "/v2/apps", body=json.dumps({"apps": [fixture]}), status=200, ) rsps.add( method="GET", url=conf.MARATHON_ADDRESSES[0] + f"/v2/groups//{self.account.namespace}/", body=json.dumps({"apps": [fixture]}), status=200, ) r = test_client.get("/v2/apps", headers=auth_header) self.assertEqual(200, r.status_code)
def test_jwt_add_redirect_with_account_id_on_token_after_login(self): """ Depois do processo de login, o token JWT conterá o account_id da conta padrão do usuário. """ test_client = application.test_client() with application.app_context(), \ patch.object(routes, "check_authentication_successful", return_value={"email": self.user.tx_email}),\ patch.object(routes, "redirect") as redirect_mock: response = test_client.get("/authenticate/google") jwt_token = redirect_mock.call_args_list[0][0][0].split("=")[1] token_content = jwt.decode(jwt_token, conf.SECRET_KEY) self.assertEqual(self.user.tx_email, token_content["user"]["email"]) self.assertEqual(self.user.tx_name, token_content["user"]["name"]) self.assertEqual(self.user.accounts[0].id, token_content["current_account"]["id"]) self.assertEqual(self.user.accounts[0].name, token_content["current_account"]["name"]) self.assertEqual(self.user.accounts[0].namespace, token_content["current_account"]["namespace"])
def test_change_account_has_permmission(self): """ Troca para uma conta que o user atual está vinculado. """ with application.app_context(), \ application.test_client() as client: jwt_token = self.generate_jwt_token_for_user( self.user, self.user.accounts[0]) response = client.post( "/hollow/account/change/{}".format(self.user.accounts[1].id), headers={ "Authorization": "JWT {}".format(jwt_token.decode("utf8")) }) self.assertEqual(200, response.status_code) response_data = json.loads(response.data) self.assertEqual(self.user.tx_email, response_data["user"]["email"]) self.assertEqual(self.user.tx_name, response_data["user"]["name"]) self.assertEqual(self.user.accounts[1].id, response_data["current_account"]["id"]) self.assertEqual(self.user.accounts[1].name, response_data["current_account"]["name"]) jwt_response_token = response_data["jwt_token"] self.assertTrue(jwt_response_token) returned_token = jwt.decode(jwt_response_token, key=SECRET_KEY) self.assertEqual(self.user.tx_email, returned_token["user"]["email"]) self.assertEqual(self.user.tx_name, returned_token["user"]["name"]) self.assertEqual(self.user.accounts[1].id, returned_token["current_account"]["id"]) self.assertEqual(self.user.accounts[1].name, returned_token["current_account"]["name"])
def test_return_401_if_jwt_token_not_present(self): test_client = application.test_client() with application.app_context(): r = test_client.get("/v2/apps") self.assertEqual(401, r.status_code) self.assertEqual("Authorization token is invalid", json.loads(r.data)['msg'])
def test_return_200_if_jwt_token_valid(self): test_client = application.test_client() with application.app_context(): jwt_token = jwt_auth.jwt_encode_callback( jwt_generate_user_info(self.user, self.account_dev)) auth_header = { "Authorization": "JWT {}".format(jwt_token.decode('utf-8')) } r = test_client.get("/v2/apps", headers=auth_header) self.assertEqual(200, r.status_code)
def test_jwt_do_not_trigger_token_auth_if_jwt_token_is_present(self): """ Both auth uses the same header: Authorization. Token Auth should *not* be called if current token is JWT """ with application.test_client() as test_client, \ application.app_context(), \ patch.object(decorators, "HollowmanSession") as session_mock: r = test_client.get("/v2/apps", headers={"Authorization": "JWT Token"}) self.assertEqual(0, session_mock.call_count)
def test_login_failed_invalid_oauth2(self): test_client = application.test_client() with application.app_context(), \ patch.object(routes, "check_authentication_successful", return_value={}), \ patch.object(routes, "render_template") as render_mock: response = test_client.get("/authenticate/google") render_mock.assert_called_once_with("login-failed.html", reason="Invalid OAuth2 code")
def test_login_failed_user_not_found(self): test_client = application.test_client() with application.app_context(), \ patch.object(routes, "check_authentication_successful", return_value={"email": "*****@*****.**"}), \ patch.object(routes, "render_template") as render_mock: response = test_client.get("/authenticate/google") render_mock.assert_called_once_with("login-failed.html", reason="User not found")
def test_login_failed_user_does_not_have_any_account(self): test_client = application.test_client() with application.app_context(), \ patch.object(routes, "check_authentication_successful", return_value={"email": self.user_with_no_accounts.tx_email}), \ patch.object(routes, "render_template") as render_mock: response = test_client.get("/authenticate/google") render_mock.assert_called_once_with( "login-failed.html", reason="No associated accounts")
def test_jwt_populate_request_user_if_token_is_valid(self): with application.app_context(), application.test_client( ) as test_client: jwt_token = jwt_auth.jwt_encode_callback( jwt_generate_user_info(self.user, self.account_infra)) auth_header = { "Authorization": "JWT {}".format(jwt_token.decode('utf-8')) } r = test_client.get("/v2/apps", headers=auth_header) self.assertEqual(200, r.status_code) self.assertEqual("*****@*****.**", request.user.tx_email) self.assertEqual(5, request.user.current_account.id)
def test_jwt_return_401_if_when_account_does_not_exist(self): test_client = application.test_client() with application.app_context(): jwt_token = jwt_auth.jwt_encode_callback( jwt_generate_user_info(self.user, Account(id=1024))) auth_header = { "Authorization": "JWT {}".format(jwt_token.decode('utf-8')) } r = test_client.get("/v2/apps", headers=auth_header) self.assertEqual(401, r.status_code) self.assertEqual("Account does not exist", json.loads(r.data)['msg'])
def test_return_401_if_jwt_token_is_invalid(self): with application.app_context(), application.test_client( ) as test_client: jwt_token = jwt.encode({"email": "*****@*****.**"}, key="wrong key") auth_header = { "Authorization": "JWT {}".format(jwt_token.decode('utf-8')) } r = test_client.get("/v2/apps", headers=auth_header) self.assertEqual(401, r.status_code) self.assertEqual("Authorization token is invalid", json.loads(r.data)['msg'])
def test_jwt_return_401_if_user_has_no_associated_account(self): test_client = application.test_client() with application.app_context(): jwt_token = jwt_auth.jwt_encode_callback({ "email": "*****@*****.**", "account_id": 2 }) auth_header = { "Authorization": "JWT {}".format(jwt_token.decode('utf-8')) } r = test_client.get("/v2/apps", headers=auth_header) self.assertEqual(401, r.status_code) self.assertEqual("No associated account", json.loads(r.data)['msg'])
def test_redirect_with_jwt_url_is_formed_with_unicode_jwt(self): test_client = application.test_client() jwt = MagicMock() with application.app_context(), \ patch.object(routes, "check_authentication_successful", return_value={"email": "*****@*****.**"}),\ patch.object(routes.jwt_auth, "jwt_encode_callback", return_value=jwt), \ patch.object(routes, 'redirect') as redirect: response = test_client.get("/authenticate/google") jwt.decode.assert_called_once_with('utf-8') redirect.assert_called_once_with("{}?jwt={}".format( conf.REDIRECT_AFTER_LOGIN, jwt.decode.return_value))
def test_jwt_populate_default_account_if_request_account_is_empty(self): """ Como quem gera o token JWT é o server e ele *sempre* coloca account_id (Um user sem nennhuma account associada não se loga), esse request nunca vai acontecer. Não acontece pois é impossivel gerar um JWT válido sem ter a SECRET_KEY que só o server tem. """ test_client = application.test_client() with application.app_context(): jwt_token = jwt_auth.jwt_encode_callback( {"email": "*****@*****.**"}) auth_header = { "Authorization": "JWT {}".format(jwt_token.decode('utf-8')) } r = test_client.get("/v2/apps", headers=auth_header) self.assertEqual(200, r.status_code) self.assertEqual(3, r.user.current_account)
def test_jwt_return_401_if_user_is_not_linked_to_account(self): """ If user tries to access account without being associated to this account """ test_client = application.test_client() with application.app_context(): jwt_token = jwt_auth.jwt_encode_callback( jwt_generate_user_info(self.user, self.account_with_no_user)) auth_header = { "Authorization": "JWT {}".format(jwt_token.decode('utf-8')) } r = test_client.get("/v2/apps", headers=auth_header) self.assertEqual(401, r.status_code) self.assertEqual("Permission Denied to access this account", json.loads(r.data)['msg'])
def test_add_default_account_on_first_jwt_token(self): """ Depois do processo de login, o token JWT conterá o account_id da conta padrão do usuário. """ test_client = application.test_client() jwt = MagicMock() with application.app_context(), \ patch.object(routes, "check_authentication_successful", return_value={"email": self.user.tx_email}),\ patch.object(routes.jwt_auth, "jwt_encode_callback") as jwt_auth_mock: response = test_client.get("/authenticate/google") jwt_auth_mock.assert_called_once_with( jwt_generate_user_info(self.user, self.user.accounts[0]))
def test_jwt_auth_with_token_from_session_if_headers_not_present(self): """ Se não encontrarmos o token JWT no header, olhamos na flask session procurando por ele. """ test_client = application.test_client() with application.app_context(), \ patch.object(routes, "check_authentication_successful", return_value={"email": self.user.tx_email}): jwt_token = jwt_auth.jwt_encode_callback( jwt_generate_user_info(self.user, self.account_dev)) with test_client.session_transaction() as flask_session: flask_session['jwt'] = jwt_token response = test_client.get("/v2/apps") self.assertEqual(200, response.status_code)
def test_change_account_user_is_not_associated(self): """ Retorna HTTP 401 se tentarmos trocar para uma conta que não estamos vinculados, ou seja, não existe registro na tabela `user_has_account` """ with application.app_context(), \ application.test_client() as client: jwt_token = self.generate_jwt_token_for_user( self.user, self.user.accounts[0]) response = client.post("/hollow/account/change/42", headers={ "Authorization": "JWT {}".format( jwt_token.decode("utf8")) }) self.assertEqual(401, response.status_code) self.assertEquals("Not associated with account", json.loads(response.data)["msg"])
def test_get_current_user_info_valid_auth(self): with application.app_context(), application.test_client() as client: jwt_token = self.generate_jwt_token_for_user( self.user, self.account_dev) response = client.get( "/hollow/account/me", headers={ "Authorization": "JWT {}".format(jwt_token.decode("utf8")) }, ) self.assertEqual(200, response.status_code) response_data = json.loads(response.data) self.assertEqual(self.user.email, response_data["user"]["email"]) self.assertEqual(self.user.name, response_data["user"]["name"]) self.assertEqual(self.account_dev.id, response_data["current_account"]["id"]) self.assertEqual(self.account_dev.name, response_data["current_account"]["name"])
def test_change_to_next_account_one_account_left(self): """ User tem duas accounts, está usando a primeira e pede pra trocar para a proxima. Retornamos a segunda """ with application.app_context(), \ application.test_client() as client: jwt_token = self.generate_jwt_token_for_user( self.user, self.user.accounts[0]) response = client.post("/hollow/account/next", headers={ "Authorization": "JWT {}".format( jwt_token.decode("utf8")) }) self.assertEqual(200, response.status_code) response_data = json.loads(response.data) self.assertEqual(self.user.tx_email, response_data["user"]["email"]) self.assertEqual(self.user.tx_name, response_data["user"]["name"]) self.assertEqual(self.user.accounts[1].id, response_data["current_account"]["id"]) self.assertEqual(self.user.accounts[1].name, response_data["current_account"]["name"]) jwt_response_header = response_data["jwt_token"] self.assertTrue(jwt_response_header) returned_token = jwt.decode(jwt_response_header, key=SECRET_KEY) self.assertEqual(self.user.tx_email, returned_token["user"]["email"]) self.assertEqual(self.user.tx_name, returned_token["user"]["name"]) self.assertEqual(self.user.accounts[1].id, returned_token["current_account"]["id"]) self.assertEqual(self.user.accounts[1].name, returned_token["current_account"]["name"])
def test_get_current_user_info_auth_invalid(self): with application.app_context(), application.test_client() as client: response = client.get("/hollow/account/me") self.assertEqual(401, response.status_code)