adding unactivated (invited/pending activation) users to grandfathering

This commit is contained in:
Dario Ghunney Ware
2025-12-02 11:02:01 +00:00
parent 368077ee10
commit bfbd85b225
4 changed files with 72 additions and 0 deletions
@@ -56,6 +56,19 @@ public interface UserRepository extends JpaRepository<User, Long> {
+ "OR LOWER(u.authenticationType) IN ('sso', 'oauth2', 'saml2')")
List<User> findAllSsoUsers();
/**
* Finds SSO users who have never created a session (pending activation) and are not yet
* grandfathered.
*/
@Query(
"SELECT u FROM User u "
+ "LEFT JOIN SessionEntity s ON u.username = s.principalName "
+ "WHERE (u.ssoProvider IS NOT NULL "
+ "OR LOWER(u.authenticationType) IN ('sso', 'oauth2', 'saml2')) "
+ "AND (u.oauthGrandfathered IS NULL OR u.oauthGrandfathered = false) "
+ "AND s.sessionId IS NULL")
List<User> findPendingSsoUsersWithoutSession();
/**
* Counts all SSO users - those with sso_provider set OR authenticationType is sso/oauth2/saml2.
*/
@@ -776,6 +776,32 @@ public class UserService implements UserServiceInterface {
userRepository.saveAll(ssoUsers);
}
return updated;
}
/**
* Grandfathers SSO users who have never created a session (invited/pending accounts). These
* users would otherwise be blocked when SSO requires a paid license despite existing before the
* policy change.
*
* @return Number of pending users updated
*/
@Transactional
public int grandfatherPendingSsoUsersWithoutSession() {
List<User> pendingUsers = userRepository.findPendingSsoUsersWithoutSession();
int updated = 0;
for (User user : pendingUsers) {
if (!user.isOauthGrandfathered()) {
user.setOauthGrandfathered(true);
updated++;
}
}
if (updated > 0) {
userRepository.saveAll(pendingUsers);
}
return updated;
}
}
@@ -198,6 +198,16 @@ public class UserLicenseSettingsService {
"OAuth grandfathering already completed: {} users grandfathered",
grandfatheredCount);
}
int pendingUpdated = userService.grandfatherPendingSsoUsersWithoutSession();
if (pendingUpdated > 0) {
log.warn(
"OAuth GRANDFATHERING: Marked {} pending SSO users (no prior sessions) as"
+ " grandfathered.",
pendingUpdated);
} else {
log.debug("No pending SSO users required grandfathering");
}
}
}
@@ -232,4 +232,27 @@ class UserLicenseSettingsServiceTest {
verify(userService, never()).grandfatherAllOAuthUsers();
}
@Test
void grandfatherExistingOAuthUsers_handlesPendingUsersWithoutSessions() {
when(userService.countOAuthUsers()).thenReturn(5L);
when(userService.countGrandfatheredOAuthUsers()).thenReturn(5L);
when(userService.grandfatherPendingSsoUsersWithoutSession()).thenReturn(3);
service.grandfatherExistingOAuthUsers();
verify(userService, never()).grandfatherAllOAuthUsers();
verify(userService, times(1)).grandfatherPendingSsoUsersWithoutSession();
}
@Test
void grandfatherExistingOAuthUsers_checksPendingUsersEvenWhenNoneExist() {
when(userService.countOAuthUsers()).thenReturn(0L);
when(userService.countGrandfatheredOAuthUsers()).thenReturn(0L);
when(userService.grandfatherPendingSsoUsersWithoutSession()).thenReturn(0);
service.grandfatherExistingOAuthUsers();
verify(userService, times(1)).grandfatherPendingSsoUsersWithoutSession();
}
}