Skip to content

Commit a3ea05b

Browse files
authored
Merge pull request #896 from dfir-iris/api_v2_get_user_profile
Api v2 get user profile
2 parents e43d491 + 0720d4a commit a3ea05b

File tree

5 files changed

+116
-99
lines changed

5 files changed

+116
-99
lines changed

source/app/blueprints/rest/profile_routes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ def profile_refresh_permissions_and_ac():
181181

182182

183183
@profile_rest_blueprint.route('/user/whoami', methods=['GET'])
184+
@endpoint_deprecated('GET', '/api/v2/me')
184185
@ac_api_requires()
185186
def profile_whoami():
186187
"""Returns the current user's profile"""

source/app/blueprints/rest/v2/auth.py

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
from app.blueprints.rest.endpoints import response_api_success
3636
from app.business.auth import validate_ldap_login, validate_local_login, return_authed_user_info, generate_auth_tokens
3737
from app.iris_engine.utils.tracker import track_activity
38-
from app.schema.marshables import UserSchema
3938

4039

4140
auth_blueprint = Blueprint('auth', __name__, url_prefix='/auth')
@@ -112,23 +111,6 @@ def logout():
112111
return redirect(not_authenticated_redirection_url('/'))
113112

114113

115-
# TODO - We should have /api/v2/users/{identifier}. For now keeping it since the route doesn't exist elsewhere
116-
@auth_blueprint.route('/whoami', methods=['GET'])
117-
def whoami():
118-
"""
119-
Returns information about the currently authenticated user.
120-
"""
121-
122-
# Ensure we are authenticated
123-
if not iris_current_user.is_authenticated:
124-
return response_api_error("Unauthenticated")
125-
126-
# Return the current_user dict
127-
return response_api_success(data=UserSchema(only=[
128-
'id', 'user_name', 'user_login', 'user_email'
129-
]).dump(iris_current_user))
130-
131-
132114
@auth_blueprint.post('/refresh-token')
133115
def refresh_token_endpoint():
134116
"""

source/app/blueprints/rest/v2/case_objects/evidences.py

Lines changed: 100 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -39,114 +39,133 @@
3939
from app.business.evidences import evidences_update
4040
from app.business.evidences import evidences_filter
4141
from app.business.evidences import evidences_delete
42-
from app.models.models import CaseReceivedFile
4342

4443

45-
case_evidences_blueprint = Blueprint('case_evidences_rest_v2', __name__, url_prefix='/<int:case_identifier>/evidences')
44+
class EvidencesOperations:
4645

46+
def __init__(self):
47+
self._schema = CaseEvidenceSchema()
4748

48-
@case_evidences_blueprint.get('')
49-
@ac_api_requires()
50-
def get_evidences(case_identifier):
51-
if not cases_exists(case_identifier):
52-
return response_api_not_found()
49+
@staticmethod
50+
def _get_evidence_in_case(identifier, case_identifier):
51+
evidence = evidences_get(identifier)
52+
if evidence.case_id != case_identifier:
53+
raise BusinessProcessingError(f'Evidence {evidence.id} does not belong to case {case_identifier}')
54+
return evidence
5355

54-
if not ac_fast_check_current_user_has_case_access(case_identifier, [CaseAccessLevel.read_only, CaseAccessLevel.full_access]):
55-
return ac_api_return_access_denied(caseid=case_identifier)
56+
def list(self, case_identifier):
57+
if not cases_exists(case_identifier):
58+
return response_api_not_found()
5659

57-
pagination_parameters = parse_pagination_parameters(request, default_order_by='date_added', default_direction='desc')
58-
try:
59-
evidences = evidences_filter(case_identifier, pagination_parameters)
60+
if not ac_fast_check_current_user_has_case_access(case_identifier,
61+
[CaseAccessLevel.read_only, CaseAccessLevel.full_access]):
62+
return ac_api_return_access_denied(caseid=case_identifier)
6063

61-
evidence_schema = CaseEvidenceSchema()
62-
return response_api_paginated(evidence_schema, evidences)
63-
except BusinessProcessingError as e:
64-
return response_api_error(e.get_message(), data=e.get_data())
64+
pagination_parameters = parse_pagination_parameters(request, default_order_by='date_added',
65+
default_direction='desc')
66+
try:
67+
evidences = evidences_filter(case_identifier, pagination_parameters)
6568

69+
return response_api_paginated(self._schema, evidences)
70+
except BusinessProcessingError as e:
71+
return response_api_error(e.get_message(), data=e.get_data())
6672

67-
@case_evidences_blueprint.post('')
68-
@ac_api_requires()
69-
def create_evidence(case_identifier):
73+
def create(self, case_identifier):
7074

71-
if not cases_exists(case_identifier):
72-
return response_api_not_found()
73-
if not ac_fast_check_current_user_has_case_access(case_identifier, [CaseAccessLevel.full_access]):
74-
return ac_api_return_access_denied(caseid=case_identifier)
75+
if not cases_exists(case_identifier):
76+
return response_api_not_found()
77+
if not ac_fast_check_current_user_has_case_access(case_identifier, [CaseAccessLevel.full_access]):
78+
return ac_api_return_access_denied(caseid=case_identifier)
7579

76-
try:
77-
evidence = evidences_create(case_identifier, request.get_json())
80+
try:
81+
evidence = evidences_create(case_identifier, request.get_json())
7882

79-
evidence_schema = CaseEvidenceSchema()
80-
return response_api_created(evidence_schema.dump(evidence))
81-
except BusinessProcessingError as e:
82-
return response_api_error(e.get_message(), data=e.get_data())
83+
return response_api_created(self._schema.dump(evidence))
84+
except BusinessProcessingError as e:
85+
return response_api_error(e.get_message(), data=e.get_data())
8386

87+
def get(self, case_identifier, identifier):
88+
if not cases_exists(case_identifier):
89+
return response_api_not_found()
8490

85-
@case_evidences_blueprint.get('/<int:identifier>')
86-
@ac_api_requires()
87-
def get_evidence(case_identifier, identifier):
88-
if not cases_exists(case_identifier):
89-
return response_api_not_found()
91+
try:
92+
evidence = self._get_evidence_in_case(identifier, case_identifier)
9093

91-
try:
92-
evidence = evidences_get(identifier)
93-
_check_evidence_and_case_identifier_match(evidence, case_identifier)
94+
if not ac_fast_check_current_user_has_case_access(evidence.case_id,
95+
[CaseAccessLevel.read_only, CaseAccessLevel.full_access]):
96+
return ac_api_return_access_denied(caseid=evidence.case_id)
9497

95-
if not ac_fast_check_current_user_has_case_access(evidence.case_id, [CaseAccessLevel.read_only, CaseAccessLevel.full_access]):
96-
return ac_api_return_access_denied(caseid=evidence.case_id)
98+
return response_api_success(self._schema.dump(evidence))
99+
except ObjectNotFoundError:
100+
return response_api_not_found()
101+
except BusinessProcessingError as e:
102+
return response_api_error(e.get_message(), data=e.get_data())
97103

98-
evidence_schema = CaseEvidenceSchema()
99-
return response_api_success(evidence_schema.dump(evidence))
100-
except ObjectNotFoundError:
101-
return response_api_not_found()
102-
except BusinessProcessingError as e:
103-
return response_api_error(e.get_message(), data=e.get_data())
104+
def update(self, case_identifier, identifier):
105+
if not cases_exists(case_identifier):
106+
return response_api_not_found()
104107

108+
try:
109+
evidence = self._get_evidence_in_case(identifier, case_identifier)
110+
if not ac_fast_check_current_user_has_case_access(evidence.case_id, [CaseAccessLevel.full_access]):
111+
return ac_api_return_access_denied(caseid=evidence.case_id)
105112

106-
@case_evidences_blueprint.put('/<int:identifier>')
107-
@ac_api_requires()
108-
def update_evidence(case_identifier, identifier):
109-
if not cases_exists(case_identifier):
110-
return response_api_not_found()
113+
evidence = evidences_update(evidence, request.get_json())
111114

112-
try:
113-
evidence = evidences_get(identifier)
114-
if not ac_fast_check_current_user_has_case_access(evidence.case_id, [CaseAccessLevel.full_access]):
115-
return ac_api_return_access_denied(caseid=evidence.case_id)
116-
_check_evidence_and_case_identifier_match(evidence, case_identifier)
115+
result = self._schema.dump(evidence)
116+
return response_api_success(result)
117+
except ObjectNotFoundError:
118+
return response_api_not_found()
119+
except BusinessProcessingError as e:
120+
return response_api_error(e.get_message(), data=e.get_data())
117121

118-
evidence = evidences_update(evidence, request.get_json())
122+
def delete(self, case_identifier, identifier):
123+
if not cases_exists(case_identifier):
124+
return response_api_not_found()
119125

120-
schema = CaseEvidenceSchema()
121-
result = schema.dump(evidence)
122-
return response_api_success(result)
123-
except ObjectNotFoundError:
124-
return response_api_not_found()
125-
except BusinessProcessingError as e:
126-
return response_api_error(e.get_message(), data=e.get_data())
126+
try:
127+
evidence = self._get_evidence_in_case(identifier, case_identifier)
128+
if not ac_fast_check_current_user_has_case_access(evidence.case_id, [CaseAccessLevel.full_access]):
129+
return ac_api_return_access_denied(caseid=evidence.case_id)
127130

131+
evidences_delete(evidence)
128132

129-
@case_evidences_blueprint.delete('/<int:identifier>')
133+
return response_api_deleted()
134+
except ObjectNotFoundError:
135+
return response_api_not_found()
136+
except BusinessProcessingError as e:
137+
return response_api_error(e.get_message(), data=e.get_data())
138+
139+
140+
evidences_operations = EvidencesOperations()
141+
case_evidences_blueprint = Blueprint('case_evidences_rest_v2', __name__, url_prefix='/<int:case_identifier>/evidences')
142+
143+
144+
@case_evidences_blueprint.get('')
130145
@ac_api_requires()
131-
def delete_evidence(case_identifier, identifier):
132-
if not cases_exists(case_identifier):
133-
return response_api_not_found()
146+
def get_evidences(case_identifier):
147+
return evidences_operations.list(case_identifier)
148+
149+
150+
@case_evidences_blueprint.post('')
151+
@ac_api_requires()
152+
def create_evidence(case_identifier):
153+
return evidences_operations.create(case_identifier)
134154

135-
try:
136-
evidence = evidences_get(identifier)
137-
_check_evidence_and_case_identifier_match(evidence, case_identifier)
138-
if not ac_fast_check_current_user_has_case_access(evidence.case_id, [CaseAccessLevel.full_access]):
139-
return ac_api_return_access_denied(caseid=evidence.case_id)
140155

141-
evidences_delete(evidence)
156+
@case_evidences_blueprint.get('/<int:identifier>')
157+
@ac_api_requires()
158+
def get_evidence(case_identifier, identifier):
159+
return evidences_operations.get(case_identifier, identifier)
142160

143-
return response_api_deleted()
144-
except ObjectNotFoundError:
145-
return response_api_not_found()
146-
except BusinessProcessingError as e:
147-
return response_api_error(e.get_message(), data=e.get_data())
161+
162+
@case_evidences_blueprint.put('/<int:identifier>')
163+
@ac_api_requires()
164+
def update_evidence(case_identifier, identifier):
165+
return evidences_operations.update(case_identifier, identifier)
148166

149167

150-
def _check_evidence_and_case_identifier_match(evidence: CaseReceivedFile, case_identifier):
151-
if evidence.case_id != case_identifier:
152-
raise BusinessProcessingError(f'Evidence {evidence.id} does not belong to case {case_identifier}')
168+
@case_evidences_blueprint.delete('/<int:identifier>')
169+
@ac_api_requires()
170+
def delete_evidence(case_identifier, identifier):
171+
return evidences_operations.delete(case_identifier, identifier)

source/app/blueprints/rest/v2/profile.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ def __init__(self):
3535
self._schema = UserSchemaForAPIV2()
3636
self._update_request_schema = UserSchemaForAPIV2(exclude=['user_is_service_account', 'user_active', 'uuid'])
3737

38+
def get(self):
39+
user = users_get(iris_current_user.id)
40+
result = self._schema.dump(user)
41+
return response_api_success(result)
42+
3843
def update(self):
3944
try:
4045
user = users_get(iris_current_user.id)
@@ -52,6 +57,12 @@ def update(self):
5257
profile_blueprint = Blueprint('profile_rest_v2', __name__, url_prefix='/me')
5358

5459

60+
@profile_blueprint.get('')
61+
@ac_api_requires()
62+
def get_profile():
63+
return profile_operations.get()
64+
65+
5566
@profile_blueprint.put('')
5667
@ac_api_requires()
5768
def update_profile():

tests/tests_rest_profile.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ def setUp(self) -> None:
2828
def tearDown(self):
2929
self._subject.clear_database()
3030

31+
def test_get_me_should_return_200(self):
32+
response = self._subject.get('/api/v2/me')
33+
self.assertEqual(200, response.status_code)
34+
3135
def test_update_me_should_return_200(self):
3236
response = self._subject.update('/api/v2/me', {})
3337
self.assertEqual(200, response.status_code)

0 commit comments

Comments
 (0)