Closed jeremywillans closed 3 years ago
Hi, thanks for the report!
Both my test instance and my production instance don't use a split flow like that at the moment so it is likely broken as you reported. I'll get a split flow setup on my test instance using the latest Keycloak this weekend and see if I can get the problem solved!
I wasn't able to find a ton of developer documentation on how the "Try another way" system works. Based on my testing, it looks like the request to select another authenticator is a POST request, and even specifying the same fields via GET does not select the authenticator, instead starts at the default authenticator.
The Duo Universal callback is always a GET request which poses a problem. As a workaround, this extension will now add an additional endpoint to the Keycloak server that will accept the GET callback from Duo, and redirect the browser to send the data to the normal authentication flow over POST.
I'm not super happy with this solution as it does add an additional redirect to the chain, which increases the overall authentication time (especially on slow connections), but I cannot think of a better solution for now.
I've released 1.0.2 as a prerelease if you want to download it and give it a try to make sure it works correctly in your authentication flow. https://github.com/instipod/DuoUniversalKeycloakAuthenticator/releases/tag/1.0.2-pr
As for the display text, it looks like that comes from the theme localization file.
Adding the following to /opt/jboss/keycloak/themes/base/login/messages/messages_en.properties
file:
duo-universal-display-name=Duo Push
duo-universal-help-text=Send a Duo Push to your devices
results in the following being displayed:
@instipod This has worked, thanks!
I wasn't sure if I should leave a new issue or just post to this one. I am currently experiencing this issue with keycloak 19.0.1
I figure it's at least similar as Duo works if it's the ONLY second factor provider, but not for split auth flows. Here's some pictures!
Works!
Doesn't work =[
Here's some logs for when I try.
keycloak-keycloak-1 | 2022-09-13 21:26:35,829 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (executor-thread-320) Uncaught server error: java.lang.NoSuchMethodError: 'org.jboss.resteasy.spi.ResteasyUriInfo org.jboss.resteasy.spi.HttpRequest.getUri()'
keycloak-keycloak-1 | at com.instipod.duouniversal.DuoUniversalAuthenticator.getRedirectUrlShim(DuoUniversalAuthenticator.java:42)
keycloak-keycloak-1 | at com.instipod.duouniversal.DuoUniversalAuthenticator.getRedirectUrl(DuoUniversalAuthenticator.java:31)
keycloak-keycloak-1 | at com.instipod.duouniversal.DuoUniversalAuthenticator.startDuoProcess(DuoUniversalAuthenticator.java:193)
keycloak-keycloak-1 | at com.instipod.duouniversal.DuoUniversalAuthenticator.authenticate(DuoUniversalAuthenticator.java:133)
keycloak-keycloak-1 | at org.keycloak.authentication.DefaultAuthenticationFlow.processSingleFlowExecutionModel(DefaultAuthenticationFlow.java:446)
keycloak-keycloak-1 | at org.keycloak.authentication.DefaultAuthenticationFlow.processAction(DefaultAuthenticationFlow.java:122)
keycloak-keycloak-1 | at org.keycloak.authentication.AuthenticationProcessor.authenticationAction(AuthenticationProcessor.java:977)
keycloak-keycloak-1 | at org.keycloak.services.resources.LoginActionsService.processFlow(LoginActionsService.java:314)
keycloak-keycloak-1 | at org.keycloak.services.resources.LoginActionsService.processAuthentication(LoginActionsService.java:285)
keycloak-keycloak-1 | at org.keycloak.services.resources.LoginActionsService.authenticate(LoginActionsService.java:277)
keycloak-keycloak-1 | at org.keycloak.services.resources.LoginActionsService.authenticateForm(LoginActionsService.java:342)
keycloak-keycloak-1 | at jdk.internal.reflect.GeneratedMethodAccessor648.invoke(Unknown Source)
keycloak-keycloak-1 | at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
keycloak-keycloak-1 | at java.base/java.lang.reflect.Method.invoke(Method.java:566)
keycloak-keycloak-1 | at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:170)
keycloak-keycloak-1 | at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:130)
keycloak-keycloak-1 | at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:660)
keycloak-keycloak-1 | at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:524)
keycloak-keycloak-1 | at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:474)
keycloak-keycloak-1 | at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
keycloak-keycloak-1 | at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:476)
keycloak-keycloak-1 | at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:434)
keycloak-keycloak-1 | at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:192)
keycloak-keycloak-1 | at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:141)
keycloak-keycloak-1 | at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:32)
keycloak-keycloak-1 | at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:492)
keycloak-keycloak-1 | at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261)
keycloak-keycloak-1 | at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161)
keycloak-keycloak-1 | at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
keycloak-keycloak-1 | at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:164)
keycloak-keycloak-1 | at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247)
keycloak-keycloak-1 | at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73)
keycloak-keycloak-1 | at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:151)
keycloak-keycloak-1 | at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:82)
keycloak-keycloak-1 | at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:42)
keycloak-keycloak-1 | at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
keycloak-keycloak-1 | at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
keycloak-keycloak-1 | at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
keycloak-keycloak-1 | at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:67)
keycloak-keycloak-1 | at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:55)
keycloak-keycloak-1 | at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
keycloak-keycloak-1 | at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
keycloak-keycloak-1 | at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
keycloak-keycloak-1 | at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:380)
keycloak-keycloak-1 | at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:358)
keycloak-keycloak-1 | at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
keycloak-keycloak-1 | at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
keycloak-keycloak-1 | at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
keycloak-keycloak-1 | at org.keycloak.quarkus.runtime.integration.web.QuarkusRequestFilter.lambda$createBlockingHandler$1(QuarkusRequestFilter.java:90)
keycloak-keycloak-1 | at io.vertx.core.impl.ContextImpl.lambda$null$0(ContextImpl.java:159)
keycloak-keycloak-1 | at io.vertx.core.impl.AbstractContext.dispatch(AbstractContext.java:100)
keycloak-keycloak-1 | at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$1(ContextImpl.java:157)
keycloak-keycloak-1 | at io.quarkus.vertx.core.runtime.VertxCoreRecorder$13.runWith(VertxCoreRecorder.java:545)
keycloak-keycloak-1 | at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
keycloak-keycloak-1 | at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
keycloak-keycloak-1 | at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
keycloak-keycloak-1 | at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
keycloak-keycloak-1 | at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
keycloak-keycloak-1 | at java.base/java.lang.Thread.run(Thread.java:829)
I can 100% open a new issue if that's better also.
It would probably be best to open a new issue since this one is already closed.
Firstly, thanks for this plugin!
It seems to work great... except when used in a conditional forwarder scenario.
I have configured an Authentication Flow to support 2FA using WebAuthN and Duo, but for some reason it just throws me back to the "Sign in with Security Key" screen rather than processing the flow.
WebAuthn Guide Keycloak 15.0.2 in Docker
Also, the "display text" does not appear to be showing on the prompt, I am getting placeholders instead 🤔