Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add permission checks for admin to read and write in any cod_SIAPE_instituidora #104

Merged
merged 31 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
41b7e73
Add test for admin create pe in another unit
augusto-herrmann Jan 26, 2024
f9e0b26
Checks that user is admin in test
augusto-herrmann Jan 26, 2024
d343cf3
Add test admin create status_participante
augusto-herrmann Jan 26, 2024
74ee363
Solve linting warning singleton comparison
augusto-herrmann Jan 26, 2024
6901855
Add test for admin create pt in another unit
augusto-herrmann Jan 26, 2024
99cb692
Use for tests user that is not actual admin
augusto-herrmann Jan 26, 2024
8cda1ed
Fix organizational unit in test
augusto-herrmann Jan 26, 2024
58fe6d8
Implement is_admin check in endpoint permissions
augusto-herrmann Jan 26, 2024
0ee1686
Solve linting warning
augusto-herrmann Jan 30, 2024
cea2d28
Solve linting warning
augusto-herrmann Jan 30, 2024
1cdc210
Format with black
augusto-herrmann Jan 30, 2024
a0da0e3
Add fixtures to fix test
augusto-herrmann Jan 30, 2024
063735f
Add fixture for creating a pt in unit 3
augusto-herrmann Jan 30, 2024
e2f091f
Adjust fixtures to recreate pe at every test
augusto-herrmann Jan 30, 2024
9cbab50
Add tests for creating a pt in different unit
augusto-herrmann Jan 30, 2024
30885bd
Change user in test to not admin user
augusto-herrmann Jan 30, 2024
65eff6f
Implement permission check to read pt
augusto-herrmann Jan 30, 2024
38e9083
Add docstrings to tests
augusto-herrmann Jan 30, 2024
b7e5e19
Add tests for creating pe in different unit
augusto-herrmann Jan 30, 2024
f1397cc
Implement access control for reading plano_entrega
augusto-herrmann Jan 30, 2024
478e39e
Add missing docstrings and make summaries uniform
augusto-herrmann Jan 31, 2024
946f4a3
Fix test to use a normal user and add example data
augusto-herrmann Jan 31, 2024
e985a11
Add assert equal in get pe
augusto-herrmann Jan 31, 2024
0a9e5e0
Add helper functions for comparing status part
augusto-herrmann Jan 31, 2024
11acce2
Compare status part content in test
augusto-herrmann Jan 31, 2024
934fbc6
Formatting and remove debug prints
augusto-herrmann Jan 31, 2024
182d3d6
Create example_part_unidade_3 fixture
augusto-herrmann Jan 31, 2024
c16d9c1
Implement permission check in GET status_part
augusto-herrmann Jan 31, 2024
14232d7
Replace fixture used in URL
augusto-herrmann Jan 31, 2024
3a215fc
Rename test
augusto-herrmann Jan 31, 2024
b209066
Add test add part in different unit as admin
augusto-herrmann Jan 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 46 additions & 34 deletions src/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,15 @@

@app.on_event("startup")
async def on_startup():
"""Executa as rotinas de inicialização da API."""
await create_db_and_tables()
await crud_auth.init_user_admin()


@app.get("/", include_in_schema=False)
async def docs_redirect(accept: Union[str, None] = Header(default="text/html")):
async def docs_redirect(
accept: Union[str, None] = Header(default="text/html")
) -> RedirectResponse:
"""
Redireciona para a documentação da API.
"""
Expand All @@ -66,14 +69,16 @@ async def docs_redirect(accept: Union[str, None] = Header(default="text/html")):

