mirror of
https://github.com/iflytek/skillhub.git
synced 2026-08-28 11:25:00 +00:00
test(auth): cover identity link terminal states
Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
This commit is contained in:
parent
9557478dd8
commit
4874ce0dec
1 changed files with 152 additions and 2 deletions
|
|
@ -3,6 +3,7 @@ package com.iflytek.skillhub.auth.identity;
|
|||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
import com.iflytek.skillhub.auth.entity.IdentityLinkRequestStatus;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.Statement;
|
||||
|
|
@ -15,9 +16,13 @@ import java.util.UUID;
|
|||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
|
@ -55,6 +60,9 @@ class IdentityLinkPostgresIntegrationTest {
|
|||
@Autowired
|
||||
private ExternalIdentityLinkService externalLinkService;
|
||||
|
||||
@Autowired
|
||||
private ExternalIdentityLoginService externalLoginService;
|
||||
|
||||
@Autowired
|
||||
private TrustedProviderRouteResolver routeResolver;
|
||||
|
||||
|
|
@ -209,6 +217,91 @@ class IdentityLinkPostgresIntegrationTest {
|
|||
intentId.toString())).isEqualTo(1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void cancelledIntentCannotBeReadReauthenticatedOrConsumed() {
|
||||
String userId = "identity-link-cancelled";
|
||||
seedLocalUser(userId, "identity_link_cancelled");
|
||||
IdentityLinkActor actor = actor(
|
||||
userId,
|
||||
"nonce-link-cancelled");
|
||||
UUID intentId = UUID.randomUUID();
|
||||
intentService.createLinkIntent(
|
||||
actor,
|
||||
intentId,
|
||||
"github");
|
||||
|
||||
IdentityLinkIntent cancelled = intentService.cancel(
|
||||
actor,
|
||||
intentId);
|
||||
|
||||
assertThat(cancelled.status())
|
||||
.isEqualTo(IdentityLinkRequestStatus.CANCELLED);
|
||||
assertAlreadyConsumed(() ->
|
||||
intentService.getIntent(actor, intentId));
|
||||
assertAlreadyConsumed(() ->
|
||||
intentService.reauthenticateLocal(
|
||||
actor,
|
||||
intentId,
|
||||
PASSWORD));
|
||||
assertAlreadyConsumed(() ->
|
||||
externalLinkService.link(
|
||||
actor,
|
||||
intentId,
|
||||
githubProvider(),
|
||||
githubResult("6551201")));
|
||||
assertThat(count(
|
||||
"""
|
||||
SELECT COUNT(*)
|
||||
FROM identity_link_request
|
||||
WHERE id = ?
|
||||
AND status = 'CANCELLED'
|
||||
""",
|
||||
intentId)).isEqualTo(1L);
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "{0}")
|
||||
@MethodSource("blockedAccountStates")
|
||||
void blockedAccountsCannotCreateLinkOrUnlinkIntents(
|
||||
String caseName,
|
||||
String accountStatus,
|
||||
boolean systemAccount) {
|
||||
String suffix = caseName.toLowerCase().replace('_', '-');
|
||||
String userId = "identity-link-blocked-" + suffix;
|
||||
String username = "identity_link_blocked_"
|
||||
+ caseName.toLowerCase();
|
||||
seedLocalUser(
|
||||
userId,
|
||||
username,
|
||||
accountStatus,
|
||||
systemAccount);
|
||||
long bindingId = insertLegacyBinding(
|
||||
userId,
|
||||
"blocked-" + suffix,
|
||||
"655-blocked-" + suffix,
|
||||
username);
|
||||
IdentityLinkActor actor = actor(
|
||||
userId,
|
||||
"nonce-blocked-" + suffix);
|
||||
|
||||
assertAccountNotEligible(() ->
|
||||
intentService.createLinkIntent(
|
||||
actor,
|
||||
UUID.randomUUID(),
|
||||
"github"));
|
||||
assertAccountNotEligible(() ->
|
||||
intentService.createUnlinkIntent(
|
||||
actor,
|
||||
UUID.randomUUID(),
|
||||
bindingId));
|
||||
assertThat(count(
|
||||
"""
|
||||
SELECT COUNT(*)
|
||||
FROM identity_link_request
|
||||
WHERE primary_user_id = ?
|
||||
""",
|
||||
userId)).isZero();
|
||||
}
|
||||
|
||||
@Test
|
||||
void concurrentConsumptionOfSameIntentCompletesExactlyOnce()
|
||||
throws Exception {
|
||||
|
|
@ -532,6 +625,19 @@ class IdentityLinkPostgresIntegrationTest {
|
|||
PASSWORD);
|
||||
intentService.completeUnlink(actor, unlinkIntent);
|
||||
|
||||
assertThatThrownBy(() ->
|
||||
externalLoginService.authenticate(
|
||||
githubProvider(),
|
||||
githubResult(subject),
|
||||
IdentityLoginContext.empty()))
|
||||
.isInstanceOfSatisfying(
|
||||
IdentityCoreException.class,
|
||||
exception -> assertThat(
|
||||
exception.getReasonCode())
|
||||
.isEqualTo(
|
||||
IdentityFailureCode
|
||||
.ACCESS_DENIED));
|
||||
|
||||
UUID secondLinkIntent = readyLinkIntent(actor, PASSWORD);
|
||||
IdentityLinkOutcome.Linked secondLink =
|
||||
(IdentityLinkOutcome.Linked)
|
||||
|
|
@ -678,6 +784,28 @@ class IdentityLinkPostgresIntegrationTest {
|
|||
}
|
||||
}
|
||||
|
||||
private void assertAlreadyConsumed(Runnable operation) {
|
||||
assertThatThrownBy(operation::run)
|
||||
.isInstanceOfSatisfying(
|
||||
IdentityLinkException.class,
|
||||
exception -> assertThat(
|
||||
exception.getReasonCode())
|
||||
.isEqualTo(
|
||||
IdentityLinkFailureCode
|
||||
.ALREADY_CONSUMED));
|
||||
}
|
||||
|
||||
private void assertAccountNotEligible(Runnable operation) {
|
||||
assertThatThrownBy(operation::run)
|
||||
.isInstanceOfSatisfying(
|
||||
IdentityLinkException.class,
|
||||
exception -> assertThat(
|
||||
exception.getReasonCode())
|
||||
.isEqualTo(
|
||||
IdentityLinkFailureCode
|
||||
.ACCOUNT_NOT_ELIGIBLE));
|
||||
}
|
||||
|
||||
private IdentityLinkActor actor(
|
||||
String userId,
|
||||
String nonce) {
|
||||
|
|
@ -691,6 +819,18 @@ class IdentityLinkPostgresIntegrationTest {
|
|||
private void seedLocalUser(
|
||||
String userId,
|
||||
String username) {
|
||||
seedLocalUser(
|
||||
userId,
|
||||
username,
|
||||
"ACTIVE",
|
||||
false);
|
||||
}
|
||||
|
||||
private void seedLocalUser(
|
||||
String userId,
|
||||
String username,
|
||||
String accountStatus,
|
||||
boolean systemAccount) {
|
||||
jdbcTemplate.update(
|
||||
"""
|
||||
INSERT INTO user_account (
|
||||
|
|
@ -701,15 +841,25 @@ class IdentityLinkPostgresIntegrationTest {
|
|||
system_account,
|
||||
created_at,
|
||||
updated_at
|
||||
) VALUES (?, ?, ?, 'ACTIVE', FALSE,
|
||||
) VALUES (?, ?, ?, ?, ?,
|
||||
CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
|
||||
""",
|
||||
userId,
|
||||
username,
|
||||
username + "@example.com");
|
||||
username + "@example.com",
|
||||
accountStatus,
|
||||
systemAccount);
|
||||
insertLocalCredential(userId, username);
|
||||
}
|
||||
|
||||
private static Stream<Arguments> blockedAccountStates() {
|
||||
return Stream.of(
|
||||
Arguments.of("PENDING", "PENDING", false),
|
||||
Arguments.of("DISABLED", "DISABLED", false),
|
||||
Arguments.of("MERGED", "MERGED", false),
|
||||
Arguments.of("SYSTEM", "ACTIVE", true));
|
||||
}
|
||||
|
||||
private void insertLocalCredential(
|
||||
String userId,
|
||||
String username) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue