netzbegruenung / keycloak-mfa-plugins Goto Github PK
View Code? Open in Web Editor NEWKeycloak Authentication Provider implementation to get a 2nd-factor authentication with a OTP/code/token send via SMS
License: Apache License 2.0
Keycloak Authentication Provider implementation to get a 2nd-factor authentication with a OTP/code/token send via SMS
License: Apache License 2.0
Keycloak 19 is currently not supported:
https://www.keycloak.org/2022/07/keycloak-1900-released.html
When editing a user in the admin interface, an error 500 appears with the following stack trace:
2022-11-04 09:31:25,817 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (executor-thread-57) Uncaught server error: java.lang.AbstractMethodError: Receiver class netzbegruenung.keycloak.authenticator.SmsMobileNumberProvider does not define or inherit an implementation of the resolved method 'abstract java.util.stream.Stream getDisableableCredentialTypesStream(org.keycloak.models.RealmModel, org.keycloak.models.UserModel)' of interface org.keycloak.credential.CredentialInputUpdater.
at org.keycloak.credential.LegacyUserCredentialManager.lambda$getDisableableCredentialTypesStream$5(LegacyUserCredentialManager.java:185)
at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:271)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
at java.base/java.util.HashMap$ValueSpliterator.forEachRemaining(HashMap.java:1693)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:312)
at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:735)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
at org.keycloak.models.utils.ModelToRepresentation.toRepresentation(ModelToRepresentation.java:265)
at org.keycloak.services.resources.admin.UserResource.getUser(UserResource.java:286)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:170)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:130)
at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:660)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:524)
at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:474)
at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:476)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:434)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:192)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:152)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:183)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:152)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:183)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:152)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:183)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:141)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:32)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:492)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161)
at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:164)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247)
at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73)
at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:151)
at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:82)
at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:42)
at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1284)
at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:173)
at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:140)
at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:84)
at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:71)
at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1284)
at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:173)
at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:140)
at io.quarkus.vertx.http.runtime.VertxHttpRecorder$6.handle(VertxHttpRecorder.java:430)
at io.quarkus.vertx.http.runtime.VertxHttpRecorder$6.handle(VertxHttpRecorder.java:408)
at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1284)
at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:173)
at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:140)
at org.keycloak.quarkus.runtime.integration.web.QuarkusRequestFilter.lambda$createBlockingHandler$0(QuarkusRequestFilter.java:82)
at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:564)
at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:829)
Keycloak launch a new major version containing the full implementation of user profile and progressive profiling.
Could you generate a new jar support this version?
When a user enters a phone number and clicks on next, the phone number must be confirmed by entering the SMS code. Until the right SMS code is submitted, a new required action "Set phone number" is added to the user, even if other 2FA methods are configured.
This makes it hard for the user to abort the setup. The only way currently is to successfully setup SMS 2FA.
Add a config option for recognizing land lines. If a land line is used, add spaces between each character of the SMS code. This makes it easier to use in cases where the SMS is automatically being read to the user.
With this plugin enabled, we experience an increased rate of Keycloak errors. We need to investigate if this is caused by Keycloak itself or this plugin.
There are 2 errors that seem to be related to activating the "Force 2FA" function:
2022-11-28 14:01:03,783 WARN [org.keycloak.storage.ldap.LDAPStorageProviderFactory] (Timer-0) User with ID 'XXX' is not updated during sync as he already exists in Keycloak database but is not linked to federation provider 'myldap'
)The error rate is strongly increasing with the feature activated. But it seems there are other causes as well. We should try to answer the following questions:
It is possible for users to hit the submit button multiple times when entering a code. This results in an error page for users, because usually for the second request the CSRF token has expired.
We should disable the submit action after it has been triggered once.
Input entered by users should be limited to [0-9]
,
, .
, +
, -
, /
.
This should probably to into the processAction method (https://github.com/netzbegruenung/keycloak-2fa-sms-authenticator/blob/main/src/main/java/netzbegruenung/keycloak/authenticator/SmsAuthenticatorSetMobileNumberAction.java#L28)
It seems that credentials can have priorities. As TOTP and FIDO2 should always be preferred to SMS, we should try to save the credential with a lesser priority than the other methods. Not sure if this is possible.
keycloak 21 breaks SMS plugin:
2023-02-24 08:38:32,255 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (executor-thread-5) Uncaught server error: java.lang.NoSuchMethodError: 'org.jboss.resteasy.spi.HttpRequest org.keycloak.authentication.AuthenticationFlowContext.getHttpRequest()'
at netzbegruenung.keycloak.authenticator.SmsAuthenticator.action(SmsAuthenticator.java:97)
at org.keycloak.authentication.DefaultAuthenticationFlow.processAction(DefaultAuthenticationFlow.java:154)
at org.keycloak.authentication.AuthenticationProcessor.authenticationAction(AuthenticationProcessor.java:985)
at org.keycloak.services.resources.LoginActionsService.processFlow(LoginActionsService.java:324)
at org.keycloak.services.resources.LoginActionsService.processAuthentication(LoginActionsService.java:295)
at org.keycloak.services.resources.LoginActionsService.authenticateInternal(LoginActionsService.java:287)
at org.keycloak.services.resources.LoginActionsService.access$100(LoginActionsService.java:112)
at org.keycloak.services.resources.LoginActionsService$1.runInternal(LoginActionsService.java:267)
at org.keycloak.common.util.ResponseSessionTask.run(ResponseSessionTask.java:67)
at org.keycloak.common.util.ResponseSessionTask.run(ResponseSessionTask.java:44)
at org.keycloak.models.utils.KeycloakModelUtils.runJobInRetriableTransaction(KeycloakModelUtils.java:299)
at org.keycloak.services.resources.LoginActionsService.authenticate(LoginActionsService.java:260)
at org.keycloak.services.resources.LoginActionsService.authenticateForm(LoginActionsService.java:352)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:170)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:130)
at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:660)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:524)
at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:474)
at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:476)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:434)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:192)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:141)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:32)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:492)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161)
at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:164)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247)
at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73)
at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:151)
at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:82)
at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:42)
at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1284)
at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:173)
at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:140)
at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:84)
at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:71)
at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1284)
at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:173)
at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:140)
at io.quarkus.vertx.http.runtime.VertxHttpRecorder$6.handle(VertxHttpRecorder.java:430)
at io.quarkus.vertx.http.runtime.VertxHttpRecorder$6.handle(VertxHttpRecorder.java:408)
at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1284)
at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:173)
at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:140)
at org.keycloak.quarkus.runtime.integration.web.QuarkusRequestFilter.lambda$createBlockingHandler$0(QuarkusRequestFilter.java:82)
at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:576)
at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:829)
When adding a SMS authenticator action to the reset credentials, an error is thrown:
2022-09-05 12:27:43,293 WARN [org.keycloak.services] (executor-thread-565) KC-SERVICES0013: Failed authentication: java.lang.NullPointerException
at netzbegruenung.keycloak.authenticator.SmsAuthenticator.authenticate(SmsAuthenticator.java:71)
at org.keycloak.authentication.DefaultAuthenticationFlow.processSingleFlowExecutionModel(DefaultAuthenticationFlow.java:460)
at org.keycloak.authentication.DefaultAuthenticationFlow.processAction(DefaultAuthenticationFlow.java:136)
at org.keycloak.authentication.AuthenticationProcessor.authenticationAction(AuthenticationProcessor.java:990)
at org.keycloak.services.resources.LoginActionsService.processFlow(LoginActionsService.java:321)
at org.keycloak.services.resources.LoginActionsService.processResetCredentials(LoginActionsService.java:660)
at org.keycloak.services.resources.LoginActionsService.resetCredentials(LoginActionsService.java:450)
at org.keycloak.services.resources.LoginActionsService.resetCredentialsPOST(LoginActionsService.java:366)
at jdk.internal.reflect.GeneratedMethodAccessor694.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:170)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:130)
at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:660)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:524)
at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:474)
at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:476)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:434)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:192)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:141)
at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:32)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:492)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161)
at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:164)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247)
The context.getAuthenticatorConfig() probably returns null.
Try using the 2FA SMS in conjunction with a local hardware SMSEagle device. And actually I have gotten countless webhooks or SMSEagle API applications to run with the device.
But somehow I don't understand the Keycloak error message.
`2024-01-26 11:54:26,048 INFO [netzbegruenung.keycloak.authenticator.gateway.SmsServiceFactory] (executor-thread-1) API request: (POST https://mySMSEagleURL/api/v2/messages/sms) 400
2024-01-26 11:54:26,048 ERROR [netzbegruenung.keycloak.authenticator.gateway.SmsServiceFactory] (executor-thread-1) Failed to send message to 0157xxxxxxxx with answer: {"message":{"to":"The type of the attribute must be one of array (string given)."}}. Validate your config.
`
It should be possible to deactivate the SMS 2FA method with the settings introduced in #6 . The easiest way to achieve this is by removing the phone number.
Support configuration for multiple SMS provider APIs. It should be possible to select between URL encoded parameters and JSON body. And it should be possible map the 4 attributes username, access token, receiver number and message text to 4 arbitrary JSON or urlencoded variables.
This should be added to the settings of each flow (https://github.com/netzbegruenung/keycloak-2fa-sms-authenticator/blob/main/src/main/java/netzbegruenung/keycloak/authenticator/SmsAuthenticatorFactory.java#L51) to allow different providers in different flows and realms.
For example https://www.twilio.com/docs/sms/api should work. https://www.gtx-messaging.com/de/api-docs/sms-rest-api/ as well.
Would it be possible to build and release the .jar
with Github actions or sth?
I'd like to include a stable release in our setup.
It should be possible for admins to change the phone number in the credentials tab of a user.
It would be nice to have the input type for the text field for the SMS OTP set to numbers, so mobile users can type in the code easier.
Sometimes users are not able to correctly enter their country code. They enter a zero (indicating the provider prefix) between the county code and provider number (for example +490176 ...
instead of +49176 ...
. At least for Germany, these can be safely replaced (+490X
> +49X
).
Also, if a number starts with the local country prefix and a + is forgotten, the + should be added automatically.
See #63 (comment)
Most of it is already done. But still the HTTP Signatures replacement and the consistency check on setup (e.g. on setup a signature is sent and checked with the supplied public key) is open.
code_verifier
query parameter409
error also when there is no login attempt. Otherweise the client does'nt know if the authenticator needs to get removed.clientName
and clientUrl
in payload of Get-Challenges-endpointsecret
in Challenge DTO to codeChallenge
device_id
query parameter on Get-Challenges-endpoint retrieve it from the signatureEnable customization of the SMS text. We probably need some sort of placeholder for the code itself. Then we can add a setting for a custom text.
The mobile number is not read from the credential store while sending the SMS.
We want a phone number form next to the Webauthn and TOTP configuration for users.
This is currently "blocked" by keycloak/keycloak#12709
When no 2FA method is activated for a user, we have an option to force a user to set up SMS 2FA. However, this is also triggered when a user already has the "Configure OTP" or "Webauthn Register" required action.
We should check if a user already has any other 2FA configuration required action set before setting the SMS 2FA action in the enforcement mode. I'm not sure if we can check for unknown 2FA methods, but at least the 2 existing ones should be recognized.
It would be good for account owners to recognize which phone number is currently stored. This could be indicated by showing the last 3 digits of the phone number like ****123
, right behind "Phone Number". This would be the same location as the name of the Webauthn device:
Maybe just set the User Label?!
After upgrading from Keycloak 23.0.7 to 24.0.2, the Resource Provider for server sent events throws exception below. During my tests this was not critical. The form submission, which is triggered by the server sent event, still works as expected.
2024-03-27 07:54:34,304 ERROR [io.quarkus.vertx.http.runtime.QuarkusErrorHandler] (executor-thread-10) HTTP Request to
/realms/realm/app-auth-status?session_code=sfa7st4CvMBni23bpkTBIrtKeUJf5zV41sIARpz6BQ0&execution=app-register&client_id=account-console&tab_id=bNhbEzFwlrw failed,
error id: 2ec0baaa-0557-4ac2-8aa6-ecf2a6882d62-2:
jakarta.enterprise.context.ContextNotActiveException:
RequestScoped context was not active when trying to obtain a bean instance for a client proxy of CLASS bean
[class=io.quarkus.vertx.http.runtime.CurrentVertxRequest, id=0_6n6EmChCiiDdd8HelptG_A0AE]
- you can activate the request context for a specific method using the @ActivateRequestContext interceptor binding
at io.quarkus.arc.impl.ClientProxies.notActive(ClientProxies.java:70)
at io.quarkus.arc.impl.ClientProxies.getSingleContextDelegate(ClientProxies.java:30)
at io.quarkus.vertx.http.runtime.CurrentVertxRequest_ClientProxy.arc$delegate(Unknown Source)
at io.quarkus.vertx.http.runtime.CurrentVertxRequest_ClientProxy.getCurrent(Unknown Source)
at java.base/java.util.Optional.map(Optional.java:260)
at org.keycloak.quarkus.runtime.integration.resteasy.ResteasyVertxProvider.getContextData(ResteasyVertxProvider.java:44)
at org.keycloak.common.util.Resteasy.getContextData(Resteasy.java:62)
at org.keycloak.services.error.KeycloakErrorHandler.toResponse(KeycloakErrorHandler.java:54)
at org.jboss.resteasy.reactive.server.core.RuntimeExceptionMapper.mapException(RuntimeExceptionMapper.java:100)
at org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext.mapExceptionIfPresent(ResteasyReactiveRequestContext.java:346)
at org.jboss.resteasy.reactive.server.handlers.ExceptionHandler.handle(ExceptionHandler.java:15)
at io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.invokeHandler(QuarkusResteasyReactiveRequestContext.java:150)
at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:147)
at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:582)
at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1538)
at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:840)
During testing I somehow managed to get my plugin stuck in "simulation" mode. I've gone as far as to destroy all custom flows and deleting the sms step. Saving. Coming back and readding the flow and ensuring simulation toggle is off. However when client initiates SMS flow, my console still shows **** SIMULATION MODE *** and I don't know how to turn it off now.
E.g. like this <finalName>${project.groupId}.${project.artifactId}-${project.version}</finalName>
According to https://www.twilio.com/docs/sms/send-messages, the following curl request needs to be supported:
curl -X POST https://api.twilio.com/2010-04-01/Accounts/$TWILIO_ACCOUNT_SID/Messages.json \
--data-urlencode "Body=Hi there" \
--data-urlencode "From=+15017122661" \
--data-urlencode "To=+15558675310" \
-u $TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN
Additionally to creating artifacts a new release should be created on pushing new versions, too.
Related to #23
After clicking the link of the password reset email, sometimes multiple SMS codes are submitted.
Maybe related to: #30
A phone number should be verified before the user should be able to use it as second factor. This is similar to TOTP, where the user needs to enter the first OTP, before TOTP becomes active as a second factor.
Procedure:
When logging in a user is always asked for a new phone number, while sending the SMS always uses the development mode.
In the moment the custom required actions assume there exists an authenticator config object with the alias "sms-2fa".
Instead of loading the config by this predefined alias it should be loaded either from the database (with arbitrary alias) or loaded from keycloaks globale settings (see #20 (comment) and following)
With versions 0.2.1 and 0.2.2 the update phone number required action fails after entering the phone number. No code is being sent and a mail notification about a failed login attempt is being sent to the user.
Currently there is a mix of licenses. We need to check which files actually contain larger parts of original code and probably should keep the corresponding license.
If the Phone Number Action is shown during log in, it does not yet show existing phone numbers. It would be better for users, if the existing phone number is shown.
It seems that 0049171xxx
is being replaced to +4949171xxx
.
Add a boolean setting that automatically adds a required action for registering a phone number, if no other second factor is configured for the user.
/realms/realm-id/login-actions/action-token?key=jwt&client_id=account-console&tab_id=someTabId
Setup Steps:
Required additional query parameters:
device_id: firebase device's registration token
device_os: OS
public_key: base64 encoded public key (RSA)
/realms/realm-id/login-actions/action-token?key=jwt&client_id=account-console&tab_id=someTabId
Auth Steps:
Required additional query parameters:
secret: decrypted secret (see below)
The firebase message contains an encrypted secret (RSA), which the app is supposed to decrypt with their secret key and send the decrypted string back to keycloak for verification.
How to make sure that the apps public key was not tampered during transmission. (solved, see: https://chatbegruenung.de/group/gruene-app-alle?msg=gYqrCfqTgunZexoEA)
Hey guys, first of all, thanks for keep the implementation and share this repository.
I'm working in a project that needs to replace the current Auth Service for Keycloak with SMS as MFA.
I'm trying to use your plugin, but even watching the Niko Kobler videos and reading the repository README. i'm facing a lot of doubts and problems to implement it.
Thinking on that, i'm forking the repository to update the README with all the instructions to implement it, and help eveyone that needs to have it in their Keycloak.
I'll start adding here some questions and explaining my steps.
I have the Keycloak running in a Docker Container (i'll add the steps to install it in the ReadMe too)
To be able to use the plugin, you need to have an User Attibute called 'mobile_number' to store the phone numbers. This can be done using the User profile or using User Attributes
I've the User Profile Attirbute set as mobile_number, but in the docker logs, looks like the user number is not identified
Go to Authentication > Flows > Duplicate the 'browser' flow - I've set the name as 'browser with sms'
On 'browser with sms forms' step, click over the + and add a new step
Search by 'SMS Authentication (2FA)' and click on Add button
Drag and Drop the added step to under the Useranme Password Form
Change the to 'Required' and click over the engine to Edit the plugin settings
Go back to Authentication Flows page, find the create flow, click over the settings and 'Bind Flow' option
This is the basic configuration to allow you to test before configure you SMS Api Service.
2024-03-09 10:22:28 2024-03-09 13:22:28,935 WARN [org.keycloak.services] (executor-thread-337) KC-SERVICES0013: Failed authentication: org.keycloak.authentication.AuthenticationFlowException: authenticator: mobile-number-authenticator 2024-03-09 10:22:28 at org.keycloak.authentication.DefaultAuthenticationFlow.processSingleFlowExecutionModel(DefaultAuthenticationFlow.java:432) 2024-03-09 10:22:28 at org.keycloak.authentication.DefaultAuthenticationFlow.processFlow(DefaultAuthenticationFlow.java:249) 2024-03-09 10:22:28 at org.keycloak.authentication.DefaultAuthenticationFlow.processSingleFlowExecutionModel(DefaultAuthenticationFlow.java:380) 2024-03-09 10:22:28 at org.keycloak.authentication.DefaultAuthenticationFlow.continueAuthenticationAfterSuccessfulAction(DefaultAuthenticationFlow.java:181) 2024-03-09 10:22:28 at org.keycloak.authentication.DefaultAuthenticationFlow.processAction(DefaultAuthenticationFlow.java:157) 2024-03-09 10:22:28 at org.keycloak.authentication.AuthenticationProcessor.authenticationAction(AuthenticationProcessor.java:988) 2024-03-09 10:22:28 at org.keycloak.services.resources.LoginActionsService.processFlow(LoginActionsService.java:362) 2024-03-09 10:22:28 at org.keycloak.services.resources.LoginActionsService.processAuthentication(LoginActionsService.java:333) 2024-03-09 10:22:28 at org.keycloak.services.resources.LoginActionsService.authenticate(LoginActionsService.java:325) 2024-03-09 10:22:28 at org.keycloak.services.resources.LoginActionsService.authenticateForm(LoginActionsService.java:390) 2024-03-09 10:22:28 at org.keycloak.services.resources.LoginActionsService$quarkusrestinvoker$authenticateForm_32b8e198ac3110abd1d5774e83a4cf87858129f4.invoke(Unknown Source) 2024-03-09 10:22:28 at org.jboss.resteasy.reactive.server.handlers.InvocationHandler.handle(InvocationHandler.java:29) 2024-03-09 10:22:28 at io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.invokeHandler(QuarkusResteasyReactiveRequestContext.java:141) 2024-03-09 10:22:28 at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:145) 2024-03-09 10:22:28 at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:576) 2024-03-09 10:22:28 at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513) 2024-03-09 10:22:28 at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1538) 2024-03-09 10:22:28 at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29) 2024-03-09 10:22:28 at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29) 2024-03-09 10:22:28 at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) 2024-03-09 10:22:28 at java.base/java.lang.Thread.run(Thread.java:840)
Open the Realm Authentication page, under the Required Actions, turned on the 'Phone Validation' option
With that, after create a new user, the SMS Code page starts to appear
Now, FOR NEW USERS i'm able to use the SMS CODE.
I've noticed that the created user got the following credentials
I think, that was that allow the user login using the SMS 2FA.
But as mentionated at the very beggining, i'm migrating existent users to the Keycloak using the Keycloak Rest Api.
Tried to add this credential throw the api, and i'm getting this errror:
How can i add the Mobile-number credential to the migrated users and allow them use the SMS Code flow?
Because if i follow the above steps and don't add the credential, when i trying to login, i'm getting the following error:
2024-03-09 10:48:25 2024-03-09 13:48:25,741 WARN [org.keycloak.services] (executor-thread-358) KC-SERVICES0013: Failed authentication: org.keycloak.authentication.AuthenticationFlowException: authenticator: mobile-number-authenticator 2024-03-09 10:48:25 at org.keycloak.authentication.DefaultAuthenticationFlow.processSingleFlowExecutionModel(DefaultAuthenticationFlow.java:432) 2024-03-09 10:48:25 at org.keycloak.authentication.DefaultAuthenticationFlow.processFlow(DefaultAuthenticationFlow.java:249) 2024-03-09 10:48:25 at org.keycloak.authentication.DefaultAuthenticationFlow.processSingleFlowExecutionModel(DefaultAuthenticationFlow.java:380) 2024-03-09 10:48:25 at org.keycloak.authentication.DefaultAuthenticationFlow.continueAuthenticationAfterSuccessfulAction(DefaultAuthenticationFlow.java:181) 2024-03-09 10:48:25 at org.keycloak.authentication.DefaultAuthenticationFlow.processAction(DefaultAuthenticationFlow.java:157) 2024-03-09 10:48:25 at org.keycloak.authentication.AuthenticationProcessor.authenticationAction(AuthenticationProcessor.java:988) 2024-03-09 10:48:25 at org.keycloak.services.resources.LoginActionsService.processFlow(LoginActionsService.java:362) 2024-03-09 10:48:25 at org.keycloak.services.resources.LoginActionsService.processAuthentication(LoginActionsService.java:333) 2024-03-09 10:48:25 at org.keycloak.services.resources.LoginActionsService.authenticate(LoginActionsService.java:325) 2024-03-09 10:48:25 at org.keycloak.services.resources.LoginActionsService.authenticateForm(LoginActionsService.java:390) 2024-03-09 10:48:25 at org.keycloak.services.resources.LoginActionsService$quarkusrestinvoker$authenticateForm_32b8e198ac3110abd1d5774e83a4cf87858129f4.invoke(Unknown Source) 2024-03-09 10:48:25 at org.jboss.resteasy.reactive.server.handlers.InvocationHandler.handle(InvocationHandler.java:29) 2024-03-09 10:48:25 at io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.invokeHandler(QuarkusResteasyReactiveRequestContext.java:141) 2024-03-09 10:48:25 at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:145) 2024-03-09 10:48:25 at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:576) 2024-03-09 10:48:25 at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513) 2024-03-09 10:48:25 at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1538) 2024-03-09 10:48:25 at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29) 2024-03-09 10:48:25 at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29) 2024-03-09 10:48:25 at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) 2024-03-09 10:48:25 at java.base/java.lang.Thread.run(Thread.java:840)
Thanks in advanced, I know it's a lot of information, but i really need some help here to implement it.
Message previews allow many users to just type the 6 digit code from their phone from message preview, whereas right now the digit code is to late in the message text and not shown in preview anymore:
https://helpdesk.verdigado.com/#ticket/zoom/80807/122860
Neuerdings wird auch von Apple der Code nicht mehr erkannt melden Anwender*innen im chat:
Früher:
Ihr Grünes Netz SMS Code lautet 738269 und ist gültig für 15 Minuten.
Jetzt:
Ihr Grünes Netz SMS ist 961640 und ist gültig für 15 Minuten.
https://chatbegruenung.de/channel/chatbegruenung?msg=XBbNPWeLHZwpJNhm5
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.