@app.post(
"/token",
summary="Autentica na api-pgd",
summary="Autentica na API.",
response_model=schemas.Token,
tags=["Auth"],
)
async def login_for_access_token(
form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
db: DbContextManager = Depends(DbContextManager),
):
) -> dict:
"""Realiza o login na API usando as credenciais de acesso, obtendo um
token de acesso."""
try:
schemas.UsersInputSchema(email=form_data.username)
except Exception as exception:
Expand Down Expand Up @@ -101,7 +106,7 @@ async def login_for_access_token(

@app.get(
"/users",
summary="Consulta usuários da api-pgd",
summary="Lista usuários da API.",
tags=["Auth"],
)
async def get_users(
Expand All @@ -111,12 +116,13 @@ async def get_users(
],
db: DbContextManager = Depends(DbContextManager),
) -> list[schemas.UsersGetSchema]:
"""Obtém a lista de usuários da API."""
return await crud_auth.get_all_users(db)


@app.put(
"/user/{email}",
summary="Cria ou edita usuário na api-pgd",
summary="Cria ou altera usuário na API.",
tags=["Auth"],
)
async def create_or_update_user(
Expand All @@ -127,6 +133,8 @@ async def create_or_update_user(
email: str,
db: DbContextManager = Depends(DbContextManager),
) -> dict:
"""Cria um usuário da API ou atualiza os seus dados cadastrais."""

# Validações

# ## url
Expand Down Expand Up @@ -166,7 +174,7 @@ async def create_or_update_user(

@app.get(
"/user/{email}",
summary="Consulta usuários da api-pgd",
summary="Consulta um usuário da API.",
tags=["Auth"],
)
async def get_user(
Expand All @@ -177,6 +185,9 @@ async def get_user(
email: str,
db: DbContextManager = Depends(DbContextManager),
) -> schemas.UsersGetSchema:
"""Retorna os dados cadastrais do usuário da API especificado pelo
e-mail informado."""

user = await crud_auth.get_user(db, email)

if user:
Expand All @@ -189,13 +200,16 @@ async def get_user(

@app.post(
"/user/forgot_password/{email}",
summary="Recuperação de Acesso",
summary="Solicita recuperação de acesso à API.",
tags=["Auth"],
)
async def forgot_password(
email: str,
db: DbContextManager = Depends(DbContextManager),
) -> schemas.UsersInputSchema:
"""Dispara o processo de recuperação de senha, enviando um token de
redefinição de senha ao e-mail informado no cadastro do usuário."""

user = await crud_auth.get_user(db, email)

if user:
Expand All @@ -213,7 +227,7 @@ async def forgot_password(

@app.get(
"/user/reset_password/",
summary="Criar nova senha a partir do token de acesso",
summary="Criar nova senha a partir do token de acesso.",
tags=["Auth"],
)
async def reset_password(
Expand Down Expand Up @@ -243,13 +257,22 @@ async def reset_password(
)
async def get_plano_entrega(
user: Annotated[schemas.UsersSchema, Depends(crud_auth.get_current_active_user)],
cod_SIAPE_instituidora: int,
id_plano_entrega_unidade: int,
db: DbContextManager = Depends(DbContextManager),
):
"Consulta o plano de entregas com o código especificado."

# Validações de permissão
if (cod_SIAPE_instituidora != user.cod_SIAPE_instituidora) and not user.is_admin:
raise HTTPException(
status.HTTP_401_UNAUTHORIZED,
detail="Usuário não tem permissão na cod_SIAPE_instituidora informada",
)

db_plano_entrega = await crud.get_plano_entregas(
db_session=db,
cod_SIAPE_instituidora=user.cod_SIAPE_instituidora,
cod_SIAPE_instituidora=cod_SIAPE_instituidora,
id_plano_entrega_unidade=id_plano_entrega_unidade,
)
if not db_plano_entrega:
Expand Down Expand Up @@ -278,12 +301,7 @@ async def create_or_update_plano_entregas(
plano de entregas por um novo com os dados informados."""

# Validações de permissão
if (
cod_SIAPE_instituidora
!= user.cod_SIAPE_instituidora
# TODO: Dar acesso ao superusuário em todas as unidades.
# and "all:write" not in access_token_info["permissions"]
):
if (cod_SIAPE_instituidora != user.cod_SIAPE_instituidora) and not user.is_admin:
raise HTTPException(
status.HTTP_401_UNAUTHORIZED,
detail="Usuário não tem permissão na cod_SIAPE_instituidora informada",
Expand Down Expand Up @@ -366,13 +384,22 @@ async def create_or_update_plano_entregas(
)
async def get_plano_trabalho(
user: Annotated[schemas.UsersSchema, Depends(crud_auth.get_current_active_user)],
cod_SIAPE_instituidora: int,
id_plano_trabalho_participante: int,
db: DbContextManager = Depends(DbContextManager),
):
"Consulta o plano de trabalho com o código especificado."

# Validações de permissão
if (cod_SIAPE_instituidora != user.cod_SIAPE_instituidora) and not user.is_admin:
raise HTTPException(
status.HTTP_401_UNAUTHORIZED,
detail="Usuário não tem permissão na cod_SIAPE_instituidora informada",
)

db_plano_trabalho = await crud.get_plano_trabalho(
db_session=db,
cod_SIAPE_instituidora=user.cod_SIAPE_instituidora,
cod_SIAPE_instituidora=cod_SIAPE_instituidora,
id_plano_trabalho_participante=id_plano_trabalho_participante,
)
if not db_plano_trabalho:
Expand Down Expand Up @@ -401,12 +428,7 @@ async def create_or_update_plano_trabalho(
plano de trabalho por um novo com os dados informados."""

# Validações de permissão
if (
cod_SIAPE_instituidora
!= user.cod_SIAPE_instituidora
# TODO: Dar acesso ao superusuário em todas as unidades.
# and "all:write" not in access_token_info["permissions"]
):
if (cod_SIAPE_instituidora != user.cod_SIAPE_instituidora) and not user.is_admin:
raise HTTPException(
status.HTTP_401_UNAUTHORIZED,
detail="Usuário não tem permissão na cod_SIAPE_instituidora informada",
Expand Down Expand Up @@ -499,12 +521,7 @@ async def get_status_participante(
"Consulta o status do participante a partir da matricula SIAPE."

# Validações de permissão
if (
cod_SIAPE_instituidora
!= user.cod_SIAPE_instituidora
# TODO: Dar acesso ao superusuário em todas as unidades.
# and "all:write" not in access_token_info["permissions"]
):
if (cod_SIAPE_instituidora != user.cod_SIAPE_instituidora) and not user.is_admin:
raise HTTPException(
status.HTTP_401_UNAUTHORIZED,
detail="Usuário não tem permissão na cod_SIAPE_instituidora informada",
Expand Down Expand Up @@ -540,12 +557,7 @@ async def create_status_participante(
"""Envia um ou mais status de Programa de Gestão de um participante."""

# Validações de permissão
if (
cod_SIAPE_instituidora
!= user.cod_SIAPE_instituidora
# TODO: Dar acesso ao superusuário em todas as unidades.
# and "all:write" not in access_token_info["permissions"]
):
if (cod_SIAPE_instituidora != user.cod_SIAPE_instituidora) and not user.is_admin:
raise HTTPException(
status.HTTP_401_UNAUTHORIZED,
detail="Usuário não tem permissão na cod_SIAPE_instituidora informada",
Expand Down
58 changes: 53 additions & 5 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,23 @@ def example_pe(
)


@pytest.fixture()
def example_pe_unidade_3(
client: httpx.Client,
input_pe: dict,
user1_credentials: dict,
header_usr_1: dict,
):
"""Cria um Plano de Entrega como exemplo."""
input_pe["cod_SIAPE_instituidora"] = 3
client.put(
f"/organizacao/{input_pe['cod_SIAPE_instituidora']}"
f"/plano_entregas/{input_pe['id_plano_entrega_unidade']}",
json=input_pe,
headers=header_usr_1,
)


@pytest.fixture()
def example_pt(
client: httpx.Client, input_pt: dict, user1_credentials: dict, header_usr_1: dict
Expand All @@ -241,15 +258,46 @@ def example_pt(
)


@pytest.fixture()
def example_pt_unidade_3(
client: httpx.Client,
input_pt: dict,
header_admin: dict,
):
"""Cria um Plano de Trabalho do Participante como exemplo."""
input_pt["cod_SIAPE_instituidora"] = 3
client.put(
f"/organizacao/{input_pt['cod_SIAPE_instituidora']}"
f"/plano_trabalho/{input_pt['id_plano_trabalho_participante']}",
json=input_pt,
headers=header_admin,
)


@pytest.fixture()
def example_part(
client: httpx.Client, input_part: dict, user1_credentials: dict, header_usr_1: dict
client: httpx.Client, input_part: dict, header_admin: dict
):
"""Cria um exemplo de status de participante."""
client.put(
f"/organizacao/{user1_credentials['cod_SIAPE_instituidora']}"
f"/organizacao/{input_part['cod_SIAPE_instituidora']}"
f"/participante/{input_part['cpf_participante']}",
json={"lista_status": [input_part]},
headers=header_usr_1,
headers=header_admin,
)


@pytest.fixture()
def example_part_unidade_3(
client: httpx.Client, input_part: dict, header_admin: dict
):
"""Cria um exemplo de status de participante na unidade 3."""
input_part["cod_SIAPE_instituidora"] = 3
client.put(
f"/organizacao/{input_part['cod_SIAPE_instituidora']}"
f"/participante/{input_part['cpf_participante']}",
json={"lista_status": [input_part]},
headers=header_admin,
)


Expand All @@ -269,7 +317,7 @@ def truncate_participantes():


@pytest.fixture(scope="module", name="truncate_users")
def fixture_truncate_users(admin_credentials: dict):
def fixture_truncate_users(admin_credentials: dict): # pylint: disable=unused-argument
truncate_user()
asyncio.get_event_loop().run_until_complete(init_user_admin())

Expand Down Expand Up @@ -309,7 +357,7 @@ def header_not_logged_in() -> dict:

@pytest.fixture(scope="module", name="header_admin")
def fixture_header_admin(
register_admin, admin_credentials: dict # pylint: disable=unused-argument
admin_credentials: dict, # pylint: disable=unused-argument
) -> dict:
"""Authenticate in the API as an admin and return a dict with bearer
header parameter to be passed to API's requests."""
Expand Down
Loading