1package dev.rafex.ether.http.jetty12;
29import java.time.Instant;
30import java.util.ArrayList;
32import java.util.Objects;
34import org.eclipse.jetty.http.pathmap.PathSpec;
35import org.eclipse.jetty.server.Handler;
36import org.eclipse.jetty.server.Request;
37import org.eclipse.jetty.server.Response;
38import org.eclipse.jetty.util.Callback;
40import dev.rafex.ether.http.core.AuthPolicy;
41import dev.rafex.ether.http.jetty12.response.JettyApiErrorResponses;
42import dev.rafex.ether.http.jetty12.security.TokenVerificationResult;
43import dev.rafex.ether.http.jetty12.security.TokenVerifier;
44import dev.rafex.ether.json.JsonCodec;
50 record Rule(String method, PathSpec pathSpec) {
55 private final List<Rule> publicRules =
new ArrayList<>();
56 private final List<PathSpec> protectedPrefixes =
new ArrayList<>();
60 this.tokenVerifier = Objects.requireNonNull(tokenVerifier);
65 publicRules.add(
new Rule(method.toUpperCase(), PathSpec.from(pathSpec)));
70 protectedPrefixes.add(PathSpec.from(pathSpec));
78 if (policy.type() == AuthPolicy.Type.PUBLIC_PATH) {
79 return publicPath(policy.method(), policy.pathSpec());
85 if (policies ==
null) {
88 for (
final var policy : policies) {
95 public boolean handle(
final Request request,
final Response
response,
final Callback callback)
throws Exception {
96 final var method = request.getMethod().toUpperCase();
97 final var path = request.getHttpURI() !=
null ? request.getHttpURI().getPath() :
null;
99 errorResponses.badRequest(
response, callback,
"missing_path");
103 if (isPublic(method, path) || !isProtected(path)) {
104 return super.handle(request,
response, callback);
107 final var authz = request.getHeaders().get(
"authorization");
108 if (authz ==
null || !authz.startsWith(
"Bearer ")) {
109 errorResponses.unauthorized(
response, callback,
"missing_bearer_token");
113 final var token = authz.substring(
"Bearer ".length()).trim();
114 final var verification = tokenVerifier.verify(token, Instant.now().getEpochSecond());
115 if (!verification.ok()) {
116 final var code = verification.code() ==
null || verification.code().isBlank() ?
"invalid_token"
117 : verification.code();
118 errorResponses.unauthorized(
response, callback, code);
123 return super.handle(request,
response, callback);
126 private boolean isPublic(
final String method,
final String path) {
127 for (
final var rule : publicRules) {
128 if (rule.method().equals(method) && rule.pathSpec().matches(path)) {
135 private boolean isProtected(
final String path) {
136 for (
final var p : protectedPrefixes) {
137 if (p.matches(path)) {
boolean handle(final Request request, final Response response, final Callback callback)
JettyAuthHandler authPolicy(final AuthPolicy policy)
static final String REQ_ATTR_AUTH
JettyAuthHandler authPolicies(final List< AuthPolicy > policies)
JettyAuthHandler publicPath(final String method, final String pathSpec)
JettyAuthHandler(final Handler delegate, final TokenVerifier tokenVerifier, final JsonCodec jsonCodec)
JettyAuthHandler protectedPrefix(final String pathSpec)