continuous-integration/drone/pr Build is passing
Регистрация остаётся закрытой. Администраторы — MAIL_ADMINS (по умолчанию первый ящик); роль не в базе, укравший ящик себя админом не сделает. API /api/admin/mailboxes, сгенерированный пароль — один раз в ответе, в лог не пишется. Настройки → MAILBOXES (видно только администратору). Тесты: MailboxAdminControllerTest (5), всего 73. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
82 lines
3.6 KiB
Java
82 lines
3.6 KiB
Java
package com.mailserver.controller;
|
|
|
|
import com.mailserver.config.MailDomains;
|
|
import com.mailserver.domain.User;
|
|
import com.mailserver.dto.LoginRequest;
|
|
import com.mailserver.security.LoginGuard;
|
|
import com.mailserver.service.MailService;
|
|
import com.mailserver.service.UserService;
|
|
import com.mailserver.util.JwtUtils;
|
|
import org.junit.jupiter.api.Test;
|
|
import org.springframework.http.HttpStatus;
|
|
import org.springframework.http.ResponseEntity;
|
|
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
|
|
import reactor.core.publisher.Mono;
|
|
|
|
import java.net.InetSocketAddress;
|
|
import java.time.Duration;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
|
import static org.mockito.ArgumentMatchers.any;
|
|
import static org.mockito.ArgumentMatchers.anyString;
|
|
import static org.mockito.ArgumentMatchers.eq;
|
|
import static org.mockito.Mockito.mock;
|
|
import static org.mockito.Mockito.never;
|
|
import static org.mockito.Mockito.verify;
|
|
import static org.mockito.Mockito.when;
|
|
|
|
class AuthenticationControllerTest {
|
|
|
|
private final UserService users = mock(UserService.class);
|
|
private final JwtUtils jwt = mock(JwtUtils.class);
|
|
private final LoginGuard guard = new LoginGuard(new LoginGuard.Settings(true, 3, 100, Duration.ofMinutes(15),
|
|
Duration.ofMinutes(15), Duration.ofHours(24), Duration.ofDays(30), Set.of(), Duration.ZERO));
|
|
private final AuthenticationController controller = new AuthenticationController(users, mock(MailService.class), jwt,
|
|
mock(MailDomains.class), false, guard, mock(com.mailserver.config.MailAdmins.class));
|
|
|
|
private final User alice = new User();
|
|
|
|
AuthenticationControllerTest() {
|
|
alice.setEmail("alice@x.test");
|
|
alice.setPassword("hash");
|
|
when(users.findByEmail("alice@x.test")).thenReturn(Mono.just(alice));
|
|
when(users.findByEmail("ghost@x.test")).thenReturn(Mono.empty());
|
|
when(users.checkPassword(eq(alice), anyString())).thenAnswer(i -> "secret".equals(i.getArgument(1)));
|
|
when(jwt.generateToken(any())).thenReturn("token");
|
|
}
|
|
|
|
private ResponseEntity<?> login(String ip, String email, String password) {
|
|
LoginRequest request = new LoginRequest();
|
|
request.setEmail(email);
|
|
request.setPassword(password);
|
|
MockServerHttpRequest http = MockServerHttpRequest.post("/api/login")
|
|
.remoteAddress(new InetSocketAddress(ip, 40000)).build();
|
|
return controller.login(Mono.just(request), http).block();
|
|
}
|
|
|
|
@Test
|
|
void unknownMailboxAndWrongPasswordLookTheSameAndBothCount() {
|
|
assertThat(login("1.2.3.4", "ghost@x.test", "x").getBody()).isEqualTo(Map.of("error", "Invalid credentials"));
|
|
assertThat(login("1.2.3.4", "alice@x.test", "x").getBody()).isEqualTo(Map.of("error", "Invalid credentials"));
|
|
login("1.2.3.4", "alice@x.test", "y");
|
|
|
|
ResponseEntity<?> blocked = login("1.2.3.4", "alice@x.test", "secret");
|
|
assertThat(blocked.getStatusCode()).isEqualTo(HttpStatus.TOO_MANY_REQUESTS);
|
|
assertThat(blocked.getHeaders().getFirst("Retry-After")).isEqualTo("900");
|
|
assertThat(blocked.getBody()).isEqualTo(Map.of("error", "Too many failed logins, try again in 15 min"));
|
|
|
|
assertThat(login("5.6.7.8", "alice@x.test", "secret").getStatusCode()).isEqualTo(HttpStatus.OK);
|
|
}
|
|
|
|
@Test
|
|
void blockedAttemptDoesNotCheckThePassword() {
|
|
for (int i = 0; i < 3; i++) {
|
|
login("1.2.3.4", "ghost@x.test", "x");
|
|
}
|
|
login("1.2.3.4", "alice@x.test", "secret");
|
|
verify(users, never()).checkPassword(any(), eq("secret"));
|
|
}
|
|
}
|