Verified Commit 9948088e authored by Peter Stanko's avatar Peter Stanko
Browse files

Ability to expire secrets -- and check whether the secret is expired

parent 770b124f
......@@ -83,7 +83,8 @@ class Client(db.Model):
self.type = client_type
def verify_secret(self, secret: str) -> bool:
return any(check_password_hash(item.value, secret) for item in self.secrets)
return any(check_password_hash(item.value, secret) and not item.expired
for item in self.secrets)
def query_permissions_for_course(self, course: 'Course'):
"""Returns the query for client's permissions in the course
......@@ -167,6 +168,18 @@ class Secret(db.Model, EntityBase):
def log_name(self):
return f"{self.id} ({self.name})"
@property
def expired(self) -> bool:
"""Gets whether the secret is expired or not
If the expires_at is empty, then it always returns False
Returns(bool):
"""
if self.expires_at is None:
return False
return time.normalize_time(self.expires_at) < time.current_time()
class User(EntityBase, Client):
"""User entity model
......
......@@ -301,6 +301,7 @@ class SecretSchema(BaseSchema, Schema):
"""
name = fields.Str()
expires_at = fields.LocalDateTime(allow_none=True)
expired = fields.Boolean
client = NESTED['client']
......
......@@ -3,8 +3,8 @@ from datetime import MAXYEAR, MINYEAR, datetime, timedelta
import pytest
from sqlalchemy import exc
from portal.database.models import Client, ClientType, Course, Group, Project, ProjectState, \
Review, ReviewItem, Role, Submission, User
from portal.database.models import Client, ClientType, Course, Group, Project, ProjectState, Review, \
ReviewItem, Role, Secret, Submission, User
from portal.tools import time
......@@ -469,7 +469,6 @@ def test_relation_course_project_update_swap_project_from_project(session, cours
def test_relation_course_project_update_swap_project_from_course(session, course1, course2):
project = Project(course=course1, name="p1")
session.add_all([project])
session.flush()
......@@ -685,6 +684,46 @@ def test_project_time_constraints_same_from_archive(session, course1):
session.flush()
def _get_secret(expires=None):
return Secret(name='test-secret', expires_at=expires, value='test-value')
def test_secret_expiration_is_empty(session, user1):
secret = _get_secret()
user1.secrets.append(secret)
session.add(secret)
session.flush()
assert not secret.expired
def test_secret_expiration_now(session, user1):
secret = _get_secret(time.current_time())
user1.secrets.append(secret)
session.add(secret)
session.flush()
assert secret.expired
def test_secret_expiration_yesterday(session, user1):
secret = _get_secret(time.current_time() - timedelta(days=1))
user1.secrets.append(secret)
session.add(secret)
session.flush()
assert secret.expired
def test_secret_expiration_tomorrow(session, user1):
secret = _get_secret(time.current_time() + timedelta(days=1))
user1.secrets.append(secret)
session.add(secret)
session.flush()
assert not secret.expired
def test_project_time_constraints_invalid_from_to(session, course1):
project = Project(course=course1, name="p1")
project.config.submissions_allowed_from = time.current_time()
......
......@@ -60,6 +60,7 @@ def test_list_secret(client):
assert_response(response, 200)
secrets = rest_tools.extract_data(response)
assert len(secrets) == 1
......
......@@ -2,6 +2,8 @@
import pytest
from portal.database.models import Secret
from portal.tools import time
from tests.rest import rest_tools
from .rest_tools import assert_response
......@@ -60,3 +62,21 @@ def test_user_logout(client, tokens):
}
response = client.post("/api/v1.0/auth/logout", headers=headers)
assert_response(response)
def test_login_with_expired_secret(client, rest_service):
secret1 = Secret(name='user_secret1', value='test-1', expires_at=None)
secret2 = Secret(name='user_secret2', value='test-2', expires_at=time.current_time())
student = rest_service.find.user('student1')
student.secrets.append(secret1)
student.secrets.append(secret2)
rest_service.general.write_entity(student)
request_dict1 = dict(type="secret", identifier="student1", secret="test-1")
request_dict2 = dict(type="secret", identifier="student1", secret="test-2")
response = client.post("/api/v1.0/auth/login", json=request_dict1)
assert_response(response)
response = client.post("/api/v1.0/auth/login", json=request_dict2)
assert_response(response, 401)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment