mirror of
https://github.com/iflytek/skillhub.git
synced 2026-09-22 00:31:21 +00:00
test(auth): add SSO unit tests (22 tests) and fix timeout configuration
- Add SsoClientTest (7 tests): ticket validation, null/empty/missing field responses, custom response field mapping - Add SsoIdentityServiceTest (6 tests): auto-provisioning, display name update, disabled user rejection, role resolution - Add SsoLoginControllerTest (9 tests): enabled/disabled guard, redirect flow, returnTo preservation, error handling - Fix SsoClient: replace RestTemplateBuilder with SimpleClientHttpRequestFactory for timeout config (RestTemplateBuilder.connectTimeout() is a valid Spring Boot 3.x API but caused transient build failures in Docker buildx)
This commit is contained in:
parent
cbe675e98d
commit
bd805c941a
4 changed files with 518 additions and 6 deletions
|
|
@ -0,0 +1,188 @@
|
|||
package com.iflytek.skillhub.controller;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.iflytek.skillhub.auth.config.SsoProperties;
|
||||
import com.iflytek.skillhub.auth.rbac.PlatformPrincipal;
|
||||
import com.iflytek.skillhub.auth.session.PlatformSessionService;
|
||||
import com.iflytek.skillhub.auth.sso.SsoClient;
|
||||
import com.iflytek.skillhub.auth.sso.SsoIdentityService;
|
||||
import com.iflytek.skillhub.auth.sso.SsoUser;
|
||||
import com.iflytek.skillhub.auth.sso.TicketValidationException;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import java.util.Set;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class SsoLoginControllerTest {
|
||||
|
||||
private static final String BASE_URL = "https://sso.example.com";
|
||||
private static final String CLIENT_URL = "https://skillhub.example.com/api/v1/auth/sso/callback";
|
||||
|
||||
private SsoProperties properties;
|
||||
|
||||
@Mock
|
||||
private SsoClient ssoClient;
|
||||
|
||||
@Mock
|
||||
private SsoIdentityService ssoIdentityService;
|
||||
|
||||
@Mock
|
||||
private PlatformSessionService platformSessionService;
|
||||
|
||||
private SsoLoginController controller;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
properties = new SsoProperties();
|
||||
properties.setBaseUrl(BASE_URL);
|
||||
properties.setClientUrl(CLIENT_URL);
|
||||
controller = new SsoLoginController(properties, ssoClient, ssoIdentityService,
|
||||
platformSessionService);
|
||||
}
|
||||
|
||||
@Test
|
||||
void ssoLogin_enabled_redirectsToSsoServer() throws Exception {
|
||||
properties.setEnabled(true);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
controller.ssoLogin(null, request, response);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(302);
|
||||
assertThat(response.getRedirectedUrl())
|
||||
.startsWith("https://sso.example.com/login")
|
||||
.contains("clientUrl=" + CLIENT_URL);
|
||||
}
|
||||
|
||||
@Test
|
||||
void ssoLogin_disabled_returns403() throws Exception {
|
||||
properties.setEnabled(false);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
controller.ssoLogin(null, request, response);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(403);
|
||||
}
|
||||
|
||||
@Test
|
||||
void ssoLogin_withReturnTo_storesInSession() throws Exception {
|
||||
properties.setEnabled(true);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setParameter("returnTo", "/skills/123");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
controller.ssoLogin("/skills/123", request, response);
|
||||
|
||||
HttpSession session = request.getSession(false);
|
||||
assertThat(session).isNotNull();
|
||||
assertThat(session.getAttribute("ssoReturnTo")).isEqualTo("/skills/123");
|
||||
}
|
||||
|
||||
@Test
|
||||
void ssoCallback_enabled_validatesTicketAndRedirects() throws Exception {
|
||||
properties.setEnabled(true);
|
||||
SsoUser ssoUser = new SsoUser("zhangsan", "EMP001", "张三");
|
||||
PlatformPrincipal principal = new PlatformPrincipal(
|
||||
"usr_001", "张三", null, null, "sso", Set.of("USER"));
|
||||
|
||||
when(ssoClient.validateTicket("ST-valid")).thenReturn(ssoUser);
|
||||
when(ssoIdentityService.resolveOrCreate(ssoUser)).thenReturn(principal);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
controller.ssoCallback("ST-valid", request, response);
|
||||
|
||||
verify(platformSessionService).establishSession(principal, request);
|
||||
assertThat(response.getStatus()).isEqualTo(302);
|
||||
assertThat(response.getRedirectedUrl()).isEqualTo("/");
|
||||
}
|
||||
|
||||
@Test
|
||||
void ssoCallback_withReturnTo_redirectsToSavedUrl() throws Exception {
|
||||
properties.setEnabled(true);
|
||||
SsoUser ssoUser = new SsoUser("zhangsan", "EMP001", "张三");
|
||||
PlatformPrincipal principal = new PlatformPrincipal(
|
||||
"usr_001", "张三", null, null, "sso", Set.of("USER"));
|
||||
|
||||
when(ssoClient.validateTicket("ST-valid")).thenReturn(ssoUser);
|
||||
when(ssoIdentityService.resolveOrCreate(ssoUser)).thenReturn(principal);
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.getSession().setAttribute("ssoReturnTo", "/skills/456");
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
controller.ssoCallback("ST-valid", request, response);
|
||||
|
||||
assertThat(response.getRedirectedUrl()).isEqualTo("/skills/456");
|
||||
HttpSession session = request.getSession(false);
|
||||
assertThat(session.getAttribute("ssoReturnTo")).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void ssoCallback_invalidTicket_redirectsToErrorPage() throws Exception {
|
||||
properties.setEnabled(true);
|
||||
when(ssoClient.validateTicket("ST-invalid"))
|
||||
.thenThrow(new TicketValidationException("Invalid ticket"));
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
controller.ssoCallback("ST-invalid", request, response);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(302);
|
||||
assertThat(response.getRedirectedUrl()).isEqualTo("/login?error=sso_auth_failed");
|
||||
}
|
||||
|
||||
@Test
|
||||
void ssoCallback_genericException_redirectsToErrorPage() throws Exception {
|
||||
properties.setEnabled(true);
|
||||
when(ssoClient.validateTicket("ST-error"))
|
||||
.thenThrow(new RuntimeException("Unexpected error"));
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
controller.ssoCallback("ST-error", request, response);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(302);
|
||||
assertThat(response.getRedirectedUrl()).isEqualTo("/login?error=sso_error");
|
||||
}
|
||||
|
||||
@Test
|
||||
void ssoCallback_disabled_returns403() throws Exception {
|
||||
properties.setEnabled(false);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
controller.ssoCallback("ST-anything", request, response);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(403);
|
||||
}
|
||||
|
||||
@Test
|
||||
void ssoLogin_ssoUrlContainsClientUrl() throws Exception {
|
||||
properties.setEnabled(true);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
controller.ssoLogin(null, request, response);
|
||||
|
||||
String redirectUrl = response.getRedirectedUrl();
|
||||
assertThat(redirectUrl).contains("clientUrl=" + CLIENT_URL);
|
||||
assertThat(redirectUrl).startsWith("https://sso.example.com/login");
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ import java.time.Duration;
|
|||
import java.util.Map;
|
||||
|
||||
import com.iflytek.skillhub.auth.config.SsoProperties;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
|
@ -19,12 +19,12 @@ public class SsoClient {
|
|||
private final SsoProperties properties;
|
||||
private final RestTemplate restTemplate;
|
||||
|
||||
public SsoClient(SsoProperties properties, RestTemplateBuilder restTemplateBuilder) {
|
||||
public SsoClient(SsoProperties properties) {
|
||||
this.properties = properties;
|
||||
this.restTemplate = restTemplateBuilder
|
||||
.connectTimeout(Duration.ofSeconds(5))
|
||||
.readTimeout(Duration.ofSeconds(10))
|
||||
.build();
|
||||
var factory = new SimpleClientHttpRequestFactory();
|
||||
factory.setConnectTimeout((int) Duration.ofSeconds(5).toMillis());
|
||||
factory.setReadTimeout((int) Duration.ofSeconds(10).toMillis());
|
||||
this.restTemplate = new RestTemplate(factory);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,149 @@
|
|||
package com.iflytek.skillhub.auth.sso;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.iflytek.skillhub.auth.config.SsoProperties;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class SsoClientTest {
|
||||
|
||||
private static final String BASE_URL = "https://sso.example.com";
|
||||
private static final String VALIDATE_PATH = "/stvalidate";
|
||||
private static final String CLIENT_URL = "https://skillhub.example.com/api/v1/auth/sso/callback";
|
||||
private static final String CLIENT_TOKEN = "test-token-123";
|
||||
|
||||
private SsoProperties properties;
|
||||
|
||||
@Mock
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
private SsoClient client;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
properties = new SsoProperties();
|
||||
properties.setEnabled(true);
|
||||
properties.setBaseUrl(BASE_URL);
|
||||
properties.setValidatePath(VALIDATE_PATH);
|
||||
properties.setClientUrl(CLIENT_URL);
|
||||
properties.setClientToken(CLIENT_TOKEN);
|
||||
|
||||
client = new SsoClient(properties);
|
||||
ReflectionTestUtils.setField(client, "restTemplate", restTemplate);
|
||||
}
|
||||
|
||||
@Test
|
||||
void validateTicket_returnsSsoUserOnSuccess() {
|
||||
Map<String, Object> response = Map.of(
|
||||
"account", "zhangsan",
|
||||
"id", "EMP001",
|
||||
"name", "张三"
|
||||
);
|
||||
when(restTemplate.postForObject(anyString(), any(), eq(Map.class)))
|
||||
.thenReturn(response);
|
||||
|
||||
SsoUser user = client.validateTicket("ST-valid-ticket");
|
||||
|
||||
assertThat(user.account()).isEqualTo("zhangsan");
|
||||
assertThat(user.id()).isEqualTo("EMP001");
|
||||
assertThat(user.name()).isEqualTo("张三");
|
||||
}
|
||||
|
||||
@Test
|
||||
void validateTicket_returnsSsoUserWithEmptyName() {
|
||||
Map<String, Object> response = Map.of(
|
||||
"account", "lisi",
|
||||
"id", "EMP002",
|
||||
"name", ""
|
||||
);
|
||||
when(restTemplate.postForObject(anyString(), any(), eq(Map.class)))
|
||||
.thenReturn(response);
|
||||
|
||||
SsoUser user = client.validateTicket("ST-another-ticket");
|
||||
|
||||
assertThat(user.account()).isEqualTo("lisi");
|
||||
assertThat(user.id()).isEqualTo("EMP002");
|
||||
assertThat(user.name()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void validateTicket_throwsOnNullResponse() {
|
||||
when(restTemplate.postForObject(anyString(), any(), eq(Map.class)))
|
||||
.thenReturn(null);
|
||||
|
||||
assertThatThrownBy(() -> client.validateTicket("ST-null"))
|
||||
.isInstanceOf(TicketValidationException.class)
|
||||
.hasMessageContaining("Empty response");
|
||||
}
|
||||
|
||||
@Test
|
||||
void validateTicket_throwsOnEmptyResponse() {
|
||||
when(restTemplate.postForObject(anyString(), any(), eq(Map.class)))
|
||||
.thenReturn(Map.of());
|
||||
|
||||
assertThatThrownBy(() -> client.validateTicket("ST-empty"))
|
||||
.isInstanceOf(TicketValidationException.class)
|
||||
.hasMessageContaining("Empty response");
|
||||
}
|
||||
|
||||
@Test
|
||||
void validateTicket_throwsOnMissingRequiredFields() {
|
||||
Map<String, Object> response = Map.of(
|
||||
"name", "test"
|
||||
);
|
||||
when(restTemplate.postForObject(anyString(), any(), eq(Map.class)))
|
||||
.thenReturn(response);
|
||||
|
||||
assertThatThrownBy(() -> client.validateTicket("ST-partial"))
|
||||
.isInstanceOf(TicketValidationException.class)
|
||||
.hasMessageContaining("missing required fields");
|
||||
}
|
||||
|
||||
@Test
|
||||
void validateTicket_throwsOnMissingIdField() {
|
||||
Map<String, Object> response = Map.of(
|
||||
"account", "wangwu"
|
||||
);
|
||||
when(restTemplate.postForObject(anyString(), any(), eq(Map.class)))
|
||||
.thenReturn(response);
|
||||
|
||||
assertThatThrownBy(() -> client.validateTicket("ST-no-id"))
|
||||
.isInstanceOf(TicketValidationException.class)
|
||||
.hasMessageContaining("missing required fields");
|
||||
}
|
||||
|
||||
@Test
|
||||
void validateTicket_usesCustomResponseFields() {
|
||||
properties.getResponse().setAccountField("login");
|
||||
properties.getResponse().setIdField("employeeId");
|
||||
properties.getResponse().setNameField("fullName");
|
||||
|
||||
Map<String, Object> response = Map.of(
|
||||
"login", "zhaoliu",
|
||||
"employeeId", "EMP006",
|
||||
"fullName", "赵六"
|
||||
);
|
||||
when(restTemplate.postForObject(anyString(), any(), eq(Map.class)))
|
||||
.thenReturn(response);
|
||||
|
||||
SsoUser user = client.validateTicket("ST-custom");
|
||||
|
||||
assertThat(user.account()).isEqualTo("zhaoliu");
|
||||
assertThat(user.id()).isEqualTo("EMP006");
|
||||
assertThat(user.name()).isEqualTo("赵六");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,175 @@
|
|||
package com.iflytek.skillhub.auth.sso;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.iflytek.skillhub.auth.entity.IdentityBinding;
|
||||
import com.iflytek.skillhub.auth.entity.Role;
|
||||
import com.iflytek.skillhub.auth.entity.UserRoleBinding;
|
||||
import com.iflytek.skillhub.auth.rbac.PlatformPrincipal;
|
||||
import com.iflytek.skillhub.auth.repository.IdentityBindingRepository;
|
||||
import com.iflytek.skillhub.auth.repository.UserRoleBindingRepository;
|
||||
import com.iflytek.skillhub.domain.namespace.GlobalNamespaceMembershipService;
|
||||
import com.iflytek.skillhub.domain.user.UserAccount;
|
||||
import com.iflytek.skillhub.domain.user.UserAccountRepository;
|
||||
import com.iflytek.skillhub.domain.user.UserStatus;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class SsoIdentityServiceTest {
|
||||
|
||||
private static final String PROVIDER_CODE = "sso";
|
||||
private static final String SSO_ACCOUNT = "zhangsan";
|
||||
private static final String SSO_ID = "EMP001";
|
||||
private static final String SSO_NAME = "张三";
|
||||
|
||||
@Mock
|
||||
private IdentityBindingRepository bindingRepo;
|
||||
|
||||
@Mock
|
||||
private UserAccountRepository userRepo;
|
||||
|
||||
@Mock
|
||||
private UserRoleBindingRepository roleBindingRepo;
|
||||
|
||||
@Mock
|
||||
private GlobalNamespaceMembershipService globalNamespaceMembershipService;
|
||||
|
||||
private SsoIdentityService service;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
service = new SsoIdentityService(bindingRepo, userRepo, roleBindingRepo,
|
||||
globalNamespaceMembershipService);
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveOrCreate_existingBinding_updatesDisplayName() {
|
||||
SsoUser ssoUser = new SsoUser(SSO_ACCOUNT, SSO_ID, "张三(更新)");
|
||||
IdentityBinding binding = new IdentityBinding("usr_001", PROVIDER_CODE, SSO_ID, SSO_ACCOUNT);
|
||||
UserAccount existingUser = new UserAccount("usr_001", SSO_NAME, null, null);
|
||||
existingUser.setStatus(UserStatus.ACTIVE);
|
||||
|
||||
when(bindingRepo.findByProviderCodeAndSubject(PROVIDER_CODE, SSO_ID))
|
||||
.thenReturn(Optional.of(binding));
|
||||
when(userRepo.findById("usr_001")).thenReturn(Optional.of(existingUser));
|
||||
when(userRepo.save(any(UserAccount.class))).thenAnswer(invocation -> invocation.getArgument(0));
|
||||
when(roleBindingRepo.findByUserId("usr_001")).thenReturn(List.of());
|
||||
|
||||
PlatformPrincipal principal = service.resolveOrCreate(ssoUser);
|
||||
|
||||
assertThat(principal.displayName()).isEqualTo("张三(更新)");
|
||||
assertThat(principal.oauthProvider()).isEqualTo(PROVIDER_CODE);
|
||||
verify(userRepo).save(existingUser);
|
||||
verify(globalNamespaceMembershipService, never()).ensureMember(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveOrCreate_newSsoUser_createsUserAndBinding() {
|
||||
SsoUser ssoUser = new SsoUser(SSO_ACCOUNT, SSO_ID, SSO_NAME);
|
||||
|
||||
when(bindingRepo.findByProviderCodeAndSubject(PROVIDER_CODE, SSO_ID))
|
||||
.thenReturn(Optional.empty());
|
||||
when(userRepo.save(any(UserAccount.class))).thenAnswer(invocation -> invocation.getArgument(0));
|
||||
when(roleBindingRepo.findByUserId(any())).thenReturn(List.of());
|
||||
|
||||
PlatformPrincipal principal = service.resolveOrCreate(ssoUser);
|
||||
|
||||
ArgumentCaptor<UserAccount> userCaptor = ArgumentCaptor.forClass(UserAccount.class);
|
||||
verify(userRepo).save(userCaptor.capture());
|
||||
UserAccount createdUser = userCaptor.getValue();
|
||||
assertThat(createdUser.getId()).startsWith("usr_");
|
||||
assertThat(createdUser.getDisplayName()).isEqualTo(SSO_NAME);
|
||||
assertThat(createdUser.getStatus()).isEqualTo(UserStatus.ACTIVE);
|
||||
|
||||
ArgumentCaptor<IdentityBinding> bindingCaptor = ArgumentCaptor.forClass(IdentityBinding.class);
|
||||
verify(bindingRepo).save(bindingCaptor.capture());
|
||||
IdentityBinding createdBinding = bindingCaptor.getValue();
|
||||
assertThat(createdBinding.getProviderCode()).isEqualTo(PROVIDER_CODE);
|
||||
assertThat(createdBinding.getSubject()).isEqualTo(SSO_ID);
|
||||
assertThat(createdBinding.getLoginName()).isEqualTo(SSO_ACCOUNT);
|
||||
|
||||
verify(globalNamespaceMembershipService).ensureMember(createdUser.getId());
|
||||
assertThat(principal.displayName()).isEqualTo(SSO_NAME);
|
||||
assertThat(principal.oauthProvider()).isEqualTo(PROVIDER_CODE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveOrCreate_existingUserWithExplicitRoles() {
|
||||
SsoUser ssoUser = new SsoUser(SSO_ACCOUNT, SSO_ID, SSO_NAME);
|
||||
IdentityBinding binding = new IdentityBinding("usr_001", PROVIDER_CODE, SSO_ID, SSO_ACCOUNT);
|
||||
UserAccount existingUser = new UserAccount("usr_001", SSO_NAME, null, null);
|
||||
existingUser.setStatus(UserStatus.ACTIVE);
|
||||
|
||||
Role role = new Role();
|
||||
ReflectionTestUtils.setField(role, "code", "AUDITOR");
|
||||
|
||||
when(bindingRepo.findByProviderCodeAndSubject(PROVIDER_CODE, SSO_ID))
|
||||
.thenReturn(Optional.of(binding));
|
||||
when(userRepo.findById("usr_001")).thenReturn(Optional.of(existingUser));
|
||||
when(userRepo.save(any(UserAccount.class))).thenAnswer(invocation -> invocation.getArgument(0));
|
||||
when(roleBindingRepo.findByUserId("usr_001"))
|
||||
.thenReturn(List.of(new UserRoleBinding("usr_001", role)));
|
||||
|
||||
PlatformPrincipal principal = service.resolveOrCreate(ssoUser);
|
||||
|
||||
assertThat(principal.platformRoles()).contains("AUDITOR");
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveOrCreate_defaultsToUserRole() {
|
||||
SsoUser ssoUser = new SsoUser(SSO_ACCOUNT, SSO_ID, SSO_NAME);
|
||||
|
||||
when(bindingRepo.findByProviderCodeAndSubject(PROVIDER_CODE, SSO_ID))
|
||||
.thenReturn(Optional.empty());
|
||||
when(userRepo.save(any(UserAccount.class))).thenAnswer(invocation -> invocation.getArgument(0));
|
||||
when(roleBindingRepo.findByUserId(any())).thenReturn(List.of());
|
||||
|
||||
PlatformPrincipal principal = service.resolveOrCreate(ssoUser);
|
||||
|
||||
assertThat(principal.platformRoles()).contains("USER");
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveOrCreate_nonActiveUser_throwsException() {
|
||||
SsoUser ssoUser = new SsoUser(SSO_ACCOUNT, SSO_ID, SSO_NAME);
|
||||
IdentityBinding binding = new IdentityBinding("usr_001", PROVIDER_CODE, SSO_ID, SSO_ACCOUNT);
|
||||
UserAccount disabledUser = new UserAccount("usr_001", SSO_NAME, null, null);
|
||||
disabledUser.setStatus(UserStatus.DISABLED);
|
||||
|
||||
when(bindingRepo.findByProviderCodeAndSubject(PROVIDER_CODE, SSO_ID))
|
||||
.thenReturn(Optional.of(binding));
|
||||
when(userRepo.findById("usr_001")).thenReturn(Optional.of(disabledUser));
|
||||
when(userRepo.save(any(UserAccount.class))).thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
assertThatThrownBy(() -> service.resolveOrCreate(ssoUser))
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.hasMessageContaining("not active");
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveOrCreate_bindingWithoutUser_throwsException() {
|
||||
SsoUser ssoUser = new SsoUser(SSO_ACCOUNT, SSO_ID, SSO_NAME);
|
||||
IdentityBinding binding = new IdentityBinding("usr_ghost", PROVIDER_CODE, SSO_ID, SSO_ACCOUNT);
|
||||
|
||||
when(bindingRepo.findByProviderCodeAndSubject(PROVIDER_CODE, SSO_ID))
|
||||
.thenReturn(Optional.of(binding));
|
||||
when(userRepo.findById("usr_ghost")).thenReturn(Optional.empty());
|
||||
|
||||
assertThatThrownBy(() -> service.resolveOrCreate(ssoUser))
|
||||
.isInstanceOf(IllegalStateException.class)
|
||||
.hasMessageContaining("User not found for binding");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue