Skip to content

Commit 4494ce9

Browse files
authored
Merge pull request #14 from fireflyframework/fix/framework-hardening
fix: NoOp security adapters deny-by-default
2 parents d9c3bc3 + 1e67c51 commit 4494ce9

4 files changed

Lines changed: 34 additions & 23 deletions

File tree

src/main/java/org/fireflyframework/ecm/adapter/noop/NoOpGenericAdapter.java

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,14 @@
3636
* <ul>
3737
* <li>Methods returning {@link Mono}: Return empty Mono or error for modifications</li>
3838
* <li>Methods returning {@link Flux}: Return empty Flux</li>
39-
* <li>Methods returning {@link Boolean}: Return false for existence checks, true for permissions</li>
39+
* <li>Methods returning {@link Boolean}: Return false (deny by default) for ALL checks including permissions</li>
4040
* <li>Methods returning {@link String}: Return adapter name for getAdapterName(), empty for others</li>
4141
* <li>Other return types: Return null or appropriate defaults</li>
4242
* </ul>
4343
*
44+
* <p><strong>Security Note:</strong> All permission/access checks return DENY by default.
45+
* Configure a real adapter for production use.</p>
46+
*
4447
* @param <T> the port interface type
4548
* @author Firefly Software Solutions Inc.
4649
* @version 1.0
@@ -121,12 +124,14 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
121124
private Mono<?> handleMonoReturn(String methodName) {
122125
String lowerMethodName = methodName.toLowerCase();
123126

124-
// For boolean permission/access methods, return true (permissive default) - CHECK FIRST
127+
// SECURITY: Permission/access methods DENY by default when no adapter configured
125128
if (lowerMethodName.startsWith("can") ||
126129
lowerMethodName.contains("access") ||
127130
lowerMethodName.contains("permission") ||
128131
lowerMethodName.contains("allow")) {
129-
return Mono.just(true);
132+
log.warn("SECURITY: Permission check '{}' denied by NoOp {} adapter. " +
133+
"Configure a real adapter for production use.", methodName, getAdapterType());
134+
return Mono.just(false);
130135
}
131136

132137
// For boolean existence/status checks, return false
@@ -170,23 +175,17 @@ private Mono<?> handleMonoReturn(String methodName) {
170175
private boolean handleBooleanReturn(String methodName) {
171176
String lowerMethodName = methodName.toLowerCase();
172177

173-
// For permission/access methods, return true (permissive default)
178+
// SECURITY: Permission/access methods DENY by default
174179
if (lowerMethodName.startsWith("can") ||
175180
lowerMethodName.contains("access") ||
176181
lowerMethodName.contains("permission") ||
177182
lowerMethodName.contains("allow")) {
178-
return true;
179-
}
180-
181-
// For existence/status checks, return false
182-
if (lowerMethodName.startsWith("exists") ||
183-
lowerMethodName.startsWith("has") ||
184-
lowerMethodName.startsWith("is") ||
185-
lowerMethodName.startsWith("contains")) {
183+
log.warn("SECURITY: Permission check '{}' denied by NoOp {} adapter. " +
184+
"Configure a real adapter for production use.", methodName, getAdapterType());
186185
return false;
187186
}
188187

189-
// Default to false for other boolean methods
188+
// For all other boolean methods, return false
190189
return false;
191190
}
192191
}

src/main/java/org/fireflyframework/ecm/config/EcmAutoConfiguration.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,13 @@ public FolderHierarchyPort folderHierarchyPort(EcmPortProvider portProvider, NoO
338338
@ConditionalOnProperty(prefix = "firefly.ecm.features", name = "permissions", havingValue = "true", matchIfMissing = true)
339339
public PermissionPort permissionPort(EcmPortProvider portProvider, NoOpAdapterFactory noOpAdapterFactory) {
340340
return portProvider.getPermissionPort()
341-
.orElseGet(noOpAdapterFactory::createPermissionPort);
341+
.orElseGet(() -> {
342+
log.warn("=========================================================================");
343+
log.warn("ECM PermissionPort is using NoOp adapter — ALL permission checks will");
344+
log.warn("DENY by default. Configure a real adapter for production use.");
345+
log.warn("=========================================================================");
346+
return noOpAdapterFactory.createPermissionPort();
347+
});
342348
}
343349

344350
/**
@@ -361,7 +367,13 @@ public PermissionPort permissionPort(EcmPortProvider portProvider, NoOpAdapterFa
361367
@ConditionalOnProperty(prefix = "firefly.ecm.features", name = "security", havingValue = "true", matchIfMissing = true)
362368
public DocumentSecurityPort documentSecurityPort(EcmPortProvider portProvider, NoOpAdapterFactory noOpAdapterFactory) {
363369
return portProvider.getDocumentSecurityPort()
364-
.orElseGet(noOpAdapterFactory::createDocumentSecurityPort);
370+
.orElseGet(() -> {
371+
log.warn("=========================================================================");
372+
log.warn("ECM DocumentSecurityPort is using NoOp adapter — ALL security operations");
373+
log.warn("will be denied/no-op. Configure a real adapter for production use.");
374+
log.warn("=========================================================================");
375+
return noOpAdapterFactory.createDocumentSecurityPort();
376+
});
365377
}
366378

367379
/**

src/test/java/org/fireflyframework/ecm/adapter/noop/NoOpAdapterLoggingTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,9 @@ void shouldLogWarningsForSecurityAdapterMethods() {
145145
UUID testDocumentId = UUID.randomUUID();
146146
UUID testUserId = UUID.randomUUID();
147147

148-
// Call a permission check method (should return true with warning)
148+
// Call a permission check method (should return false with warning — deny by default)
149149
StepVerifier.create(adapter.canAccessDocument(testDocumentId, testUserId, "READ"))
150-
.expectNext(true)
150+
.expectNext(false)
151151
.verifyComplete();
152152

153153
// Call an encryption method and expect error

src/test/java/org/fireflyframework/ecm/config/EcmGracefulDegradationTest.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,24 +120,24 @@ void shouldReturnEmptyResultsForQueryOperations() {
120120
}
121121

122122
/**
123-
* Verifies that no-op adapters return permissive defaults for security operations.
123+
* Verifies that no-op adapters return deny by default for security operations.
124124
*/
125125
@Test
126-
void shouldReturnPermissiveDefaultsForSecurityOperations() {
126+
void shouldReturnDenyByDefaultForSecurityOperations() {
127127
UUID testDocumentId = UUID.randomUUID();
128128
UUID testUserId = UUID.randomUUID();
129129

130-
// Access checks should return true (permissive default)
130+
// Access checks should return false (deny by default)
131131
StepVerifier.create(documentSecurityPort.canAccessDocument(testDocumentId, testUserId, "READ"))
132-
.expectNext(true)
132+
.expectNext(false)
133133
.verifyComplete();
134134

135135
StepVerifier.create(documentSecurityPort.canDeleteDocument(testDocumentId, testUserId))
136-
.expectNext(true)
136+
.expectNext(false)
137137
.verifyComplete();
138138

139139
StepVerifier.create(documentSecurityPort.canModifyDocument(testDocumentId, testUserId))
140-
.expectNext(true)
140+
.expectNext(false)
141141
.verifyComplete();
142142
}
143143

0 commit comments

Comments
 (0)