Skip to content

Commit

Permalink
Fix issues with hot reload and security annotations, and redirect loops
Browse files Browse the repository at this point in the history
Make sure we declare some endpoints as FWK classes so that changing
their number of interceptors via configuration does not cause errors on
hot reload.
Also avoid infinite redirect loop when login page is itself protected.

Fixes #160
  • Loading branch information
FroMage committed Oct 20, 2023
1 parent fb65c00 commit b5e39b9
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Stream;

import jakarta.enterprise.context.RequestScoped;
Expand Down Expand Up @@ -103,6 +104,7 @@
import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.builditem.AdditionalIndexedClassesBuildItem;
import io.quarkus.deployment.builditem.ApplicationArchivesBuildItem;
import io.quarkus.deployment.builditem.ApplicationClassPredicateBuildItem;
import io.quarkus.deployment.builditem.ApplicationIndexBuildItem;
import io.quarkus.deployment.builditem.BytecodeTransformerBuildItem;
import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
Expand Down Expand Up @@ -153,6 +155,8 @@ public class RenardeProcessor {
public static final DotName DOTNAME_SECURITY = DotName.createSimple("io.quarkiverse.renarde.security.RenardeSecurity");
public static final DotName DOTNAME_RENARDE_FORM_LOGIN_CONTROLLER = DotName
.createSimple("io.quarkiverse.renarde.security.impl.RenardeFormLoginController");
public static final DotName DOTNAME_RENARDE_SECURITY_CONTROLLER = DotName
.createSimple("io.quarkiverse.renarde.security.impl.RenardeSecurityController");

public static final DotName DOTNAME_HX_CONTROLLER = DotName.createSimple(HxController.class.getName());
public static final DotName DOTNAME_LOGIN_PAGE = DotName.createSimple("io.quarkiverse.renarde.security.LoginPage");
Expand Down Expand Up @@ -317,7 +321,8 @@ void setupJWT(LaunchModeBuildItem launchMode, Capabilities capabilities,
@BuildStep
void produceBeans(BuildProducer<AdditionalBeanBuildItem> additionalBeanBuildItems,
BuildProducer<ParamConverterBuildItem> paramConverterBuildItems,
BuildProducer<AdditionalIndexedClassesBuildItem> additionalIndexedClassesBuildItems) {
BuildProducer<AdditionalIndexedClassesBuildItem> additionalIndexedClassesBuildItems,
BuildProducer<ApplicationClassPredicateBuildItem> applicationClassPredicateBuildItems) {
additionalBeanBuildItems.produce(AdditionalBeanBuildItem.unremovableOf(Globals.class));
additionalBeanBuildItems.produce(AdditionalBeanBuildItem.unremovableOf(Filters.class));
additionalBeanBuildItems.produce(AdditionalBeanBuildItem.unremovableOf(QuteResolvers.class));
Expand All @@ -338,6 +343,19 @@ void produceBeans(BuildProducer<AdditionalBeanBuildItem> additionalBeanBuildItem
new AdditionalIndexedClassesBuildItem(Filters.class.getName(), RedirectExceptionMapper.class.getName(),
Controller.class.getName(), HxController.class.getName()));

/*
* We don't have these beans, but they are endpoints, and they can't be declared FWK classes, otherwise
* config changes will not reload them. And config changes may affect the number of interceptors declared
* on beans, thus causing NoSuchMethodError because we generate bean proxy/client methods that take one
* parameter per interceptor.
*/
applicationClassPredicateBuildItems.produce(new ApplicationClassPredicateBuildItem(new Predicate<String>() {
@Override
public boolean test(String t) {
return DOTNAME_RENARDE_SECURITY_CONTROLLER.toString('.').equals(t)
|| DOTNAME_RENARDE_FORM_LOGIN_CONTROLLER.toString('.').equals(t);
}
}));
}

@BuildStep
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

import org.jboss.logging.Logger;

import io.quarkiverse.renarde.impl.RenardeConfig;
import io.quarkus.smallrye.jwt.runtime.auth.JWTAuthMechanism;
import io.quarkus.smallrye.jwt.runtime.auth.SmallRyeJwtConfig;
Expand All @@ -22,6 +24,8 @@
@ApplicationScoped
public class RenardeJWTAuthMechanism extends JWTAuthMechanism {

private static final Logger log = Logger.getLogger(RenardeJWTAuthMechanism.class);

@Inject
RenardeConfig config;

Expand Down Expand Up @@ -55,9 +59,16 @@ static Uni<ChallengeData> getRedirect(final RoutingContext exchange, final Strin
@Override
public Uni<ChallengeData> getChallenge(RoutingContext context) {
if (config.getLoginPage() != null) {
// we need to store the URL
storeInitialLocation(context);
return getRedirect(context, config.getLoginPage());
if (context.request().uri().equals(config.getLoginPage())) {
log.errorf(
"Avoiding redirect loop, make sure that your endpoint annotated with @LoginPage is accessible without being authenticated: %s",
config.getLoginPage());
return super.getChallenge(context);
} else {
// we need to store the URL
storeInitialLocation(context);
return getRedirect(context, config.getLoginPage());
}
} else {
return super.getChallenge(context);
}
Expand Down

0 comments on commit b5e39b9

Please sign in to comment.