Skip to content

Commit 5b35d8f

Browse files
committed
feat: Add securityValidator and useExternalAuthentication builder methods
1 parent e11ce37 commit 5b35d8f

2 files changed

Lines changed: 59 additions & 0 deletions

File tree

src/main/java/com/retailsvc/http/OpenApiServer.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ public static final class Builder {
139139
private int port = DEFAULT_PORT;
140140
private int shutdownTimeoutSeconds = 0;
141141
private final LinkedHashMap<String, HttpHandler> extras = new LinkedHashMap<>();
142+
private final Map<String, SchemeValidator> securityValidators = new LinkedHashMap<>();
143+
private boolean externalAuth = false;
142144

143145
private Builder() {}
144146

@@ -182,6 +184,30 @@ public Builder interceptor(RequestInterceptor interceptor) {
182184
return this;
183185
}
184186

187+
/**
188+
* Registers a {@link SchemeValidator} for the OpenAPI security scheme named {@code schemeName}.
189+
* The library extracts a {@link Credential} per request and hands it to this callback; return a
190+
* non-empty {@link Optional} carrying the principal on success, or {@link Optional#empty()} to
191+
* deny. Library renders 401/403 on denial.
192+
*/
193+
public Builder securityValidator(String schemeName, SchemeValidator validator) {
194+
requireNonNull(schemeName, "schemeName must not be null");
195+
requireNonNull(validator, "validator must not be null");
196+
securityValidators.put(schemeName, validator);
197+
return this;
198+
}
199+
200+
/**
201+
* Opts out of in-process security enforcement. Use when an external sidecar (OPA/Envoy etc.)
202+
* authenticates requests upstream. The library still parses {@code securitySchemes} into the
203+
* {@link Spec}, but {@code SecurityFilter} short-circuits and the boot-time
204+
* validator-registration check is skipped.
205+
*/
206+
public Builder useExternalAuthentication() {
207+
this.externalAuth = true;
208+
return this;
209+
}
210+
185211
public Builder exceptionHandler(ExceptionHandler exceptionHandler) {
186212
this.exceptionHandler = exceptionHandler;
187213
return this;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.retailsvc.http;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
5+
6+
import java.util.Optional;
7+
import org.junit.jupiter.api.Test;
8+
9+
class SecurityBuilderTest {
10+
11+
@Test
12+
void securityValidatorRequiresNonNullName() {
13+
var builder = OpenApiServer.builder();
14+
assertThatThrownBy(() -> builder.securityValidator(null, (r, c) -> Optional.empty()))
15+
.isInstanceOf(NullPointerException.class)
16+
.hasMessageContaining("schemeName");
17+
}
18+
19+
@Test
20+
void securityValidatorRequiresNonNullValidator() {
21+
var builder = OpenApiServer.builder();
22+
assertThatThrownBy(() -> builder.securityValidator("x", null))
23+
.isInstanceOf(NullPointerException.class)
24+
.hasMessageContaining("validator");
25+
}
26+
27+
@Test
28+
void useExternalAuthenticationIsFluent() {
29+
var builder = OpenApiServer.builder();
30+
var returned = builder.useExternalAuthentication();
31+
assertThat(returned).isSameAs(builder);
32+
}
33+
}

0 commit comments

Comments
 (0)