fix(web): перепроверять статус сессии
This commit is contained in:
@@ -42,4 +42,5 @@ data class MeResponse(
|
||||
val role: String,
|
||||
val name: String,
|
||||
val mustChangePassword: Boolean,
|
||||
val active: Boolean = true,
|
||||
)
|
||||
|
||||
@@ -73,22 +73,25 @@ class AuthService(
|
||||
}
|
||||
|
||||
private fun ensureLoginAllowed(account: Account) {
|
||||
if (account.status != AccountStatus.ACTIVE) {
|
||||
throw UnauthorizedException("Аккаунт архивирован")
|
||||
}
|
||||
if (account.role != LmsRole.STUDENT) return
|
||||
val status = students.findById(account.id).map { it.status }.orElse(null)
|
||||
if (status in setOf(StudentStatus.EXPELLED, StudentStatus.GRADUATED, StudentStatus.ARCHIVED)) {
|
||||
throw UnauthorizedException("Доступ к системе закрыт")
|
||||
}
|
||||
ensureGroupOpen(account)
|
||||
loginDeniedReason(account)?.let { throw UnauthorizedException(it) }
|
||||
}
|
||||
|
||||
private fun ensureGroupOpen(account: Account) {
|
||||
val groupStatus = enrollments.findByStudentAccountId(account.id)?.group?.status
|
||||
if (groupStatus in setOf(GroupStatus.GRADUATED, GroupStatus.ARCHIVED)) {
|
||||
throw UnauthorizedException("Группа закрыта")
|
||||
/** Причина запрета входа или null, если вход разрешён. Используется и в me(). */
|
||||
private fun loginDeniedReason(account: Account): String? {
|
||||
if (account.status != AccountStatus.ACTIVE) {
|
||||
return "Аккаунт архивирован"
|
||||
}
|
||||
if (account.role != LmsRole.STUDENT) return null
|
||||
val status = students.findById(account.id).map { it.status }.orElse(null)
|
||||
if (status in setOf(StudentStatus.EXPELLED, StudentStatus.GRADUATED, StudentStatus.ARCHIVED)) {
|
||||
return "Доступ к системе закрыт"
|
||||
}
|
||||
return groupDeniedReason(account)
|
||||
}
|
||||
|
||||
private fun groupDeniedReason(account: Account): String? {
|
||||
val groupStatus = enrollments.findByStudentAccountId(account.id)?.group?.status
|
||||
return if (groupStatus in setOf(GroupStatus.GRADUATED, GroupStatus.ARCHIVED)) "Группа закрыта" else null
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
@@ -103,6 +106,7 @@ class AuthService(
|
||||
role = account.role.name,
|
||||
name = displayName(account),
|
||||
mustChangePassword = account.mustChangePassword,
|
||||
active = loginDeniedReason(account) == null,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package ru.ysu.lms.identity
|
||||
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.security.crypto.password.PasswordEncoder
|
||||
import org.springframework.security.oauth2.jwt.JwtEncoder
|
||||
import ru.ysu.lms.identity.auth.AuthService
|
||||
import ru.ysu.lms.identity.auth.LoginBackoff
|
||||
import ru.ysu.lms.identity.domain.Account
|
||||
import ru.ysu.lms.identity.domain.AccountStatus
|
||||
import ru.ysu.lms.identity.domain.Enrollment
|
||||
import ru.ysu.lms.identity.domain.GroupEntity
|
||||
import ru.ysu.lms.identity.domain.GroupStatus
|
||||
import ru.ysu.lms.identity.domain.Student
|
||||
import ru.ysu.lms.identity.domain.StudentStatus
|
||||
import ru.ysu.lms.identity.repo.AccountRepository
|
||||
import ru.ysu.lms.identity.repo.EnrollmentRepository
|
||||
import ru.ysu.lms.identity.repo.LoginAttemptRepository
|
||||
import ru.ysu.lms.identity.repo.StudentRepository
|
||||
import ru.ysu.lms.security.JwtProperties
|
||||
import ru.ysu.lms.security.LmsRole
|
||||
import java.time.Duration
|
||||
import java.util.Optional
|
||||
|
||||
class AuthServiceMeActiveTest {
|
||||
@Test
|
||||
fun `me is active for active student`() {
|
||||
val account = studentAccount()
|
||||
val service = service(account, Student(accountId = account.id, lastName = "Иванов", firstName = "Иван"))
|
||||
|
||||
val me = service.me(account.id)
|
||||
|
||||
assertThat(me.active).isTrue()
|
||||
assertThat(me.name).isEqualTo("Иванов Иван")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `me is inactive for expelled student`() {
|
||||
val account = studentAccount()
|
||||
val student =
|
||||
Student(
|
||||
accountId = account.id,
|
||||
lastName = "Иванов",
|
||||
firstName = "Иван",
|
||||
status = StudentStatus.EXPELLED,
|
||||
)
|
||||
val service = service(account, student)
|
||||
|
||||
assertThat(service.me(account.id).active).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `me is inactive for archived group`() {
|
||||
val account = studentAccount()
|
||||
val student = Student(accountId = account.id, lastName = "Иванов", firstName = "Иван")
|
||||
val group = GroupEntity(name = "ИВТ-21", status = GroupStatus.ARCHIVED)
|
||||
val service = service(account, student, Enrollment(group = group))
|
||||
|
||||
assertThat(service.me(account.id).active).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `me is inactive for archived account`() {
|
||||
val account = studentAccount().apply { status = AccountStatus.ARCHIVED }
|
||||
val service = service(account, Student(accountId = account.id, lastName = "Иванов", firstName = "Иван"))
|
||||
|
||||
assertThat(service.me(account.id).active).isFalse()
|
||||
}
|
||||
|
||||
private fun studentAccount(): Account = Account(login = "2025001", passwordHash = "hash", role = LmsRole.STUDENT)
|
||||
|
||||
private fun service(
|
||||
account: Account,
|
||||
student: Student,
|
||||
enrollment: Enrollment? = null,
|
||||
): AuthService {
|
||||
val accounts = mockk<AccountRepository>()
|
||||
every { accounts.findById(account.id) } returns Optional.of(account)
|
||||
val students = mockk<StudentRepository>()
|
||||
every { students.findById(account.id) } returns Optional.of(student)
|
||||
val enrollments = mockk<EnrollmentRepository>()
|
||||
every { enrollments.findByStudentAccountId(account.id) } returns enrollment
|
||||
return AuthService(
|
||||
accounts,
|
||||
students,
|
||||
enrollments,
|
||||
mockk<PasswordEncoder>(),
|
||||
mockk<JwtEncoder>(),
|
||||
JwtProperties(accessTokenTtl = Duration.ofMinutes(10)),
|
||||
LoginBackoff(mockk<LoginAttemptRepository>(relaxed = true)),
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user