Skip to content

Commit 5ba86c4

Browse files
committed
feat: Add sample RegistrationGuard for domain-restricted registration
Add a profile-gated DomainRegistrationGuard that restricts form/passwordless registration to @example.com emails while allowing all OAuth2/OIDC registrations. Activated only with the `registration-guard` Spring profile. Also bump library dependency to 4.2.3-SNAPSHOT and fix UserServiceTest for the new SessionInvalidationService constructor parameter. Closes #61 Ref: devondragon/SpringUserFramework#271
1 parent 6312089 commit 5ba86c4

3 files changed

Lines changed: 66 additions & 2 deletions

File tree

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ repositories {
3939

4040
dependencies {
4141
// DigitalSanctuary Spring User Framework
42-
implementation 'com.digitalsanctuary:ds-spring-user-framework:4.2.1'
42+
implementation 'com.digitalsanctuary:ds-spring-user-framework:4.2.3-SNAPSHOT'
4343

4444
// WebAuthn support (Passkey authentication)
4545
implementation 'org.springframework.security:spring-security-webauthn'
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package com.digitalsanctuary.spring.demo.registration;
2+
3+
import org.springframework.context.annotation.Profile;
4+
import org.springframework.stereotype.Component;
5+
6+
import com.digitalsanctuary.spring.user.registration.RegistrationContext;
7+
import com.digitalsanctuary.spring.user.registration.RegistrationDecision;
8+
import com.digitalsanctuary.spring.user.registration.RegistrationGuard;
9+
import com.digitalsanctuary.spring.user.registration.RegistrationSource;
10+
11+
import lombok.extern.slf4j.Slf4j;
12+
13+
/**
14+
* Sample {@link RegistrationGuard} that restricts form and passwordless registration to
15+
* {@code @example.com} email addresses while allowing all OAuth2/OIDC registrations.
16+
*
17+
* <p>This guard is only active when the {@code registration-guard} Spring profile is enabled.
18+
* To try it out, add {@code registration-guard} to your active profiles:</p>
19+
*
20+
* <pre>
21+
* ./gradlew bootRun --args='--spring.profiles.active=local,registration-guard'
22+
* </pre>
23+
*
24+
* <p>See the
25+
* <a href="https://github.com/devondragon/SpringUserFramework/blob/main/REGISTRATION-GUARD.md">
26+
* Registration Guard documentation</a> for the full SPI reference.</p>
27+
*
28+
* @see RegistrationGuard
29+
* @see RegistrationContext
30+
* @see RegistrationDecision
31+
*/
32+
@Slf4j
33+
@Component
34+
@Profile("registration-guard")
35+
public class DomainRegistrationGuard implements RegistrationGuard {
36+
37+
private static final String ALLOWED_DOMAIN = "@example.com";
38+
39+
@Override
40+
public RegistrationDecision evaluate(RegistrationContext context) {
41+
log.debug("Evaluating registration for email: {}, source: {}, provider: {}",
42+
context.email(), context.source(), context.providerName());
43+
44+
// Allow all OAuth2/OIDC registrations regardless of email domain
45+
if (context.source() == RegistrationSource.OAUTH2
46+
|| context.source() == RegistrationSource.OIDC) {
47+
log.debug("Allowing {} registration for: {}", context.source(), context.email());
48+
return RegistrationDecision.allow();
49+
}
50+
51+
// For form/passwordless, restrict to the allowed domain
52+
if (context.email() != null && context.email().toLowerCase().endsWith(ALLOWED_DOMAIN)) {
53+
log.debug("Allowing registration for approved domain: {}", context.email());
54+
return RegistrationDecision.allow();
55+
}
56+
57+
log.info("Denied registration for: {} (domain not allowed)", context.email());
58+
return RegistrationDecision.deny(
59+
"Registration is restricted to " + ALLOWED_DOMAIN + " email addresses.");
60+
}
61+
}

src/test/java/com/digitalsanctuary/spring/user/service/UserServiceTest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ public class UserServiceTest {
5555
@Mock
5656
private PasswordHistoryRepository passwordHistoryRepository;
5757

58+
@Mock
59+
private SessionInvalidationService sessionInvalidationService;
60+
5861
private UserService userService;
5962
private User testUser;
6063
private UserDto testUserDto;
@@ -78,7 +81,7 @@ void setUp() {
7881

7982
userService = new UserService(userRepository, tokenRepository, passwordTokenRepository, passwordEncoder,
8083
roleRepository, sessionRegistry, userEmailService, userVerificationService, authorityService,
81-
dsUserDetailsService, eventPublisher, passwordHistoryRepository);
84+
dsUserDetailsService, eventPublisher, passwordHistoryRepository, sessionInvalidationService);
8285
}
8386

8487
@Test

0 commit comments

Comments
 (0)