I am trying to implement a security rule in Micronaut 4.5.0 like so:
package test;
import static io.micronaut.security.utils.LoggingUtils.debug;
import io.micronaut.context.annotation.Requires;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.security.authentication.Authentication;
import io.micronaut.security.rules.IpPatternsRule;
import io.micronaut.security.rules.SecurityRule;
import io.micronaut.security.rules.SecurityRuleResult;
import jakarta.inject.Singleton;
import java.io.IOException;
import java.net.http.HttpRequest;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.util.Objects;
import org.bouncycastle.crypto.util.PublicKeyFactory;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;
@Requires(classes = HttpRequest.class)
@Singleton
public class SignatureHeaderSecurityRule implements SecurityRule<HttpRequest> {
private final int ORDER = IpPatternsRule.ORDER - 100;
private final PublicKey incomingPublicKey;
private static final Logger LOG = LoggerFactory.getLogger(SignatureHeaderSecurityRule.class);
public SignatureHeaderSecurityRule(
Configuration configuration
) throws IOException {
incomingPublicKey = (PublicKey) PublicKeyFactory.createKey(
Objects.requireNonNull(SignatureHeaderSecurityRule.class.getResourceAsStream(
configuration.getIncomingPublicKey())));
}
@Override
public Publisher<SecurityRuleResult> check(
@Nullable HttpRequest request,
@Nullable Authentication authentication
) {
try {
Signature signer = Signature.getInstance(
"SHA256withRSA",
BouncyCastleProvider.PROVIDER_NAME);
signer.initVerify(incomingPublicKey);
String signatureHeader = request.headers().firstValue("Signature").orElse("");
boolean verification = signer.verify(signatureHeader.getBytes(StandardCharsets.UTF_8));
if (verification) {
return Mono.just(SecurityRuleResult.ALLOWED);
} else {
return Mono.just(SecurityRuleResult.REJECTED);
}
} catch (SignatureException e) {
debug(LOG, e.getMessage());
return Mono.just(SecurityRuleResult.REJECTED);
} catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidKeyException e) {
debug(LOG, e.getMessage());
return Mono.just(SecurityRuleResult.UNKNOWN);
}
}
@Override
public int getOrder() {
return ORDER;
}
}
I have configured my URI map like so:
micronaut.security.enabled=true
micronaut.security.authentication=bearer
micronaut.security.intercept-url-map[0].pattern=/notify
micronaut.security.intercept-url-map[0].http-method=POST
micronaut.security.intercept-url-map[0].access[0]=isAnonymous()
I have tried to step-debug into the rule and/or add logging. However, my custom security rule is never called. In my understanding this is all that is necessary to kick off a custom security rule in Micronaut.
How exactly do I need to configure the rule to be executed?